diff options
Diffstat (limited to 'drivers/staging/comedi/drivers')
102 files changed, 6058 insertions, 7715 deletions
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index 8a57c3c1ade0..46a385c29ba8 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -56,6 +56,7 @@ Configuration Options: not applicable, uses PCI auto config #include "../comedidev.h" #include "8255.h" +#include "mite.h" enum pci_8255_boardid { BOARD_ADLINK_PCI7224, @@ -79,6 +80,7 @@ struct pci_8255_boardinfo { const char *name; int dio_badr; int n_8255; + unsigned int has_mite:1; }; static const struct pci_8255_boardinfo pci_8255_boards[] = { @@ -126,36 +128,43 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { .name = "ni_pci-dio-96", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCIDIO96B] = { .name = "ni_pci-dio-96b", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PXI6508] = { .name = "ni_pxi-6508", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCI6503] = { .name = "ni_pci-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503B] = { .name = "ni_pci-6503b", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503X] = { .name = "ni_pci-6503x", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PXI_6503] = { .name = "ni_pxi-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, }; @@ -163,6 +172,25 @@ struct pci_8255_private { void __iomem *mmio_base; }; +static int pci_8255_mite_init(struct pci_dev *pcidev) +{ + void __iomem *mite_base; + u32 main_phys_addr; + + /* ioremap the MITE registers (BAR 0) temporarily */ + mite_base = pci_ioremap_bar(pcidev, 0); + if (!mite_base) + return -ENOMEM; + + /* set data window to main registers (BAR 1) */ + main_phys_addr = pci_resource_start(pcidev, 1); + writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR); + + /* finished with MITE registers */ + iounmap(mite_base); + return 0; +} + static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase) { void __iomem *mmio_base = (void __iomem *)iobase; @@ -201,6 +229,12 @@ static int pci_8255_auto_attach(struct comedi_device *dev, if (ret) return ret; + if (board->has_mite) { + ret = pci_8255_mite_init(pcidev); + if (ret) + return ret; + } + is_mmio = (pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM) != 0; if (is_mmio) { @@ -235,9 +269,6 @@ static int pci_8255_auto_attach(struct comedi_device *dev, return ret; } - dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n", - dev->board_name, board->n_8255 * 24); - return 0; } diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 2706f583d8f0..0757a82ddcfa 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_COMEDI_PCL818) += pcl818.o obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o +obj-$(CONFIG_COMEDI_DAC02) += dac02.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o obj-$(CONFIG_COMEDI_DAS16) += das16.o @@ -53,7 +54,6 @@ obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o -obj-$(CONFIG_COMEDI_POC) += poc.o obj-$(CONFIG_COMEDI_S526) += s526.o # Comedi PCI drivers diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index 1128c22e7517..28450f65a134 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -1,46 +1,24 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-035 | Compiler : GCC | - | Module name : hwdrv_apci035.c | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-035 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ /* Card Specific information */ #define APCI035_ADDRESS_RANGE 255 @@ -106,99 +84,66 @@ static struct comedi_lrange range_apci035_ai = { } }; -static int i_WatchdogNbr = 0; -static int i_Temp = 0; +static int i_WatchdogNbr; +static int i_Temp; static int i_Flag = 1; + /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Watchdog | -| data[1] : Watchdog number -| data[2] : Time base Unit | -| data[3] : Reload Value | -| data[4] : External Trigger | -| 1:Enable -| 0:Disable -| data[5] :External Trigger Level -| 00 Trigger Disabled -| 01 Trigger Enabled (Low level) -| 10 Trigger Enabled (High Level) -| 11 Trigger Enabled (High/Low level) -| data[6] : External Gate | -| 1:Enable -| 0:Disable -| data[7] : External Gate level -| 00 Gate Disabled -| 01 Gate Enabled (Low level) -| 10 Gate Enabled (High Level) -| data[8] :Warning Relay -| 1: ENABLE -| 0: DISABLE -| data[9] :Warning Delay available -| data[10] :Warning Relay Time unit -| data[11] :Warning Relay Time Reload value -| data[12] :Reset Relay -| 1 : ENABLE -| 0 : DISABLE -| data[13] :Interrupt -| 1 : ENABLE -| 0 : DISABLE -| -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Timer , Counter or Watchdog + * + * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog + * data[1] Watchdog number + * data[2] Time base Unit + * data[3] Reload Value + * data[4] External Trigger, 1 = Enable, 0 = Disable + * data[5] External Trigger Level + * 00 = Trigger Disabled + * 01 = Trigger Enabled (Low level) + * 10 = Trigger Enabled (High Level) + * 11 = Trigger Enabled (High/Low level) + * data[6] External Gate, 1 = Enable, 0 = Disable + * data[7] External Gate level + * 00 = Gate Disabled + * 01 = Gate Enabled (Low level) + * 10 = Gate Enabled (High Level) + * data[8] Warning Relay, 1 = Enable, 0 = Disable + * data[9] Warning Delay available + * data[10] Warning Relay Time unit + * data[11] Warning Relay Time Reload value + * data[12] Reset Relay, 1 = Enable, 0 = Disable + * data[13] Interrupt, 1 = Enable, 0 = Disable + */ +static int apci035_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; - unsigned int ui_Command = 0; - unsigned int ui_Mode = 0; + unsigned int ui_Status; + unsigned int ui_Command; + unsigned int ui_Mode; i_Temp = 0; devpriv->tsk_Current = current; devpriv->b_TimerSelectMode = data[0]; i_WatchdogNbr = data[1]; - if (data[0] == 0) { + if (data[0] == 0) ui_Mode = 2; - } else { + else ui_Mode = 0; - } -/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */ + ui_Command = 0; -/* ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/************************/ -/* Set the reload value */ -/************************/ + + /* Set the reload value */ outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); -/*********************/ -/* Set the time unit */ -/*********************/ + + /* Set the time unit */ outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8); if (data[0] == ADDIDATA_TIMER) { - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -206,101 +151,82 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Enable the timer mode */ /* - Set the timer mode */ - /******************************/ ui_Command = (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; - } /* if (data[0] == ADDIDATA_TIMER) */ - else { - if (data[0] == ADDIDATA_WATCHDOG) { + } else if (data[0] == ADDIDATA_WATCHDOG) { - /******************************/ - /* Set the mode : */ - /* - Disable the hardware */ - /* - Disable the counter mode */ - /* - Disable the warning */ - /* - Disable the reset */ - /* - Disable the timer mode */ - /******************************/ + /* Set the mode : */ + /* - Disable the hardware */ + /* - Disable the counter mode */ + /* - Disable the warning */ + /* - Disable the reset */ + /* - Disable the timer mode */ - ui_Command = ui_Command & 0xFFF819E2UL; + ui_Command = ui_Command & 0xFFF819E2UL; - } else { - printk("\n The parameter for Timer/watchdog selection is in error\n"); - return -EINVAL; - } + } else { + dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n"); + return -EINVAL; } + outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/********************************/ -/* Disable the hardware trigger */ -/********************************/ + + /* Disable the hardware trigger */ ui_Command = ui_Command & 0xFFFFF89FUL; if (data[4] == ADDIDATA_ENABLE) { - /**********************************/ + /* Set the hardware trigger level */ - /**********************************/ ui_Command = ui_Command | (data[5] << 5); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*****************************/ -/* Disable the hardware gate */ -/*****************************/ + + /* Disable the hardware gate */ ui_Command = ui_Command & 0xFFFFF87FUL; if (data[6] == ADDIDATA_ENABLE) { -/*******************************/ -/* Set the hardware gate level */ -/*******************************/ + + /* Set the hardware gate level */ ui_Command = ui_Command | (data[7] << 7); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Disable the hardware output */ -/*******************************/ + + /* Disable the hardware output */ ui_Command = ui_Command & 0xFFFFF9FBUL; -/*********************************/ -/* Set the hardware output level */ -/*********************************/ + + /* Set the hardware output level */ ui_Command = ui_Command | (data[8] << 2); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); if (data[9] == ADDIDATA_ENABLE) { - /************************/ + /* Set the reload value */ - /************************/ outl(data[11], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24); - /**********************/ + /* Set the time unite */ - /**********************/ outl(data[10], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28); } - ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*******************************/ + /* Disable the hardware output */ - /*******************************/ ui_Command = ui_Command & 0xFFFFF9F7UL; - /*********************************/ + /* Set the hardware output level */ - /*********************************/ ui_Command = ui_Command | (data[12] << 3); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*************************************/ - /** Enable the watchdog interrupt **/ - /*************************************/ - ui_Command = 0; + + /* Enable the watchdog interrupt */ ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Set the interrupt selection */ -/*******************************/ + + /* Set the interrupt selection */ ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); @@ -310,82 +236,63 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_StartStopWriteTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 - Stop Selected Timer/Watchdog | -| 1 - Start Selected Timer/Watchdog | -| 2 - Trigger Selected Timer/Watchdog | -| 3 - Stop All Timer/Watchdog | -| 4 - Start All Timer/Watchdog | -| 5 - Trigger All Timer/Watchdog | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop The Selected Timer , or Watchdog + * + * data[0] + * 0 - Stop Selected Timer/Watchdog + * 1 - Start Selected Timer/Watch*dog + * 2 - Trigger Selected Timer/Watchdog + * 3 - Stop All Timer/Watchdog + * 4 - Start All Timer/Watchdog + * 5 - Trigger All Timer/Watchdog + */ +static int apci035_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Command = 0; - int i_Count = 0; + unsigned int ui_Command; + int i_Count; if (data[0] == 1) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /**********************/ + /* Start the hardware */ - /**********************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[0]==1) */ + } if (data[0] == 2) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /***************************/ + /* Set the trigger command */ - /***************************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } - if (data[0] == 0) /* Stop The Watchdog */ - { + if (data[0] == 0) { /* Stop The Watchdog */ ui_Command = 0; -/* -* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); -* ui_Command = ui_Command & 0xFFFFF9FEUL; -*/ + /* + * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); + * ui_Command = ui_Command & 0xFFFFF9FEUL; + */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[1]==0) */ - if (data[0] == 3) /* stop all Watchdogs */ - { + } + if (data[0] == 3) { + /* stop all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x2UL; - } else { + else ui_Command = 0x10UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + @@ -393,30 +300,29 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } } - if (data[0] == 4) /* start all Watchdogs */ - { + if (data[0] == 4) { + /* start all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x1UL; - } else { + else ui_Command = 0x8UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } } - if (data[0] == 5) /* trigger all Watchdogs */ - { + if (data[0] == 5) { + /* trigger all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x4UL; - } else { + else ui_Command = 0x20UL; - } i_WatchdogNbr = i_Count; outl(ui_Command, @@ -429,109 +335,61 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : software trigger status -| data[1] : hardware trigger status -| data[2] : Software clear status -| data[3] : Overflow status -| data[4] : Timer actual value -| - -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Selected Timer , Counter or Watchdog + * + * data[0] software trigger status + * data[1] hardware trigger status + * data[2] Software clear status + * data[3] Overflow status + * data[4] Timer actual value + */ +static int apci035_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; /* Status register */ + unsigned int ui_Status; /* Status register */ i_WatchdogNbr = insn->unused[0]; - /******************/ /* Get the status */ - /******************/ - ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); - /***********************************/ /* Get the software trigger status */ - /***********************************/ - data[0] = ((ui_Status >> 1) & 1); - /***********************************/ + /* Get the hardware trigger status */ - /***********************************/ data[1] = ((ui_Status >> 2) & 1); - /*********************************/ + /* Get the software clear status */ - /*********************************/ data[2] = ((ui_Status >> 3) & 1); - /***************************/ + /* Get the overflow status */ - /***************************/ data[3] = ((ui_Status >> 0) & 1); - if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { + if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Analog Input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| data[0] : Warning delay value -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Analog Input Subdevice + * + * data[0] Warning delay value + */ +static int apci035_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; devpriv->tsk_Current = current; outl(0x200 | 0, devpriv->iobase + 128 + 0x4); outl(0, devpriv->iobase + 128 + 0); -/********************************/ -/* Initialise the warning value */ -/********************************/ + + /* Initialise the warning value */ outl(0x300 | 0, devpriv->iobase + 128 + 0x4); outl((data[0] << 8), devpriv->iobase + 128 + 0); outl(0x200000UL, devpriv->iobase + 128 + 12); @@ -540,145 +398,88 @@ static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -| data[0] : Digital Value Of Input | -| | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read value of the selected channel + * + * data[0] Digital Value Of Input + */ +static int apci035_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_CommandRegister = 0; + unsigned int ui_CommandRegister; -/******************/ -/* Set the start */ -/******************/ + /* Set the start */ ui_CommandRegister = 0x80000; - /******************************/ + /* Write the command register */ - /******************************/ outl(ui_CommandRegister, devpriv->iobase + 128 + 8); -/***************************************/ -/* Read the digital value of the input */ -/***************************************/ + /* Read the digital value of the input */ data[0] = inl(devpriv->iobase + 128 + 28); return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task :Resets the registers of the card | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_Reset(struct comedi_device *dev) +static int apci035_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; - int i_Count = 0; + int i_Count; for (i_Count = 1; i_Count <= 4; i_Count++) { i_WatchdogNbr = i_Count; - outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */ + + /* stop all timers */ + outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ return 0; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI035_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt processing Routine | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI035_Interrupt(int irq, void *d) +static void apci035_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; - unsigned int ui_StatusRegister1 = 0; - unsigned int ui_StatusRegister2 = 0; - unsigned int ui_ReadCommand = 0; - unsigned int ui_ChannelNumber = 0; - unsigned int ui_DigitalTemperature = 0; + unsigned int ui_StatusRegister1; + unsigned int ui_StatusRegister2; + unsigned int ui_ReadCommand; + unsigned int ui_ChannelNumber; + unsigned int ui_DigitalTemperature; if (i_Temp == 1) { i_WatchdogNbr = i_Flag; i_Flag = i_Flag + 1; } - /**************************************/ + /* Read the interrupt status register of temperature Warning */ - /**************************************/ ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); - /**************************************/ - /* Read the interrupt status register for Watchdog/timer */ - /**************************************/ + /* Read the interrupt status register for Watchdog/timer */ ui_StatusRegister2 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); - if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */ - { - /**********************************/ + /* Test if warning relay interrupt */ + if ((((ui_StatusRegister1) & 0x8) == 0x8)) { + /* Disable the temperature warning */ - /**********************************/ ui_ReadCommand = inl(devpriv->iobase + 128 + 12); ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL; outl(ui_ReadCommand, devpriv->iobase + 128 + 12); - /***************************/ + /* Read the channel number */ - /***************************/ ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); - /**************************************/ + /* Read the digital temperature value */ - /**************************************/ ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */ - else { - if ((ui_StatusRegister2 & 0x1) == 0x1) { - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } - } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + + } else if ((ui_StatusRegister2 & 0x1) == 0x1) { + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + } return; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 054910511e9e..a633957890d7 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -1,48 +1,25 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1500 | Compiler : GCC | - | Module name : hwdrv_apci1500.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1500 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/********* Definitions for APCI-1500 card *****/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ /* Card Specific information */ #define APCI1500_ADDRESS_RANGE 4 @@ -141,99 +118,45 @@ enum { APCI1500_RW_PORT_B_PATTERN_MASK }; -static int i_TimerCounter1Init = 0; -static int i_TimerCounter2Init = 0; -static int i_WatchdogCounter3Init = 0; -static int i_Event1Status = 0, i_Event2Status = 0; -static int i_TimerCounterWatchdogInterrupt = 0; -static int i_Logic = 0, i_CounterLogic = 0; -static int i_InterruptMask = 0; -static int i_InputChannel = 0; -static int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = 0, - i_WatchdogCounter3Enabled = 0; +static int i_TimerCounter1Init; +static int i_TimerCounter2Init; +static int i_WatchdogCounter3Init; +static int i_Event1Status, i_Event2Status; +static int i_TimerCounterWatchdogInterrupt; +static int i_Logic, i_CounterLogic; +static int i_InterruptMask; +static int i_InputChannel; +static int i_TimerCounter1Enabled, i_TimerCounter2Enabled, + i_WatchdogCounter3Enabled; /* - +----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : An event can be generated for each port. | -| The first event is related to the first 8 channels | -| (port 1) and the second to the following 6 channels | -| (port 2). An interrupt is generated when one or both | -| events have occurred | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] :Number of the input port on | -| which the event will take place | -| (1 or 2) -| data[1] : The event logic for port 1 has | -| three possibilities | -| :0 APCI1500_AND :This logic | -| links | -| the inputs | -| with an AND | -| logic. | -| 1 APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| OR logic. | -| 2 APCI1500_OR_PRIORITY | -| :This logic | -| links | -| the inputs | -| with a | -| priority | -| OR logic. | -| Input 1 | -| has the | -| highest | -| priority | -| level and | -| input 8 | -| the smallest| -| For the second port the user has| -| 1 possibility: | -| APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| polarity | -| OR logic | -| data[2] : These 8-character word for port1| -| and 6-character word for port 2 | -| give the mask of the event. | -| Each place gives the state | -| of the input channels and can | -| have one of these six characters| -| | -| 0 : This input must be on 0 | -| 1 : This input must be on 1 | -| 2 : This input reacts to | -| a falling edge | -| 3 : This input reacts to a | -| rising edge | -| 4 : This input reacts to both edges | -| -| 5 : This input is not | -| used for event | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * An event can be generated for each port. The first event is related to the + * first 8 channels (port 1) and the second to the following 6 channels (port 2) + * An interrupt is generated when one or both events have occurred. + * + * data[0] Number of the input port on which the event will take place (1 or 2) + * data[1] The event logic for port 1 has three possibilities: + * APCI1500_AND This logic links the inputs with an AND logic. + * APCI1500_OR This logic links the inputs with a OR logic. + * APCI1500_OR_PRIORITY This logic links the inputs with a priority OR + * logic. Input 1 has the highest priority level + * and input 8 the smallest. + * For the second port the user has 1 possibility: + * APCI1500_OR This logic links the inputs with a polarity OR logic + * data[2] These 8-character word for port1 and 6-character word for port 2 + * give the mask of the event. Each place gives the state of the input + * channels and can have one of these six characters + * 0 This input must be on 0 + * 1 This input must be on 1 + * 2 This input reacts to a falling edge + * 3 This input reacts to a rising edge + * 4 This input reacts to both edges + * 5 This input is not used for event + */ +static int apci1500_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0; @@ -241,14 +164,10 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, int i_PatternTransitionCount = 0, i_RegValue; int i; - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if (data[0] == 1) { @@ -259,7 +178,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_MaxChannel = 6; } /* if(data[0]==2) */ else { - printk("\nThe specified port event does not exist\n"); + dev_warn(dev->hw_dev, + "The specified port event does not exist\n"); return -EINVAL; } /* else if(data[0]==2) */ } /* else if (data[0] == 1) */ @@ -274,7 +194,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, data[1] = APCI1500_OR_PRIORITY; break; default: - printk("\nThe specified interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The specified interrupt logic does not exist\n"); return -EINVAL; } /* switch(data[1]); */ @@ -318,37 +239,30 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, case 5: break; default: - printk("\nThe option indicated in the event mask does not exist\n"); + dev_warn(dev->hw_dev, + "The option indicated in the event mask does not exist\n"); return -EINVAL; } /* switch(i_EventMask) */ } /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */ if (data[0] == 1) { - /****************************/ /* Test the interrupt logic */ - /****************************/ if (data[1] == APCI1500_AND || data[1] == APCI1500_OR || data[1] == APCI1500_OR_PRIORITY) { - /**************************************/ /* Tests if a transition was declared */ /* for a OR PRIORITY logic */ - /**************************************/ if (data[1] == APCI1500_OR_PRIORITY && i_PatternTransition != 0) { - /********************************************/ - /* Transition error on an OR PRIORITY logic */ - /********************************************/ - printk("\nTransition error on an OR PRIORITY logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an OR PRIORITY logic\n"); return -EINVAL; } /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */ - /*************************************/ /* Tests if more than one transition */ /* was declared for an AND logic */ - /*************************************/ if (data[1] == APCI1500_AND) { for (i_Count = 0; i_Count < 8; i_Count++) { @@ -360,29 +274,21 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* for (i_Count = 0; i_Count < 8; i_Count++) */ if (i_PatternTransitionCount > 1) { - /****************************************/ - /* Transition error on an AND logic */ - /****************************************/ - printk("\n Transition error on an AND logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an AND logic\n"); return -EINVAL; } /* if (i_PatternTransitionCount > 1) */ } /* if (data[1]== APCI1500_AND) */ - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the polarity register of port 1 */ - /**********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -390,20 +296,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the pattern mask register of */ /* port 1 */ - /*********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternMask, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************/ /* Selects the pattern transition register */ /* of port 1 */ - /********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -411,10 +313,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -422,17 +322,13 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Port A new mode */ - /**********************/ i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9; outb(i_RegValue, @@ -441,53 +337,40 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_Event1Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ } /* if (data[0]== 1) */ - /************************************/ /* Test if event setting for port 2 */ - /************************************/ if (data[0] == 2) { - /************************/ /* Test the event logic */ - /************************/ if (data[1] == APCI1500_OR) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the mode specification mask */ /* register of port B */ - /****************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -495,10 +378,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port B */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -507,37 +388,29 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************/ /* Selects error channels 1 and 2 */ - /**********************************/ i_PatternMask = (i_PatternMask | 0xC0); i_PatternPolarity = (i_PatternPolarity | 0xC0); i_PatternTransition = (i_PatternTransition | 0xC0); - /**********************************************/ /* Selects the polarity register of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternPolarity, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern transition register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternTransition, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern Mask register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + @@ -546,20 +419,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -569,23 +438,20 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); i_Event2Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if (data[1] == APCI1500_OR) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* elseif (data[1] == APCI1500_OR) */ } /* if(data[0]==2) */ @@ -594,31 +460,15 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Allows or disallows a port event | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -| data[0] :0 Start input event -| 1 Stop input event -| data[1] :No of port (1 or 2) -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Allows or disallows a port event + * + * data[0] 0 = Start input event, 1 = Stop input event + * data[1] Number of port (1 or 2) + */ +static int apci1500_di_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_Event1InterruptStatus = 0, i_Event2InterruptStatus = @@ -626,48 +476,30 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, switch (data[0]) { case START: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -680,185 +512,142 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 1; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[0] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[0] == 2) */ break; case STOP: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event1InterruptStatus = 0; } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 0; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[1] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[1] == 2) */ break; default: - printk("\nThe option of START/STOP logic does not exist\n"); + dev_warn(dev->hw_dev, + "The option of START/STOP logic does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -866,35 +655,17 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Initialisation | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Initialisation(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Return the status of the digital input + */ +static int apci1500_di_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_DummyRead = 0; - /******************/ /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -902,16 +673,12 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -943,9 +710,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -975,9 +740,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -992,9 +755,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1004,9 +765,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1016,9 +775,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1028,9 +785,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ @@ -1051,37 +806,15 @@ static int apci1500_di_insn_bits(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalOutputErrorInterrupt -| (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn -| *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures the digital output memory and the digital -| output error interrupt | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| data[0] :1:Memory on | -| 0:Memory off | -| data[1] :1 Enable the voltage error interrupt -| :0 Disable the voltage error interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the digital output memory and the digital output error interrupt + * + * data[1] 1 = Enable the voltage error interrupt + * 2 = Disable the voltage error interrupt + */ +static int apci1500_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; @@ -1090,31 +823,15 @@ static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *de } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To Write | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Writes port value to the selected port + */ +static int apci1500_do_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - static unsigned int ui_Temp = 0; + static unsigned int ui_Temp; unsigned int ui_Temp1; unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ @@ -1165,7 +882,9 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==0) */ @@ -1242,12 +961,15 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==1); */ else { - printk("\nSpecified functionality does not exist\n"); + dev_warn(dev->hw_dev, + "Specified functionality does not exist\n"); return -EINVAL; } /* if else data[3]==1) */ } /* if else data[3]==0) */ @@ -1256,57 +978,23 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device -| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status data[0] : 2 APCI1500_1_8_KHZ -| 1 APCI1500_3_6_KHZ | -| 0 APCI1500_115_KHZ -| data[1] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[2] : 0 Counter -| 1 Timer/Watchdog -| data[3] : This parameter has | -| two meanings. | -| - If the counter/timer | -| is used as a counter | -| the limit value of | -| the counter is given | -| | -| - If the counter/timer | -| is used as a timer, | -| the divider factor | -| for the output is | -| given. -| data[4] : 0 APCI1500_CONTINUOUS -| 1 APCI1500_SINGLE -| data[5] : 0 Software Trigger -| 1 Hardware Trigger -| -| data[6] :0 Software gate -| 1 Hardware gate -| data[7] :0 Interrupt Disable -| 1 Interrupt Enable -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Watchdog + * + * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ + * data[1] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[2] 0 = Counter, 1 = Timer/Watchdog + * data[3] This parameter has two meanings. If the counter/timer is used as + * a counter the limit value of the counter is given. If the counter/timer + * is used as a timer, the divider factor for the output is given. + * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE + * data[5] 0 = Software Trigger, 1 = Hardware Trigger + * data[6] 0 = Software gate, 1 = Hardware gate + * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable + */ +static int apci1500_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_TimerCounterMode, i_MasterConfiguration; @@ -1319,7 +1007,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[0]==0||data[0]==1||data[0]==2) */ else { if (data[0] != 3) { - printk("\nThe option for input clock selection does not exist\n"); + dev_warn(dev->hw_dev, + "The option for input clock selection does not exist\n"); return -EINVAL; } /* if(data[0]!=3) */ } /* elseif(data[0]==0||data[0]==1||data[0]==2) */ @@ -1335,7 +1024,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1348,139 +1038,110 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ i_TimerCounterMode = data[2] | data[4] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 1 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 1 and triggers timer/counter 1 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x40; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 1 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1496,7 +1157,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1509,7 +1171,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1522,7 +1185,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[5] = APCI1500_HARDWARE_TRIGGER; break; default: - printk("\nThis choice for software or hardware trigger does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware trigger does not exist\n"); return -EINVAL; } /* switch(data[5]) */ @@ -1535,140 +1199,111 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 2 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 2 and triggers timer/counter 2 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x20; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 2 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1684,7 +1319,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_WATCHDOG; break; default: - printk("\nThis choice is not a watchdog nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a watchdog nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1697,7 +1333,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1710,146 +1347,109 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ - /*****************************/ /* Test if used for watchdog */ - /*****************************/ if (data[2] == APCI1500_WATCHDOG) { - /*****************************/ /* - Enables the output line */ /* - Enables retrigger */ /* - Pulses output */ - /*****************************/ i_TimerCounterMode = data[2] | data[4] | 0x54; } /* if (data[2] == APCI1500_WATCHDOG) */ else { i_TimerCounterMode = data[2] | data[4] | data[6] | 7; } /* elseif (data[2] == APCI1500_WATCHDOG) */ - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of watchdog/counter 3 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables watchdog/counter 3 and triggers watchdog/counter 3 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x10; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************/ /* Test if COUNTER */ - /********************/ if (data[2] == APCI1500_COUNTER) { - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Disable the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Trigger the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1858,12 +1458,14 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1871,44 +1473,25 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, break; default: - printk("\nThe specified counter\timer option does not exist\n"); + dev_warn(dev->hw_dev, + "The specified counter/timer option does not exist\n"); + return -EINVAL; } /* switch(data[1]) */ i_CounterLogic = data[2]; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopTriggerTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, -| struct comedi_insn *insn,unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Start / Stop or trigger the timer counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[1] : 0 start -| 1 stop -| 2 Trigger -| data[2] : 0 Counter -| 1 Timer/Watchdog -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop or trigger the timer counter or Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[1] 0 = Start, 1 = Stop, 2 = Trigger + * data[2] 0 = Counter, 1 = Timer/Watchdog + */ +static int apci1500_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; @@ -1924,13 +1507,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 1 */ - /**************************/ i_TimerCounter1Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1939,20 +1518,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 1 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1965,23 +1541,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter1Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter1Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1990,13 +1560,15 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -2011,13 +1583,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 2 */ - /**************************/ i_TimerCounter2Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2026,20 +1594,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 2 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2051,23 +1616,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter2Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter2Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2076,12 +1635,14 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -2096,13 +1657,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts Watchdog/counter 3 */ - /**************************/ i_WatchdogCounter3Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2112,20 +1669,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device } /* if( i_WatchdogCounter3init==1) */ else { - printk("\nWatchdog/Counter3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog/Counter3 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop Watchdog/counter 3 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2140,23 +1694,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case 0: /* triggering counter 3 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_WatchdogCounter3Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_WatchdogCounter3Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2165,7 +1713,8 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "Counter3 not configured\n"); return -EINVAL; } break; @@ -2173,9 +1722,7 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device /* triggering Watchdog 3 */ if (i_WatchdogCounter3Init == 1) { - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2184,55 +1731,40 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdog 3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog 3 not configured\n"); return -EINVAL; } break; default: - printk("\nWrong choice of watchdog/counter3\n"); + dev_warn(dev->hw_dev, + "Wrong choice of watchdog/counter3\n"); return -EINVAL; } /* switch(data[2]) */ break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; default: - printk("\nThe specified choice for counter/watchdog/timer does not exist\n"); + dev_warn(dev->hw_dev, + "The specified choice for counter/watchdog/timer does not exist\n"); return -EINVAL; } /* switch(data[0]) */ return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadCounterTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + */ +static int apci1500_timer_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; @@ -2242,23 +1774,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/timer1 */ if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter1Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter1Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2266,9 +1792,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR1_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2285,7 +1809,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nTimer/Counter1 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter1 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter1Init==1) */ break; @@ -2293,23 +1818,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/timer2 */ if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter2Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2317,9 +1836,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR2_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2336,7 +1853,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nTimer/Counter2 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter2 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter2Init==1) */ break; @@ -2344,23 +1862,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/watchdog2 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_WatchdogCounter3Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2368,9 +1880,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR3_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2387,12 +1897,14 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdogCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "WatchdogCounter3 not configured\n"); return -EINVAL; } /* elseif( i_WatchdogCounter3Init==1) */ break; default: - printk("\nThe choice of timer/counter/watchdog does not exist\n"); + dev_warn(dev->hw_dev, + "The choice of timer/counter/watchdog does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -2400,31 +1912,15 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadInterruptMask | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read the interrupt mask | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | - - -+----------------------------------------------------------------------------+ -| Output Parameters : -- data[0]:The interrupt mask value data[1]:Channel no -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read the interrupt mask + * + * data[0] The interrupt mask value + * data[1] Channel Number + */ +static int apci1500_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { data[0] = i_InterruptMask; data[1] = i_InputChannel; @@ -2433,31 +1929,12 @@ static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigureInterrupt | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Configures the interrupt registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer | -| - -+----------------------------------------------------------------------------+ -| Output Parameters : -- -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the interrupt registers + */ +static int apci1500_do_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Status; @@ -2474,140 +1951,101 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, i_Constant = 0x00; } /* if{data[0]==0) */ else { - printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n"); + dev_warn(dev->hw_dev, + "The parameter passed to driver is in error for enabling the voltage interrupt\n"); return -EINVAL; } /* else if(data[0]==0) */ } /* elseif(data[0]==1) */ - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Writes the new configuration (APCI1500_OR) */ - /*********************************************/ i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************/ /* Authorises the interrupt on the board */ - /*****************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the pattern polarity register of port B */ - /***************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the pattern transition register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************************/ /* Selects the pattern mask register of port B */ - /***********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Enables the PCI interrupt */ - /*****************************/ outl(0x3000, devpriv->i_IobaseAmcc + 0x38); ui_Status = inl(devpriv->i_IobaseAmcc + 0x10); ui_Status = inl(devpriv->i_IobaseAmcc + 0x38); @@ -2616,24 +2054,7 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1500_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1500_Interrupt(int irq, void *d) +static void apci1500_interrupt(int irq, void *d) { struct comedi_device *dev = d; @@ -2642,44 +2063,28 @@ static void v_APCI1500_Interrupt(int irq, void *d) int i_RegValue = 0; i_InterruptMask = 0; - /***********************************/ /* Read the board interrupt status */ - /***********************************/ ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38); - /***************************************/ /* Test if board generated a interrupt */ - /***************************************/ if ((ui_InterruptStatus & 0x800000) == 0x800000) { - /************************/ /* Disable all Interrupt */ - /************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ /* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ /* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2693,9 +2098,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the interrupt vector register of port A */ - /***************************************************/ outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2711,45 +2114,32 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* elseif(i_Logic==APCI1500_OR_PRIORITY) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - printk("\n\n\n"); - /****************/ /* Reads port B */ - /****************/ i_RegValue = inb((unsigned int) devpriv->iobase + APCI1500_Z8536_PORT_B); i_RegValue = i_RegValue & 0xC0; - /**************************************/ /* Tests if this is an external error */ - /**************************************/ if (i_RegValue) { /* Disable the interrupt */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outl(0x0, devpriv->i_IobaseAmcc + 0x38); if (i_RegValue & 0x80) { @@ -2767,46 +2157,34 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if (i_RegValue) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 4; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2814,23 +2192,17 @@ static void v_APCI1500_Interrupt(int irq, void *d) i_InterruptMask = i_InterruptMask | 8; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2844,42 +2216,23 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if ((i_RegValue & 0x60) == 0x60) */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - /***********************/ /* Enable all Interrupts */ - /***********************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */ else { - printk("\nInterrupt from unknown source\n"); + dev_warn(dev->hw_dev, + "Interrupt from unknown source\n"); } /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */ return; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Reset(struct comedi_device *dev) +static int apci1500_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_DummyRead = 0; @@ -2898,9 +2251,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) i_TimerCounter2Enabled = 0; i_WatchdogCounter3Enabled = 0; - /******************/ /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2908,16 +2259,12 @@ static int i_APCI1500_Reset(struct comedi_device *dev) outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2949,9 +2296,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2981,9 +2326,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -2998,9 +2341,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3010,9 +2351,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3022,9 +2361,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3034,71 +2371,43 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* reset all the digital outputs */ outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); -/*******************************/ /* Disable the board interrupt */ -/*******************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 3*/ -/*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index 84668544f52d..9c86b02eb6da 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -1,74 +1,32 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1564 | Compiler : GCC | - | Module name : hwdrv_apci1564.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1564 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/********* Definitions for APCI-1564 card *****/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ #define APCI1564_ADDRESS_RANGE 128 -/* DIGITAL INPUT-OUTPUT DEFINE */ -/* Input defines */ -#define APCI1564_DIGITAL_IP 0x04 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE1 4 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE2 8 -#define APCI1564_DIGITAL_IP_IRQ 16 - -/* Output defines */ -#define APCI1564_DIGITAL_OP 0x18 -#define APCI1564_DIGITAL_OP_RW 0 -#define APCI1564_DIGITAL_OP_INTERRUPT 4 -#define APCI1564_DIGITAL_OP_IRQ 12 - /* Digital Input IRQ Function Selection */ #define ADDIDATA_OR 0 #define ADDIDATA_AND 1 -/* Digital Input Interrupt Status */ -#define APCI1564_DIGITAL_IP_INTERRUPT_STATUS 12 - -/* Digital Output Interrupt Status */ -#define APCI1564_DIGITAL_OP_INTERRUPT_STATUS 8 - /* Digital Input Interrupt Enable Disable. */ #define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4 #define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE 0xfffffffb @@ -80,98 +38,91 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY #define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xfffffffd /* TIMER COUNTER WATCHDOG DEFINES */ - #define ADDIDATA_TIMER 0 #define ADDIDATA_COUNTER 1 #define ADDIDATA_WATCHDOG 2 -#define APCI1564_DIGITAL_OP_WATCHDOG 0x28 -#define APCI1564_TIMER 0x48 -#define APCI1564_COUNTER1 0x0 -#define APCI1564_COUNTER2 0x20 -#define APCI1564_COUNTER3 0x40 -#define APCI1564_COUNTER4 0x60 -#define APCI1564_TCW_SYNC_ENABLEDISABLE 0 -#define APCI1564_TCW_RELOAD_VALUE 4 -#define APCI1564_TCW_TIMEBASE 8 -#define APCI1564_TCW_PROG 12 -#define APCI1564_TCW_TRIG_STATUS 16 -#define APCI1564_TCW_IRQ 20 -#define APCI1564_TCW_WARN_TIMEVAL 24 -#define APCI1564_TCW_WARN_TIMEBASE 28 +#define APCI1564_COUNTER1 0 +#define APCI1564_COUNTER2 1 +#define APCI1564_COUNTER3 2 +#define APCI1564_COUNTER4 3 + +/* + * devpriv->i_IobaseAmcc Register Map + */ +#define APCI1564_DI_REG 0x04 +#define APCI1564_DI_INT_MODE1_REG 0x08 +#define APCI1564_DI_INT_MODE2_REG 0x0c +#define APCI1564_DI_INT_STATUS_REG 0x10 +#define APCI1564_DI_IRQ_REG 0x14 +#define APCI1564_DO_REG 0x18 +#define APCI1564_DO_INT_CTRL_REG 0x1c +#define APCI1564_DO_INT_STATUS_REG 0x20 +#define APCI1564_DO_IRQ_REG 0x24 +#define APCI1564_WDOG_REG 0x28 +#define APCI1564_WDOG_RELOAD_REG 0x2c +#define APCI1564_WDOG_TIMEBASE_REG 0x30 +#define APCI1564_WDOG_CTRL_REG 0x34 +#define APCI1564_WDOG_STATUS_REG 0x38 +#define APCI1564_WDOG_IRQ_REG 0x3c +#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x40 +#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x44 +#define APCI1564_TIMER_REG 0x48 +#define APCI1564_TIMER_RELOAD_REG 0x4c +#define APCI1564_TIMER_TIMEBASE_REG 0x50 +#define APCI1564_TIMER_CTRL_REG 0x54 +#define APCI1564_TIMER_STATUS_REG 0x58 +#define APCI1564_TIMER_IRQ_REG 0x5c +#define APCI1564_TIMER_WARN_TIMEVAL_REG 0x60 +#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64 + +/* + * devpriv->iobase Register Map + */ +#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20)) +#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20)) +#define APCI1564_TCW_TIMEBASE_REG(x) (0x08 + ((x) * 0x20)) +#define APCI1564_TCW_CTRL_REG(x) (0x0c + ((x) * 0x20)) +#define APCI1564_TCW_STATUS_REG(x) (0x10 + ((x) * 0x20)) +#define APCI1564_TCW_IRQ_REG(x) (0x14 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20)) /* Global variables */ -static unsigned int ui_InterruptStatus_1564 = 0; +static unsigned int ui_InterruptStatus_1564; static unsigned int ui_InterruptData, ui_Type; /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures the digital input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 1 Enable Digital Input Interrupt | -| 0 Disable Digital Input Interrupt | -| data[1] : 0 ADDIDATA Interrupt OR LOGIC | -| : 1 ADDIDATA Interrupt AND LOGIC | -| data[2] : Interrupt mask for the mode 1 | -| data[3] : Interrupt mask for the mode 2 | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the digital input Subdevice + * + * data[0] 1 = Enable interrupt, 0 = Disable interrupt + * data[1] 0 = ADDIDATA Interrupt OR LOGIC, 1 = ADDIDATA Interrupt AND LOGIC + * data[2] Interrupt mask for the mode 1 + * data[3] Interrupt mask for the mode 2 + */ +static int apci1564_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; devpriv->tsk_Current = current; - /*******************************/ + /* Set the digital input logic */ - /*******************************/ if (data[0] == ADDIDATA_ENABLE) { data[2] = data[2] << 4; data[3] = data[3] << 4; - outl(data[2], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - if (data[1] == ADDIDATA_OR) { - outl(0x4, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* if (data[1] == ADDIDATA_OR) */ - else { - outl(0x6, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[1] == ADDIDATA_OR) */ - } /* if (data[0] == ADDIDATA_ENABLE) */ - else { - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[0] == ADDIDATA_ENABLE) */ + outl(data[2], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + if (data[1] == ADDIDATA_OR) + outl(0x4, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + else + outl(0x6, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } else { + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } return insn->n; } @@ -183,40 +134,21 @@ static int apci1564_di_insn_bits(struct comedi_device *dev, { struct addi_private *devpriv = dev->private; - data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DI_REG); return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[1] : 1 Enable VCC Interrupt | -| 0 Disable VCC Interrupt | -| data[2] : 1 Enable CC Interrupt | -| 0 Disable CC Interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Digital Output Subdevice. + * + * data[1] 0 = Disable VCC Interrupt, 1 = Enable VCC Interrupt + * data[2] 0 = Disable CC Interrupt, 1 = Enable CC Interrupt + */ +static int apci1564_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command = 0; @@ -225,31 +157,25 @@ static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } /* if ((data[0]!=0) && (data[0]!=1)) */ - if (data[0]) { + } + + if (data[0]) devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0]) */ - else { + else devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0]) */ - if (data[1] == ADDIDATA_ENABLE) { + + if (data[1] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x1; - } /* if (data[1] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFE; - } /* else if (data[1] == ADDIDATA_ENABLE) */ - if (data[2] == ADDIDATA_ENABLE) { + + if (data[2] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x2; - } /* if (data[2] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFD; - } /* else if (data[2] == ADDIDATA_ENABLE) */ - outl(ul_Command, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); - ui_InterruptData = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); + + outl(ul_Command, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + ui_InterruptData = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); devpriv->tsk_Current = current; return insn->n; } @@ -261,12 +187,10 @@ static int apci1564_do_insn_bits(struct comedi_device *dev, { struct addi_private *devpriv = dev->private; - s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); + s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DO_REG); if (comedi_dio_update_state(s, data)) - outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); + outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DO_REG); data[1] = s->state; @@ -274,39 +198,20 @@ static int apci1564_do_insn_bits(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Counter | -| 2 Configure As Watchdog | -| data[1] : 1 Enable Interrupt | -| 0 Disable Interrupt | -| data[2] : Time Unit | -| data[3] : Reload Value | -| data[4] : Timer Mode | -| data[5] : Timer Counter Watchdog Number| - data[6] : Counter Direction -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * 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; @@ -316,89 +221,59 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; /* Disable the watchdog */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); /* Loading the Reload value */ - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_RELOAD_VALUE); - } /* if (data[0]==ADDIDATA_WATCHDOG) */ - else if (data[0] == ADDIDATA_TIMER) { + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG); + } else if (data[0] == ADDIDATA_TIMER) { /* First Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Stop The Timer */ + /* Stop The Timer */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { - outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ); + /* 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_OP_WATCHDOG + - APCI1564_TCW_IRQ); + devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ); + devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ); + devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)); 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) */ + devpriv->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(devpriv->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, devpriv->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], devpriv->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1)); - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -406,65 +281,36 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Disable the timer mode */ /* - Enable the counter mode */ - /******************************/ + ul_Command1 = (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | (unsigned int) ((unsigned int) data[4] << 16UL); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + outl(ul_Command1, devpriv->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, devpriv->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, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + } else { + dev_err(dev->class_dev, "Invalid subdevice.\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_StartStopWriteTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : 1 Start | -| 0 Stop | -| 2 Trigger | -| Clear (Only Counter) | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop The Selected Timer, Counter or Watchdog + * + * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter) + */ +static int apci1564_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -472,203 +318,122 @@ static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *d if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { switch (data[1]) { case 0: /* stop the watchdog */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); /* disable the watchdog */ + /* disable the watchdog */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 1: /* start the watchdog */ - outl(0x0001, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0001, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 2: /* Software trigger */ - outl(0x0201, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0201, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; default: - printk("\nSpecified functionality does not exist\n"); + dev_err(dev->class_dev, "Specified functionality does not exist.\n"); return -EINVAL; - } /* switch (data[1]) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Timer */ - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* if (data[1]==1) */ - else if (data[1] == 0) { + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } else if (data[1] == 0) { /* Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* else if(data[1]==0) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_PROG); + inl(devpriv->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) */ + devpriv->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | - -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Selected Timer, Counter or Watchdog + */ +static int apci1564_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { /* Stores the status of the Watchdog */ - data[0] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_TRIG_STATUS) & 0x1; - data[1] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_STATUS_REG) & 0x1; + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { /* Stores the status of the Timer */ - data[0] = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_TRIG_STATUS) & 0x1; + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_STATUS_REG) & 0x1; /* Stores the Actual value of the Timer */ - data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { /* Read the Counter Actual Value. */ data[0] = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + - APCI1564_TCW_SYNC_ENABLEDISABLE); + inl(devpriv->iobase + + APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1)); ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_TRIG_STATUS); + inl(devpriv->iobase + + APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1)); - /***********************************/ /* Get the software trigger status */ - /***********************************/ data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); - /***********************************/ /* Get the hardware trigger status */ - /***********************************/ data[2] = (unsigned char) ((ul_Command1 >> 2) & 1); - /*********************************/ /* Get the software clear status */ - /*********************************/ data[3] = (unsigned char) ((ul_Command1 >> 3) & 1); - /***************************/ /* Get the overflow status */ - /***************************/ data[4] = (unsigned char) ((ul_Command1 >> 0) & 1); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ - else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) + } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG) && (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) { - printk("\n Invalid Subdevice !!!\n"); - } /* else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) */ + dev_err(dev->class_dev, "Invalid Subdevice!\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadInterruptStatus | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task :Reads the interrupt status register | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Reads the interrupt status register + */ +static int apci1564_do_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { *data = ui_Type; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1564_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler for the interruptible digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1564_Interrupt(int irq, void *d) + * Interrupt handler for the interruptible digital inputs + */ +static void apci1564_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -677,79 +442,63 @@ static void v_APCI1564_Interrupt(int irq, void *d) unsigned int ui_C1, ui_C2, ui_C3, ui_C4; unsigned int ul_Command2 = 0; - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ) & 0x01; - ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ) & 0x01; - ui_Timer = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_IRQ) & 0x01; - ui_C1 = inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ) & 0x1; - ui_C2 = inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ) & 0x1; - ui_C3 = inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_IRQ) & 0x1; - ui_C4 = inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_IRQ) & 0x1; + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG) & 0x01; + ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01; + ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01; + ui_C1 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1; + ui_C2 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1; + ui_C3 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1; + ui_C4 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1; if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0 && ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) { - printk("\nInterrupt from unknown source\n"); - } /* if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) */ + dev_err(dev->class_dev, "Interrupt from unknown source.\n"); + } if (ui_DI == 1) { - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); ui_InterruptStatus_1564 = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_STATUS); + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0; - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); /* enable the interrupt */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + /* enable the interrupt */ + outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); return; } if (ui_DO == 1) { - /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ - ui_Type = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; + /* Check for Digital Output interrupt Type */ + /* 1: VCC interrupt */ + /* 2: CC interrupt */ + ui_Type = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_STATUS_REG) & 0x3; /* Disable the Interrupt */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); /* Sends signal to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - - } /* if (ui_DO) */ + } if (ui_Timer == 1) { devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (devpriv->b_TimerSelectMode) { /* Disable Timer Interrupt */ - ul_Command2 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command2 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Timer Interrupt */ - outl(ul_Command2, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + outl(ul_Command2, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); } - }/* if (ui_Timer == 1) */ - + } if (ui_C1 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -757,21 +506,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + devpriv->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); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); } - } /* if (ui_C1 == 1) */ + } if (ui_C2 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -779,21 +525,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + devpriv->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); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); } - } /* if ((ui_C2 == 1) */ + } if (ui_C3 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -801,21 +544,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + devpriv->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); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); } - } /* if ((ui_C3 == 1) */ + } if (ui_C4 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -823,60 +563,45 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + devpriv->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); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); } - } /* if (ui_C4 == 1) */ + } return; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1564_Reset(struct comedi_device *dev) +static int apci1564_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); /* disable the interrupts */ - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2); + /* disable the interrupts */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + /* Reset the interrupt status register */ + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); + /* Disable the and/or interrupt */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); 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); + /* Resets the output channels */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG); + /* Disables the interrupt. */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index bd05857b82f2..70e8f426285c 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -248,10 +248,10 @@ static const struct comedi_lrange range_apci3120_ao = { +----------------------------------------------------------------------------+ */ -static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -304,11 +304,11 @@ static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, * If the last argument of function "check"is 1 then it only checks * the channel list is ok or not. */ -static int i_APCI3120_SetupChannelList(struct comedi_device *dev, - struct comedi_subdevice *s, - int n_chan, - unsigned int *chanlist, - char check) +static int apci3120_setup_chan_list(struct comedi_device *dev, + struct comedi_subdevice *s, + int n_chan, + unsigned int *chanlist, + char check) { struct addi_private *devpriv = dev->private; unsigned int i; /* , differencial=0, bipolar=0; */ @@ -358,10 +358,10 @@ static int i_APCI3120_SetupChannelList(struct comedi_device *dev, * as per configured if no conversion time is set uses default * conversion time 10 microsec. */ -static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -417,10 +417,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, inw(devpriv->iobase + APCI3120_RESET_FIFO); /* Initialize the sequence array */ - - /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */ - - if (!i_APCI3120_SetupChannelList(dev, s, 1, + if (!apci3120_setup_chan_list(dev, s, 1, &insn->chanspec, 0)) return -EINVAL; @@ -512,7 +509,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - if (!i_APCI3120_SetupChannelList(dev, s, + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, devpriv->ui_AiChannelList, 0)) return -EINVAL; @@ -606,7 +603,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, } -static int i_APCI3120_Reset(struct comedi_device *dev) +static int apci3120_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; unsigned int i; @@ -663,7 +660,7 @@ static int i_APCI3120_Reset(struct comedi_device *dev) return 0; } -static int i_APCI3120_ExttrigEnable(struct comedi_device *dev) +static int apci3120_exttrig_enable(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; @@ -672,7 +669,7 @@ static int i_APCI3120_ExttrigEnable(struct comedi_device *dev) return 0; } -static int i_APCI3120_ExttrigDisable(struct comedi_device *dev) +static int apci3120_exttrig_disable(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; @@ -681,8 +678,8 @@ static int i_APCI3120_ExttrigDisable(struct comedi_device *dev) return 0; } -static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; @@ -705,7 +702,7 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */ /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->us_OutputRegister = 0; /* stop counters */ @@ -729,13 +726,13 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; devpriv->b_InterruptMode = APCI3120_EOC_MODE; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } -static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3120_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { const struct addi_board *this_board = comedi_board(dev); int err = 0; @@ -818,9 +815,9 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, * If DMA is configured does DMA initialization otherwise does the * acquisition with EOS interrupt. */ -static int i_APCI3120_CyclicAnalogInput(int mode, - struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_cyclic_ai(int mode, + struct comedi_device *dev, + struct comedi_subdevice *s) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -904,7 +901,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /**********************************/ /* Initializes the sequence array */ /**********************************/ - if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels, + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, devpriv->pui_AiChannelList, 0)) return -EINVAL; @@ -957,7 +954,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /*** EL241003 End ******************************************************************************/ if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) - i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */ + apci3120_exttrig_enable(dev); /* activate EXT trigger */ switch (mode) { case 1: /* init timer0 in mode 2 */ @@ -1333,8 +1330,8 @@ static int i_APCI3120_CyclicAnalogInput(int mode, * Does asynchronous acquisition. * Determines the mode 1 or 2. */ -static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -1371,7 +1368,7 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ /* return this_board->ai_cmd(1,dev,s); */ - return i_APCI3120_CyclicAnalogInput(1, dev, s); + return apci3120_cyclic_ai(1, dev, s); } } @@ -1381,7 +1378,7 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, devpriv->ui_AiTimer1 = cmd->scan_begin_arg; devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ /* return this_board->ai_cmd(2,dev,s); */ - return i_APCI3120_CyclicAnalogInput(2, dev, s); + return apci3120_cyclic_ai(2, dev, s); } return -1; } @@ -1410,7 +1407,7 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, * For continuous DMA it reinitializes the DMA operation. * For single mode DMA it stop the acquisition. */ -static void v_APCI3120_InterruptDma(int irq, void *d) +static void apci3120_interrupt_dma(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -1429,7 +1426,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) } if (samplesinbuf & 1) { comedi_error(dev, "Odd count of bytes in DMA ring!"); - i_APCI3120_StopCyclicAcquisition(dev, s); + apci3120_cancel(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; return; @@ -1500,7 +1497,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) if (!devpriv->b_AiContinuous) if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { /* all data sampled */ - i_APCI3120_StopCyclicAcquisition(dev, s); + apci3120_cancel(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); @@ -1565,7 +1562,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) * This function handles EOS interrupt. * This function copies the acquired data(from FIFO) to Comedi buffer. */ -static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) +static int apci3120_interrupt_handle_eos(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -1574,8 +1571,6 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) n_chan = devpriv->ui_AiNbrofChannels; - s->async->events = 0; - for (i = 0; i < n_chan; i++) err &= comedi_buf_put(s->async, inw(dev->iobase + 0)); @@ -1589,7 +1584,7 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) return 0; } -static void v_APCI3120_Interrupt(int irq, void *d) +static void apci3120_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -1615,7 +1610,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->b_ExttrigEnable = APCI3120_DISABLE; } /* clear the timer 2 interrupt */ @@ -1655,7 +1650,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { ui_Check = 0; - i_APCI3120_InterruptHandleEos(dev); + apci3120_interrupt_handle_eos(dev); devpriv->ui_AiActualScan++; devpriv->b_ModeSelectRegister = devpriv-> @@ -1711,7 +1706,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) dev->iobase + APCI3120_WR_ADDRESS); /* stop timer 0 and timer 1 */ - i_APCI3120_StopCyclicAcquisition(dev, s); + apci3120_cancel(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ @@ -1765,7 +1760,8 @@ static void v_APCI3120_Interrupt(int irq, void *d) /* Clears the timer status register */ /************************************/ inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - v_APCI3120_InterruptDma(irq, d); /* do some data transfer */ + /* do some data transfer */ + apci3120_interrupt_dma(irq, d); } else { /* Stops the Timer */ outw(devpriv-> @@ -1787,7 +1783,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) * data[1] = Timer constant * data[2] = Timer2 interrupt (1)enable or(0) disable */ -static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, +static int apci3120_config_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1932,7 +1928,7 @@ static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, * = 1 Timer * = 2 Watch dog */ -static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, +static int apci3120_write_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -2104,7 +2100,7 @@ static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, * for watchdog: data[0] = 0 (still running) * = 1 (run down) */ -static int i_APCI3120_InsnReadTimer(struct comedi_device *dev, +static int apci3120_read_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -2189,10 +2185,10 @@ static int apci3120_do_insn_bits(struct comedi_device *dev, return insn->n; } -static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Range, ui_Channel; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 8c85a09d1c66..0536d8373861 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -1268,7 +1268,7 @@ static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, return 0; } -static int i_APCI3200_Reset(struct comedi_device *dev) +static int apci3200_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_Temp; @@ -1322,10 +1322,10 @@ static int i_APCI3200_Reset(struct comedi_device *dev) * data[7] : Channel current source from eeprom * data[8] : Channle gain factor from eeprom */ -static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { unsigned int ui_DummyValue = 0; int i_ConvertCJCCalibration; @@ -1336,7 +1336,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, if (s_BoardInfos[dev->minor].i_Initialised == 0) /* END JK 06.07.04: Management of sevrals boards */ { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ @@ -1586,7 +1586,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, break; default: printk("\nThe parameters passed are in error\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* switch(insn->unused[0]) */ @@ -1626,10 +1626,10 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, * = 2 RTD 3 wire connection * = 3 RTD 4 wire connection */ -static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Config = 0, ul_Temp = 0; @@ -1970,7 +1970,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, } /* switch(data[11]) */ } /* elseif(data[12]==0 || data[12]==1) */ if (i_err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_ScanType!=1) */ @@ -2079,7 +2079,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, /* END JK 06.07.04: Management of sevrals boards */ insn->unused[0] = 0; - i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy); + apci3200_ai_read(dev, s, insn, &ui_Dummy); } return insn->n; @@ -2095,10 +2095,10 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, * data[1] : calibration offset * data[2] : calibration gain */ -static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_bits_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; @@ -2107,12 +2107,12 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, /* if(i_Initialised==0) */ if (s_BoardInfos[dev->minor].i_Initialised == 0) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ if (data[0] != 0 && data[0] != 1) { printk("\nError in selection of functionality\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(data[0]!=0 && data[0]!=1) */ @@ -2202,18 +2202,18 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, return insn->n; } -static int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return insn->n; } -static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3200_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; @@ -2241,7 +2241,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, err |= -EINVAL; if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 1; } @@ -2267,7 +2267,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, } if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 2; } /* i_FirstChannel=cmd->chanlist[0]; */ @@ -2308,7 +2308,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, printk("\nThe Delay time value is in error\n"); } if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 3; } fpu_begin(); @@ -2366,15 +2366,15 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 4; } return 0; } -static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3200_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; @@ -2410,8 +2410,8 @@ static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, * Does asynchronous acquisition * Determines the mode 1 or 2. */ -static int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3200_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -2619,7 +2619,6 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /* This value is not used */ /* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */ - s->async->events = 0; /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /*************************************/ @@ -2730,7 +2729,7 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) return 0; } -static void v_APCI3200_Interrupt(int irq, void *d) +static void apci3200_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index ebc1534a8df8..20e89b0bdc4d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -16,10 +16,10 @@ * data[2] : Time Unit * data[3] : Reload Value */ -static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_config_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -86,10 +86,10 @@ static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, * 0 Stop * 2 Trigger */ -static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_write_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -153,10 +153,10 @@ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *d * 2 Watchdog * data[1] : Timer Counter Watchdog Number */ -static int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_read_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c index ccd49211ea17..4da9db35b8e2 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -27,13 +27,13 @@ static const struct addi_board apci035_boardtypes[] = { .i_Timer = 1, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI035_Interrupt, - .reset = i_APCI035_Reset, - .ai_config = i_APCI035_ConfigAnalogInput, - .ai_read = i_APCI035_ReadAnalogInput, - .timer_config = i_APCI035_ConfigTimerWatchdog, - .timer_write = i_APCI035_StartStopWriteTimerWatchdog, - .timer_read = i_APCI035_ReadTimerWatchdog, + .interrupt = apci035_interrupt, + .reset = apci035_reset, + .ai_config = apci035_ai_config, + .ai_read = apci035_ai_read, + .timer_config = apci035_timer_config, + .timer_write = apci035_timer_write, + .timer_read = apci035_timer_read, }, }; diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index 74f7ace8adbc..bd8e08ca14c0 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -20,19 +20,19 @@ static const struct addi_board apci1500_boardtypes[] = { .i_NbrDoChannel = 16, .i_DoMaxdata = 0xffff, .i_Timer = 1, - .interrupt = v_APCI1500_Interrupt, - .reset = i_APCI1500_Reset, - .di_config = i_APCI1500_ConfigDigitalInputEvent, - .di_read = i_APCI1500_Initialisation, - .di_write = i_APCI1500_StartStopInputEvent, + .interrupt = apci1500_interrupt, + .reset = apci1500_reset, + .di_config = apci1500_di_config, + .di_read = apci1500_di_read, + .di_write = apci1500_di_write, .di_bits = apci1500_di_insn_bits, - .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt, - .do_write = i_APCI1500_WriteDigitalOutput, - .do_bits = i_APCI1500_ConfigureInterrupt, - .timer_config = i_APCI1500_ConfigCounterTimerWatchdog, - .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog, - .timer_read = i_APCI1500_ReadInterruptMask, - .timer_bits = i_APCI1500_ReadCounterTimerWatchdog, + .do_config = apci1500_do_config, + .do_write = apci1500_do_write, + .do_bits = apci1500_do_bits, + .timer_config = apci1500_timer_config, + .timer_write = apci1500_timer_write, + .timer_read = apci1500_timer_read, + .timer_bits = apci1500_timer_bits, }, }; diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 6248284caaf5..27aa9ae1bdd9 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -21,16 +21,16 @@ static const struct addi_board apci1564_boardtypes[] = { .i_NbrDoChannel = 32, .i_DoMaxdata = 0xffffffff, .i_Timer = 1, - .interrupt = v_APCI1564_Interrupt, - .reset = i_APCI1564_Reset, - .di_config = i_APCI1564_ConfigDigitalInput, + .interrupt = apci1564_interrupt, + .reset = apci1564_reset, + .di_config = apci1564_di_config, .di_bits = apci1564_di_insn_bits, - .do_config = i_APCI1564_ConfigDigitalOutput, + .do_config = apci1564_do_config, .do_bits = apci1564_do_insn_bits, - .do_read = i_APCI1564_ReadInterruptStatus, - .timer_config = i_APCI1564_ConfigTimerCounterWatchdog, - .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog, - .timer_read = i_APCI1564_ReadTimerCounterWatchdog, + .do_read = apci1564_do_read, + .timer_config = apci1564_timer_config, + .timer_write = apci1564_timer_write, + .timer_read = apci1564_timer_read, }, }; diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 1e6fa56c516e..57ee6e5c7635 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -26,7 +26,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, [BOARD_APCI3001] = { .pc_DriverName = "apci3001", @@ -37,7 +37,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, }; @@ -136,11 +136,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = this_board->i_AiChannelList; s->range_table = &range_apci3120_ai; - s->insn_config = i_APCI3120_InsnConfigAnalogInput; - s->insn_read = i_APCI3120_InsnReadAnalogInput; - s->do_cmdtest = i_APCI3120_CommandTestAnalogInput; - s->do_cmd = i_APCI3120_CommandAnalogInput; - s->cancel = i_APCI3120_StopCyclicAcquisition; + s->insn_config = apci3120_ai_insn_config; + s->insn_read = apci3120_ai_insn_read; + s->do_cmdtest = apci3120_ai_cmdtest; + s->do_cmd = apci3120_ai_cmd; + s->cancel = apci3120_cancel; /* Allocate and Initialise AO Subdevice Structures */ s = &dev->subdevices[1]; @@ -151,7 +151,7 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = this_board->i_AoMaxdata; s->len_chanlist = this_board->i_NbrAoChannel; s->range_table = &range_apci3120_ao; - s->insn_write = i_APCI3120_InsnWriteAnalogOutput; + s->insn_write = apci3120_ao_insn_write; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -186,11 +186,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3120_InsnWriteTimer; - s->insn_read = i_APCI3120_InsnReadTimer; - s->insn_config = i_APCI3120_InsnConfigTimer; + s->insn_write = apci3120_write_insn_timer; + s->insn_read = apci3120_read_insn_timer; + s->insn_config = apci3120_config_insn_timer; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } @@ -200,7 +200,7 @@ static void apci3120_detach(struct comedi_device *dev) if (devpriv) { if (dev->iobase) - i_APCI3120_Reset(dev); + apci3120_reset(dev); if (dev->irq) free_irq(dev->irq, dev); if (devpriv->ul_DmaBufferVirtual[0]) { diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c index 9868a5369aff..f0f891a482a3 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ b/drivers/staging/comedi/drivers/addi_apci_3200.c @@ -43,15 +43,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, @@ -68,15 +68,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index 4cb69ec54c9b..49bf1fb840f6 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -390,9 +390,9 @@ static int apci3501_auto_attach(struct comedi_device *dev, s->maxdata = 0; s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog; - s->insn_read = i_APCI3501_ReadTimerCounterWatchdog; - s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog; + s->insn_write = apci3501_write_insn_timer; + s->insn_read = apci3501_read_insn_timer; + s->insn_config = apci3501_config_insn_timer; /* Initialize the eeprom subdevice */ s = &dev->subdevices[4]; diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index ceadf8eff47f..6dc11c407f57 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -434,13 +434,26 @@ static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec) return 0; } +static int apci3xxx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 20); + if (status & 0x1) + return 0; + return -EBUSY; +} + static int apci3xxx_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct apci3xxx_private *devpriv = dev->private; - unsigned int val; int ret; int i; @@ -453,10 +466,9 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev, writel(0x80000, devpriv->mmio + 8); /* Wait the EOS */ - do { - val = readl(devpriv->mmio + 20); - val &= 0x1; - } while (!val); + ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0); + if (ret) + return ret; /* Read the analog value */ data[i] = readl(devpriv->mmio + 28); @@ -622,6 +634,20 @@ static int apci3xxx_ai_cancel(struct comedi_device *dev, return 0; } +static int apci3xxx_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 96); + if (status & 0x100) + return 0; + return -EBUSY; +} + static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -630,7 +656,7 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct apci3xxx_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int status; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -641,9 +667,9 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, writel((data[i] << 8) | chan, devpriv->mmio + 100); /* Wait the end of transfer */ - do { - status = readl(devpriv->mmio + 96); - } while ((status & 0x100) != 0x100); + ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0); + if (ret) + return ret; } return insn->n; @@ -680,7 +706,7 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask; + unsigned int mask = 0; int ret; /* @@ -688,12 +714,13 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, * Port 1 (channels 8-15) are always outputs * Port 2 (channels 16-23) are programmable i/o */ - if (chan < 16) { - if (data[0] != INSN_CONFIG_DIO_QUERY) + if (data[0] != INSN_CONFIG_DIO_QUERY) { + /* ignore all other instructions for ports 0 and 1 */ + if (chan < 16) return -EINVAL; - } else { - /* changing any channel in port 2 changes the entire port */ - mask = 0xff0000; + else + /* changing any channel in port 2 changes the entire port */ + mask = 0xff0000; } ret = comedi_dio_insn_config(dev, s, insn, data, mask); diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 5c1413abc52d..921f6942dfce 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -73,19 +73,17 @@ struct pci6208_private { unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS]; }; -static int pci6208_ao_wait_for_data_send(struct comedi_device *dev, - unsigned int timeout) +static int pci6208_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; - while (timeout--) { - status = inw(dev->iobase + PCI6208_AO_STATUS); - if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) - return 0; - udelay(1); - } - - return -ETIME; + status = inw(dev->iobase + PCI6208_AO_STATUS); + if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) + return 0; + return -EBUSY; } static int pci6208_ao_insn_write(struct comedi_device *dev, @@ -102,8 +100,8 @@ static int pci6208_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - /* D/A transfer rate is 2.2us, wait up to 10us */ - ret = pci6208_ao_wait_for_data_send(dev, 10); + /* D/A transfer rate is 2.2us */ + ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index 6f622b4de698..5e3cc77a8a0c 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -239,9 +239,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev, } } - dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n", - dev->board_name, board->di_nchan, board->do_nchan); - return 0; } diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index 363f2e42a27f..a29ceacb966d 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -84,7 +84,6 @@ TODO: #define PCI9111_RANGE_SETTING_DELAY 10 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2 -#define PCI9111_AI_INSTANT_READ_TIMEOUT 100 /* * IO address map and bit defines @@ -490,29 +489,18 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, dev->iobase + PCI9111_AI_RANGE_STAT_REG); /* Set counter */ - - switch (async_cmd->stop_src) { - case TRIG_COUNT: + if (async_cmd->stop_src == TRIG_COUNT) { dev_private->stop_counter = async_cmd->stop_arg * async_cmd->chanlist_len; dev_private->stop_is_none = 0; - break; - - case TRIG_NONE: + } else { /* TRIG_NONE */ dev_private->stop_counter = 0; dev_private->stop_is_none = 1; - break; - - default: - comedi_error(dev, "Invalid stop trigger"); - return -1; } /* Set timer pacer */ - dev_private->scan_delay = 0; - switch (async_cmd->convert_src) { - case TRIG_TIMER: + if (async_cmd->convert_src == TRIG_TIMER) { pci9111_trigger_source_set(dev, software); pci9111_timer_set(dev); pci9111_fifo_reset(dev); @@ -528,11 +516,7 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, (async_cmd->convert_arg * async_cmd->chanlist_len)) - 1; } - - break; - - case TRIG_EXT: - + } else { /* TRIG_EXT */ pci9111_trigger_source_set(dev, external); pci9111_fifo_reset(dev); pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, @@ -540,11 +524,6 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, plx9050_interrupt_control(dev_private->lcr_io_base, true, true, false, true, true); - break; - - default: - comedi_error(dev, "Invalid convert trigger"); - return -1; } dev_private->stop_counter *= (1 + dev_private->scan_delay); @@ -613,9 +592,8 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); outb(0, dev->iobase + PCI9111_INT_CLR_REG); - pci9111_ai_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -693,20 +671,31 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) } } - if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) { + if (dev_private->stop_counter == 0 && !dev_private->stop_is_none) async->events |= COMEDI_CB_EOA; - pci9111_ai_cancel(dev, s); - } outb(0, dev->iobase + PCI9111_INT_CLR_REG); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } +static int pci9111_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + if (status & PCI9111_AI_STAT_FF_EF) + return 0; + return -EBUSY; +} + static int pci9111_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -717,7 +706,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, unsigned int invert = (maxdata + 1) >> 1; unsigned int shift = (maxdata == 0xffff) ? 0 : 4; unsigned int status; - int timeout; + int ret; int i; outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG); @@ -734,22 +723,12 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, /* Generate a software trigger */ outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG); - timeout = PCI9111_AI_INSTANT_READ_TIMEOUT; - - while (timeout--) { - status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); - /* '1' means FIFO is not empty */ - if (status & PCI9111_AI_STAT_FF_EF) - goto conversion_done; + ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0); + if (ret) { + pci9111_fifo_reset(dev); + return ret; } - comedi_error(dev, "A/D read timeout"); - data[i] = 0; - pci9111_fifo_reset(dev); - return -ETIME; - -conversion_done: - data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG); data[i] = ((data[i] >> shift) & maxdata) ^ invert; } @@ -906,8 +885,6 @@ static int pci9111_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = pci9111_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 4bdd9720e9eb..3cfa1756fa6a 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -571,12 +571,26 @@ static int setup_channel_list(struct comedi_device *dev, return 1; /* we can serve this with scan logic */ } +static int pci9118_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inl(dev->iobase + PCI9118_ADSTAT); + if (status & AdStatus_ADrdy) + return 0; + return -EBUSY; +} + static int pci9118_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci9118_private *devpriv = dev->private; - int n, timeout; + int ret; + int n; devpriv->AdControlReg = AdControl_Int & 0xff; devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; @@ -597,19 +611,13 @@ 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) { data[n] = (inl(dev->iobase + @@ -911,8 +919,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; } @@ -948,8 +955,6 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, struct pci9118_private *devpriv = dev->private; unsigned short sampl; - s->async->events = 0; - if (int_adstat & devpriv->ai_maskerr) if (pci9118_decode_error_status(dev, s, int_adstat)) return; @@ -965,8 +970,7 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, sampl & 0x000f, devpriv->chanlist[s->async->cur_chan]); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } } @@ -977,16 +981,14 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, /* one scan done */ s->async->cur_chan %= devpriv->ai_n_scanlen; 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 >= devpriv->ai_scans) 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, @@ -1001,16 +1003,14 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, 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) @@ -1048,12 +1048,11 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, m = m - sampls; /* m= how many samples was transferred */ } - if (!devpriv->ai_neverending) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pci9118_ai_cancel(dev, s); + if (!devpriv->ai_neverending) { + /* all data sampled? */ + if (devpriv->ai_act_scan >= devpriv->ai_scans) s->async->events |= COMEDI_CB_EOA; - } + } if (devpriv->dma_doublebuf) { /* switch dma buffers */ devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; @@ -1066,7 +1065,7 @@ 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) @@ -1936,28 +1935,6 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, return NULL; } -static void pci9118_report_attach(struct comedi_device *dev, unsigned int irq) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct pci9118_private *devpriv = dev->private; - char irqbuf[30]; - char muxbuf[30]; - - if (irq) - snprintf(irqbuf, sizeof(irqbuf), "irq %u%s", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - snprintf(irqbuf, sizeof(irqbuf), "irq DISABLED"); - if (devpriv->usemux) - snprintf(muxbuf, sizeof(muxbuf), "ext mux %u chans", - devpriv->usemux); - else - snprintf(muxbuf, sizeof(muxbuf), "no ext mux"); - dev_info(dev->class_dev, "%s (pci %s, %s, %sbus master, %s) attached\n", - dev->board_name, pci_name(pcidev), irqbuf, - (devpriv->master ? "" : "no "), muxbuf); -} - static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, int master, int ext_mux, int softsshdelay, int hw_err_mask) @@ -2113,7 +2090,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, break; } - pci9118_report_attach(dev, dev->irq); return 0; } diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 3190ef7d285e..b4ea37704eaf 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -94,8 +94,6 @@ If you do not specify any options, they will default to /* mask of the bit at STINR to check end of conversion */ #define ADQ12B_EOC 0x20 -#define TIMEOUT 20 - /* available ranges through the PGA gains */ static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, { @@ -122,19 +120,28 @@ struct adq12b_private { int last_range; }; -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int adq12b_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + ADQ12B_STINR); + if (status & ADQ12B_EOC) + return 0; + return -EBUSY; +} static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct adq12b_private *devpriv = dev->private; - int n, i; + int n; int range, channel; unsigned char hi, lo, status; + int ret; /* change channel and range only if it is different from the previous */ range = CR_RANGE(insn->chanspec); @@ -151,13 +158,9 @@ static int adq12b_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* wait for end of conversion */ - i = 0; - do { - /* udelay(1); */ - status = inb(dev->iobase + ADQ12B_STINR); - status = status & ADQ12B_EOC; - } while (status == 0 && ++i < TIMEOUT); - /* } while (++i < 10); */ + ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0); + if (ret) + return ret; /* read data */ hi = inb(dev->iobase + ADQ12B_ADHIG); diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 593676cf706a..28ec48548317 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -429,15 +429,26 @@ static void setup_channel_list(struct comedi_device *dev, outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); } -/* -============================================================================== -*/ +static int pci171x_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI171x_STATUS); + if ((status & Status_FE) == 0) + return 0; + return -EBUSY; +} + static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; - int n, timeout; + int ret; + int n; #ifdef PCI171x_PARANOIDCHECK const struct boardtype *this_board = comedi_board(dev); unsigned int idata; @@ -453,19 +464,14 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ - /* udelay(1); */ - timeout = 100; - while (timeout--) { - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE)) - goto conv_finish; + + ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); + if (ret) { + outb(0, dev->iobase + PCI171x_CLRFIFO); + outb(0, dev->iobase + PCI171x_CLRINT); + return ret; } - comedi_error(dev, "A/D insn timeout"); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - data[n] = 0; - return -ETIME; -conv_finish: #ifdef PCI171x_PARANOIDCHECK idata = inw(dev->iobase + PCI171x_AD_DATA); if (this_board->cardtype != TYPE_PCI1713) @@ -494,6 +500,7 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, chan, range, ofs; chan = CR_CHAN(insn->chanspec); @@ -509,11 +516,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; @@ -679,6 +689,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, rangereg, chan; chan = CR_CHAN(insn->chanspec); @@ -688,13 +699,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; } @@ -746,17 +759,15 @@ static void interrupt_pci1710_every_sample(void *d) m = inw(dev->iobase + PCI171x_STATUS); if (m & Status_FE) { dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (m & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } @@ -775,10 +786,9 @@ static void interrupt_pci1710_every_sample(void *d) 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); + cfc_handle_events(dev, s); return; } comedi_buf_put(s->async, sampl & 0x0fff); @@ -797,9 +807,8 @@ static void interrupt_pci1710_every_sample(void *d) if ((!devpriv->neverending_ai) && (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); + cfc_handle_events(dev, s); return; } } @@ -807,7 +816,7 @@ static void interrupt_pci1710_every_sample(void *d) outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -835,10 +844,9 @@ static int move_block_from_fifo(struct comedi_device *dev, (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); + cfc_handle_events(dev, s); return 1; } comedi_buf_put(s->async, sampl & 0x0fff); @@ -870,17 +878,15 @@ static void interrupt_pci1710_half_fifo(void *d) m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (m & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } @@ -900,14 +906,13 @@ static void interrupt_pci1710_half_fifo(void *d) 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); + cfc_handle_events(dev, s); return; } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -1347,9 +1352,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, subdev++; } - dev_info(dev->class_dev, "%s attached, irq %sabled\n", - dev->board_name, dev->irq ? "en" : "dis"); - return 0; } diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 72394267ddfe..07b107d1ab33 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -280,8 +280,6 @@ static int pci1723_auto_attach(struct comedi_device *dev, pci1723_reset(dev); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index d4bd61d84daf..2d966a87f2e8 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -1130,10 +1130,12 @@ static int pci_dio_auto_attach(struct comedi_device *dev, for (i = 0; i < MAX_DIO_SUBDEVG; i++) for (j = 0; j < this_board->sdio[i].regs; j++) { s = &dev->subdevices[subdev]; - subdev_8255_init(dev, s, NULL, - dev->iobase + - this_board->sdio[i].addr + - SIZE_8255 * j); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + + this_board->sdio[i].addr + + SIZE_8255 * j); + if (ret) + return ret; subdev++; } diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index 68c3fb3226ca..324746b14931 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -101,14 +101,27 @@ struct aio12_8_private { unsigned int ao_readback[4]; }; +static int aio_aio12_8_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + AIO12_8_STATUS_REG); + if (status & AIO12_8_STATUS_ADC_EOC) + return 0; + return -EBUSY; +} + static int aio_aio12_8_ai_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val; unsigned char control; + int ret; int n; /* @@ -122,20 +135,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, inb(dev->iobase + AIO12_8_STATUS_REG); for (n = 0; n < insn->n; n++) { - int timeout = 5; - /* Setup and start conversion */ outb(control, dev->iobase + AIO12_8_ADC_REG); /* Wait for conversion to complete */ - do { - val = inb(dev->iobase + AIO12_8_STATUS_REG); - timeout--; - if (timeout == 0) { - dev_err(dev->class_dev, "ADC timeout\n"); - return -ETIMEDOUT; - } - } while (!(val & AIO12_8_STATUS_ADC_EOC)); + ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0); + if (ret) + return ret; data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; } @@ -247,9 +253,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev, /* 8254 counter/timer subdevice */ s->type = COMEDI_SUBD_UNUSED; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 22b3dda135ff..781104aa533e 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -98,7 +98,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = aio_iiro_16_dio_insn_bits_read; - return 1; + return 0; } static struct comedi_driver aio_iiro_16_driver = { diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index 9c9559ffc643..818a0d7e3d58 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -1208,7 +1208,7 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq, "warning! irq %u unavailable!\n", irq); } } - dev_info(dev->class_dev, "attached\n"); + return 0; } EXPORT_SYMBOL_GPL(amplc_dio200_common_attach); diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 31734e1142fd..b21d7b48f1da 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -368,32 +368,6 @@ static irqreturn_t pc236_interrupt(int irq, void *d) return IRQ_RETVAL(handled); } -static void pc236_report_attach(struct comedi_device *dev, unsigned int irq) -{ - const struct pc236_board *thisboard = comedi_board(dev); - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - char tmpbuf[60]; - int tmplen; - - if (is_isa_board(thisboard)) - tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), - "(base %#lx) ", dev->iobase); - else if (is_pci_board(thisboard)) - tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), - "(pci %s) ", pci_name(pcidev)); - else - tmplen = 0; - if (irq) - tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen, - "(irq %u%s) ", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen, - "(no irq) "); - dev_info(dev->class_dev, "%s %sattached\n", - dev->board_name, tmpbuf); -} - static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, unsigned int irq, unsigned long req_irq_flags) { @@ -411,10 +385,9 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s = &dev->subdevices[0]; /* digital i/o subdevice (8255) */ ret = subdev_8255_init(dev, s, NULL, iobase); - if (ret < 0) { - dev_err(dev->class_dev, "error! out of memory!\n"); + if (ret) return ret; - } + s = &dev->subdevices[1]; dev->read_subdev = s; s->type = COMEDI_SUBD_UNUSED; @@ -434,8 +407,8 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s->cancel = pc236_intr_cancel; } } - pc236_report_attach(dev, irq); - return 1; + + return 0; } static int pc236_pci_common_attach(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 5b4b5ab34e2e..7c10d28d2784 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -94,8 +94,6 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (base %#lx) attached\n", dev->board_name, - dev->iobase); return 0; } diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index ae4048a624fa..29e01e280039 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -533,9 +533,8 @@ static void pci224_ao_start(struct comedi_device *dev, set_bit(AO_CMD_STARTED, &devpriv->state); if (!devpriv->ao_stop_continuous && 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); @@ -585,9 +584,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, room = PCI224_FIFO_ROOM_EMPTY; if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { /* FIFO empty at end of counted acquisition. */ - pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } break; @@ -605,9 +603,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, /* FIFO is less than half-full. */ if (num_scans == 0) { /* Nothing left to put in the FIFO. */ - pci224_ao_stop(dev, s); - s->async->events |= COMEDI_CB_OVERFLOW; dev_err(dev->class_dev, "AO buffer underrun\n"); + s->async->events |= COMEDI_CB_OVERFLOW; } } /* Determine how many new scans can be put in the FIFO. */ @@ -670,9 +667,8 @@ 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); } /* @@ -1237,20 +1233,6 @@ static struct pci_dev *pci224_find_pci_dev(struct comedi_device *dev, return NULL; } -static void pci224_report_attach(struct comedi_device *dev, unsigned int irq) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - char tmpbuf[30]; - - if (irq) - snprintf(tmpbuf, sizeof(tmpbuf), "irq %u%s", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - snprintf(tmpbuf, sizeof(tmpbuf), "no irq"); - dev_info(dev->class_dev, "%s (pci %s) (%s) attached\n", - dev->board_name, pci_name(pcidev), tmpbuf); -} - /* * Common part of attach and auto_attach. */ @@ -1399,8 +1381,7 @@ static int pci224_attach_common(struct comedi_device *dev, } } - pci224_report_attach(dev, irq); - return 1; + return 0; } static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index c08dfbbe4062..99e60835dc4a 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -799,19 +799,29 @@ static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct) /* Counter ct, 8254 mode 1, initial count not written. */ } -/* - * COMEDI_SUBD_AI instruction; - */ +static int pci230_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI230_ADCCON); + if ((status & PCI230_ADC_FIFO_EMPTY) == 0) + return 0; + return -EBUSY; +} + static int pci230_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci230_private *devpriv = dev->private; - unsigned int n, i; + unsigned int n; unsigned int chan, range, aref; unsigned int gainshift; - unsigned int status; unsigned short adccon, adcen; + int ret; /* Unpack channel and range. */ chan = CR_CHAN(insn->chanspec); @@ -883,18 +893,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev, i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + PCI230_ADCCON); - if (!(status & PCI230_ADC_FIFO_EMPTY)) - break; - udelay(1); - } - if (i == TIMEOUT) { - dev_err(dev->class_dev, "timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = pci230_ai_read(dev); @@ -2762,14 +2764,14 @@ static int pci230_attach_common(struct comedi_device *dev, /* digital i/o subdevice */ if (thisboard->have_dio) { rc = subdev_8255_init(dev, s, NULL, - (devpriv->iobase1 + PCI230_PPI_X_BASE)); - if (rc < 0) + devpriv->iobase1 + PCI230_PPI_X_BASE); + if (rc) return rc; } else { s->type = COMEDI_SUBD_UNUSED; } - dev_info(dev->class_dev, "attached\n"); - return 1; + + return 0; } static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index be28e6cbea20..93ed03ee416a 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -84,8 +84,6 @@ static int pci263_auto_attach(struct comedi_device *dev, /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (pci %s) attached\n", dev->board_name, - pci_name(pci_dev)); return 0; } diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index 5034f663eec9..e03dd6e71415 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -1,34 +1,33 @@ /* - comedi/drivers/c6xdigio.c - - Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. - (http://robot0.ge.uiuc.edu/~spong/mecha/) - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Dan Block - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * c6xdigio.c + * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. + * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/ + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Dan Block + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: c6xdigio -Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card -Author: Dan Block -Status: unknown -Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio) -Updated: Sun Nov 20 20:18:34 EST 2005 - -This driver will not work with a 2.4 kernel. -http://robot0.ge.uiuc.edu/~spong/mecha/ -*/ +/* + * Driver: c6xdigio + * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card + * Author: Dan Block + * Status: unknown + * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio] + * Updated: Sun Nov 20 20:18:34 EST 2005 + * + * Configuration Options: + * [0] - base address + */ #include <linux/kernel.h> #include <linux/module.h> @@ -43,309 +42,194 @@ http://robot0.ge.uiuc.edu/~spong/mecha/ #include "../comedidev.h" -static u8 ReadByteFromHwPort(unsigned long addr) -{ - u8 result = inb(addr); - return result; -} - -static void WriteByteToHwPort(unsigned long addr, u8 val) -{ - outb_p(val, addr); -} - -#define C6XDIGIO_SIZE 3 - /* - * port offsets + * Register I/O map */ -#define C6XDIGIO_PARALLEL_DATA 0 -#define C6XDIGIO_PARALLEL_STATUS 1 -#define C6XDIGIO_PARALLEL_CONTROL 2 -struct pwmbitstype { - unsigned sb0:2; - unsigned sb1:2; - unsigned sb2:2; - unsigned sb3:2; - unsigned sb4:2; -}; -union pwmcmdtype { - unsigned cmd; /* assuming here that int is 32bit */ - struct pwmbitstype bits; -}; -struct encbitstype { - unsigned sb0:3; - unsigned sb1:3; - unsigned sb2:3; - unsigned sb3:3; - unsigned sb4:3; - unsigned sb5:3; - unsigned sb6:3; - unsigned sb7:3; -}; -union encvaluetype { - unsigned value; - struct encbitstype bits; -}; +#define C6XDIGIO_DATA_REG 0x00 +#define C6XDIGIO_DATA_CHAN(x) (((x) + 1) << 4) +#define C6XDIGIO_DATA_PWM (1 << 5) +#define C6XDIGIO_DATA_ENCODER (1 << 6) +#define C6XDIGIO_STATUS_REG 0x01 +#define C6XDIGIO_CTRL_REG 0x02 #define C6XDIGIO_TIME_OUT 20 -static void C6X_pwmInit(unsigned long baseAddr) +static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context) { + unsigned int status; int timeout = 0; - WriteByteToHwPort(baseAddr, 0x70); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { + do { + status = inb(dev->iobase + C6XDIGIO_STATUS_REG); + if ((status & 0x80) != context) + return 0; timeout++; - } + } while (timeout < C6XDIGIO_TIME_OUT); - WriteByteToHwPort(baseAddr, 0x74); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } + return -EBUSY; +} - WriteByteToHwPort(baseAddr, 0x70); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } +static int c6xdigio_write_data(struct comedi_device *dev, + unsigned int val, unsigned int status) +{ + outb_p(val, dev->iobase + C6XDIGIO_DATA_REG); + return c6xdigio_chk_status(dev, status); +} - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } +static int c6xdigio_get_encoder_bits(struct comedi_device *dev, + unsigned int *bits, + unsigned int cmd, + unsigned int status) +{ + unsigned int val; + + val = inb(dev->iobase + C6XDIGIO_STATUS_REG); + val >>= 3; + val &= 0x07; + + *bits = val; + return c6xdigio_write_data(dev, cmd, status); } -static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value) +static void c6xdigio_pwm_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) { - unsigned ppcmd; - union pwmcmdtype pwm; - int timeout = 0; - unsigned tmp; - - pwm.cmd = value; - if (pwm.cmd > 498) - pwm.cmd = 498; - if (pwm.cmd < 2) - pwm.cmd = 2; - - if (channel == 0) { - ppcmd = 0x28; - } else { /* if channel == 1 */ - ppcmd = 0x30; - } /* endif */ - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan); + unsigned int bits; + + if (val > 498) + val = 498; + if (val < 2) + val = 2; + + bits = (val >> 0) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 2) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 4) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 6) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 8) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + + c6xdigio_write_data(dev, 0x00, 0x80); +} - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } +static int c6xdigio_encoder_read(struct comedi_device *dev, + unsigned int chan) +{ + unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan); + unsigned int val = 0; + unsigned int bits; - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_write_data(dev, cmd, 0x00); - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 0); - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 3); - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 6); -} + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 9); -static int C6X_encInput(unsigned long baseAddr, unsigned channel) -{ - unsigned ppcmd; - union encvaluetype enc; - int timeout = 0; - int tmp; - - enc.value = 0; - if (channel == 0) - ppcmd = 0x48; - else - ppcmd = 0x50; - - WriteByteToHwPort(baseAddr, ppcmd); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 12); - enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 15); - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 18); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 21); + + c6xdigio_write_data(dev, 0x00, 0x80); - return enc.value ^ 0x800000; + return val; } -static void C6X_encResetAll(unsigned long baseAddr) +static int c6xdigio_pwm_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned timeout = 0; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = (s->state >> (16 * chan)) & 0xffff; + int i; - WriteByteToHwPort(baseAddr, 0x68); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x6C); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x68); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; + for (i = 0; i < insn->n; i++) { + val = data[i]; + c6xdigio_pwm_write(dev, chan, val); } + + /* + * There are only 2 PWM channels and they have a maxdata of 500. + * Instead of allocating private data to save the values in for + * readback this driver just packs the values for the two channels + * in the s->state. + */ + s->state &= (0xffff << (16 * chan)); + s->state |= (val << (16 * chan)); + + return insn->n; } -static int c6xdigio_pwmo_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int c6xdigio_pwm_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; int i; - int chan = CR_CHAN(insn->chanspec); - for (i = 0; i < insn->n; i++) { - C6X_pwmOutput(dev->iobase, chan, data[i]); - /* devpriv->ao_readback[chan] = data[i]; */ - } - return i; + val = (s->state >> (16 * chan)) & 0xffff; + + for (i = 0; i < insn->n; i++) + data[i] = val; + + return insn->n; } -static int c6xdigio_ei_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int c6xdigio_encoder_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - for (n = 0; n < insn->n; n++) - data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff); + for (i = 0; i < insn->n; i++) { + val = c6xdigio_encoder_read(dev, chan); + + /* munge two's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); + } - return n; + return insn->n; } -static void board_init(struct comedi_device *dev) +static void c6xdigio_init(struct comedi_device *dev) { - C6X_pwmInit(dev->iobase); - C6X_encResetAll(dev->iobase); + /* Initialize the PWM */ + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x74, 0x80); + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); + + /* Reset the encoders */ + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x6c, 0x80); + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); } static const struct pnp_device_id c6xdigio_pnp_tbl[] = { @@ -367,7 +251,7 @@ static int c6xdigio_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], C6XDIGIO_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x03); if (ret) return ret; @@ -380,27 +264,26 @@ static int c6xdigio_attach(struct comedi_device *dev, s = &dev->subdevices[0]; /* pwm output subdevice */ - s->type = COMEDI_SUBD_AO; /* Not sure what to put here */ - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_pwmo; */ - s->insn_write = c6xdigio_pwmo_insn_write; - s->maxdata = 500; - s->range_table = &range_bipolar10; /* A suitable lie */ + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 500; + s->range_table = &range_unknown; + s->insn_write = c6xdigio_pwm_insn_write; + s->insn_read = c6xdigio_pwm_insn_read; s = &dev->subdevices[1]; /* encoder (counter) subdevice */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_ei; */ - s->insn_read = c6xdigio_ei_insn_read; - s->maxdata = 0xffffff; - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = 2; + s->maxdata = 0xffffff; + s->range_table = &range_unknown; + s->insn_read = c6xdigio_encoder_insn_read; /* I will call this init anyway but more than likely the DSP board */ /* will not be connected when device driver is loaded. */ - board_init(dev); + c6xdigio_init(dev); return 0; } @@ -420,5 +303,5 @@ static struct comedi_driver c6xdigio_driver = { module_comedi_driver(c6xdigio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 64d5f291553f..645fcb0cf17d 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -95,10 +95,17 @@ static const struct comedi_lrange das16cs_ai_range = { } }; -static irqreturn_t das16cs_interrupt(int irq, void *d) +static int das16cs_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - /* struct comedi_device *dev = d; */ - return IRQ_HANDLED; + unsigned int status; + + status = inw(dev->iobase + DAS16CS_MISC1); + if (status & 0x0080) + return 0; + return -EBUSY; } static int das16cs_ai_rinsn(struct comedi_device *dev, @@ -109,8 +116,8 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); + int ret; int i; - int to; outw(chan, dev->iobase + DAS16CS_DIO_MUX); @@ -138,132 +145,16 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outw(0, dev->iobase + DAS16CS_ADC_DATA); -#define TIMEOUT 1000 - for (to = 0; to < TIMEOUT; to++) { - if (inw(dev->iobase + DAS16CS_MISC1) & 0x0080) - break; - } - if (to == TIMEOUT) { - dev_dbg(dev->class_dev, "cb_das16_cs: ai timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0); + if (ret) + return ret; + data[i] = inw(dev->iobase + DAS16CS_ADC_DATA); } return i; } -static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - return -EINVAL; -} - -static int das16cs_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int tmp; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - -#define MAX_SPEED 10000 /* in nanoseconds */ -#define MIN_SPEED 1000000000 /* in nanoseconds */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); - } - if (cmd->convert_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* see above */ - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); - } - - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - if (cmd->stop_src == TRIG_COUNT) - err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); - else /* TRIG_NONE */ - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } - - if (err) - return 4; - - return 0; -} - static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -401,10 +292,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, dev->iobase = link->resource[0]->start; link->priv = dev; - ret = pcmcia_request_irq(link, das16cs_interrupt); - if (ret) - return ret; - dev->irq = link->irq; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -415,7 +302,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; @@ -424,8 +310,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->range_table = &das16cs_ai_range; s->len_chanlist = 16; s->insn_read = das16cs_ai_rinsn; - s->do_cmd = das16cs_ai_cmd; - s->do_cmdtest = das16cs_ai_cmdtest; s = &dev->subdevices[1]; /* analog output subdevice */ @@ -451,10 +335,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->insn_bits = das16cs_dio_insn_bits; s->insn_config = das16cs_dio_insn_config; - dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx, irq=%u\n", - dev->driver->driver_name, dev->board_name, - dev->iobase, dev->irq); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 9819be092f8d..83a265f3408c 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -376,6 +376,20 @@ static inline unsigned int cal_enable_bits(struct comedi_device *dev) return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); } +static int cb_pcidas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned int status; + + status = inw(devpriv->control_status + ADCMUX_CONT); + if (status & EOC) + return 0; + return -EBUSY; +} + static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -385,7 +399,8 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned int bits; - int n, i; + int ret; + int n; /* enable calibration input if appropriate */ if (insn->chanspec & CR_ALT_SOURCE) { @@ -415,13 +430,9 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, outw(0, devpriv->adc_fifo + ADCDATA); /* wait for conversion to end */ - /* return -ETIMEDOUT if there is a timeout */ - for (i = 0; i < 10000; i++) { - if (inw(devpriv->control_status + ADCMUX_CONT) & EOC) - break; - } - if (i == 10000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(devpriv->adc_fifo + ADCDATA); @@ -1006,9 +1017,9 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, /* set start trigger and burst mode */ bits = 0; - if (cmd->start_src == TRIG_NOW) + if (cmd->start_src == TRIG_NOW) { bits |= SW_TRIGGER; - else if (cmd->start_src == TRIG_EXT) { + } else { /* TRIG_EXT */ bits |= EXT_TRIGGER | TGEN | XTRCL; if (thisboard->is_1602) { if (cmd->start_arg & CR_INVERT) @@ -1016,9 +1027,6 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, if (cmd->start_arg & CR_EDGE) bits |= TGSEL; } - } else { - comedi_error(dev, "bug!"); - return -1; } if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) bits |= BURSTE; @@ -1269,8 +1277,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) unsigned int num_points; unsigned long flags; - async->events = 0; - if (status & DAEMI) { /* clear dac empty interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); @@ -1282,7 +1288,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) (cmd->stop_src == TRIG_COUNT && devpriv->ao_count)) { comedi_error(dev, "dac fifo underflow"); - cb_pcidas_ao_cancel(dev, s); async->events |= COMEDI_CB_ERROR; } async->events |= COMEDI_CB_EOA; @@ -1312,7 +1317,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) spin_unlock_irqrestore(&dev->spinlock, flags); } - comedi_event(dev, s); + cfc_handle_events(dev, s); } static irqreturn_t cb_pcidas_interrupt(int irq, void *d) @@ -1332,7 +1337,6 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) return IRQ_NONE; async = s->async; - async->events = 0; s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); @@ -1364,10 +1368,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 (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) async->events |= COMEDI_CB_EOA; - cb_pcidas_cancel(dev, s); - } /* clear half-full interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | INT, @@ -1384,7 +1386,6 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) if (async->cmd.stop_src == TRIG_COUNT && --devpriv->count == 0) { /* end of acquisition */ - cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -1411,11 +1412,10 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) outw(devpriv->adc_fifo_bits | LADFUL, devpriv->control_status + INT_ADCFIFO); spin_unlock_irqrestore(&dev->spinlock, flags); - cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -1576,9 +1576,6 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 4fff1738e3f8..f9afcbe1da54 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1664,15 +1664,36 @@ static void i2c_write(struct comedi_device *dev, unsigned int address, i2c_stop(dev); } +static int cb_pcidas64_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->main_iobase + HW_STATUS_REG); + if (thisboard->layout == LAYOUT_4020) { + status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG); + if (status) + return 0; + } else { + if (pipe_full_bits(status)) + return 0; + } + return -EBUSY; +} + static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct pcidas64_board *thisboard = comedi_board(dev); struct pcidas64_private *devpriv = dev->private; - unsigned int bits = 0, n, i; + unsigned int bits = 0, n; unsigned int channel, range, aref; unsigned long flags; - static const int timeout = 100; + int ret; channel = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -1770,23 +1791,10 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->main_iobase + ADC_CONVERT_REG); /* wait for data */ - for (i = 0; i < timeout; i++) { - bits = readw(devpriv->main_iobase + HW_STATUS_REG); - if (thisboard->layout == LAYOUT_4020) { - if (readw(devpriv->main_iobase + - ADC_WRITE_PNTR_REG)) - break; - } else { - if (pipe_full_bits(bits)) - break; - } - udelay(1); - } - if (i == timeout) { - comedi_error(dev, " analog input read insn timed out"); - dev_info(dev->class_dev, "status 0x%x\n", bits); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0); + if (ret) + return ret; + if (thisboard->layout == LAYOUT_4020) data[n] = readl(devpriv->dio_counter_iobase + ADC_FIFO_REG) & 0xffff; @@ -3816,16 +3824,19 @@ static int setup_subdevices(struct comedi_device *dev) if (thisboard->has_8255) { if (thisboard->layout == LAYOUT_4020) { dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG; - subdev_8255_init(dev, s, dio_callback_4020, - (unsigned long)dio_8255_iobase); + ret = subdev_8255_init(dev, s, dio_callback_4020, + (unsigned long)dio_8255_iobase); } else { dio_8255_iobase = devpriv->dio_counter_iobase + DIO_8255_OFFSET; - subdev_8255_init(dev, s, dio_callback, - (unsigned long)dio_8255_iobase); + ret = subdev_8255_init(dev, s, dio_callback, + (unsigned long)dio_8255_iobase); } - } else + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* 8 channel dio for 60xx */ s = &dev->subdevices[5]; diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 8cca0518cfda..901dc5d1bb72 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -388,8 +388,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, for (i = 0; i < thisboard->ao_chans; i++) cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index 57295d189ff6..d3141c865fe7 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -85,21 +85,31 @@ struct cb_pcimdas_private { unsigned int ao_readback[2]; }; -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int cb_pcimdas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct cb_pcimdas_private *devpriv = dev->private; + unsigned int status; + + status = inb(devpriv->BADR3 + 2); + if ((status & 0x80) == 0) + return 0; + return -EBUSY; +} + static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct cb_pcimdas_private *devpriv = dev->private; - int n, i; + int n; unsigned int d; - unsigned int busy; int chan = CR_CHAN(insn->chanspec); unsigned short chanlims; int maxchans; + int ret; /* only support sw initiated reads from a single channel */ @@ -133,17 +143,10 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outw(0, dev->iobase + 0); -#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */ - /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */ - /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - busy = inb(devpriv->BADR3 + 2) & 0x80; - if (!busy) - break; - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(dev->iobase + 0); @@ -247,9 +250,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, s = &dev->subdevices[2]; /* digital i/o subdevice */ - subdev_8255_init(dev, s, NULL, iobase_8255); - - dev_info(dev->class_dev, "%s attached\n", dev->board_name); + ret = subdev_8255_init(dev, s, NULL, iobase_8255); + if (ret) + return ret; return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 43a86630a66e..4a2b200de01b 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -187,9 +187,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, if (ret) return ret; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - - return 1; + return 0; } static struct comedi_driver cb_pcimdda_driver = { diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 51a59e5b8ec5..8450c99af8b0 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -211,7 +211,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) return -EINVAL; } - snprintf(file, sizeof(file), "/dev/comedi%u", minor); + snprintf(file, sizeof(file), "/dev/comedi%d", minor); file[sizeof(file) - 1] = 0; d = comedi_open(file); @@ -254,6 +254,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) if (!devs) { dev_err(dev->class_dev, "Could not allocate memory. Out of memory?\n"); + kfree(bdev); return -ENOMEM; } devpriv->devs = devs; @@ -263,7 +264,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) char buf[20]; int left = MAX_BOARD_NAME - strlen(devpriv->name) - 1; - snprintf(buf, sizeof(buf), "%d:%d ", + snprintf(buf, sizeof(buf), "%u:%u ", bdev->minor, bdev->subdev); buf[sizeof(buf) - 1] = 0; strncat(devpriv->name, buf, left); diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c index 26d9dbcf8bd4..9d9b1469e89a 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ b/drivers/staging/comedi/drivers/comedi_fc.c @@ -1,34 +1,53 @@ /* - comedi/drivers/comedi_fc.c - - This is a place for code driver writers wish to share between - two or more drivers. fc is short - for frank-common. - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi_fc.c + * This is a place for code driver writers wish to share between + * two or more drivers. fc is short for frank-common. + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #include <linux/module.h> #include "../comedidev.h" #include "comedi_fc.h" -static void increment_scan_progress(struct comedi_subdevice *subd, - unsigned int num_bytes) +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) +{ + unsigned int chanlist_len = s->async->cmd.chanlist_len; + 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 = (chanlist_len + bits_per_sample - 1) / + bits_per_sample; + break; + default: + num_samples = 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) { @@ -36,12 +55,13 @@ 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) @@ -49,24 +69,24 @@ unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, retval = comedi_buf_write_alloc(async, num_bytes); if (retval != num_bytes) { - dev_warn(subd->device->class_dev, "comedi: buffer overrun\n"); + dev_warn(s->device->class_dev, "buffer overrun\n"); async->events |= COMEDI_CB_OVERFLOW; return 0; } comedi_buf_memcpy_to(async, 0, data, num_bytes); comedi_buf_write_free(async, num_bytes); - increment_scan_progress(subd, num_bytes); + cfc_inc_scan_progress(s, num_bytes); async->events |= COMEDI_CB_BLOCK; return num_bytes; } EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer); -unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *s, void *data, unsigned int num_bytes) { - struct comedi_async *async = subd->async; + struct comedi_async *async = s->async; if (num_bytes == 0) return 0; @@ -74,7 +94,7 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, 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); + cfc_inc_scan_progress(s, num_bytes); async->events |= COMEDI_CB_BLOCK; return num_bytes; @@ -82,34 +102,33 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer); unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd) + struct comedi_subdevice *s) { - unsigned int events = subd->async->events; + unsigned int events = s->async->events; if (events == 0) return events; if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) - subd->cancel(dev, subd); + s->cancel(dev, s); - comedi_event(dev, subd); + comedi_event(dev, s); return events; } EXPORT_SYMBOL_GPL(cfc_handle_events); -MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); -MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); -MODULE_LICENSE("GPL"); - static int __init comedi_fc_init_module(void) { return 0; } +module_init(comedi_fc_init_module); static void __exit comedi_fc_cleanup_module(void) { } - -module_init(comedi_fc_init_module); module_exit(comedi_fc_cleanup_module); + +MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); +MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index 8558b07f8df3..541b9371d3da 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -1,72 +1,52 @@ /* - comedi_fc.h - - This is a place for code driver writers wish to share between - two or more drivers. These functions are meant to be used only - by drivers, they are NOT part of the kcomedilib API! - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi_fc.h + * This is a place for code driver writers wish to share between + * two or more drivers. These functions are meant to be used only + * by drivers, they are NOT part of the kcomedilib API! + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #ifndef _COMEDI_FC_H #define _COMEDI_FC_H #include "../comedidev.h" +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *); +void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes); + /* Writes an array of data points to comedi's buffer */ -extern unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); -static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *subd, +static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s, unsigned short data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice - *subd, unsigned int data) +static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s, + unsigned int data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -extern unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); -extern unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd); - -static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *subd) -{ - int num_samples; - int bits_per_sample; - - switch (subd->type) { - case COMEDI_SUBD_DI: - case COMEDI_SUBD_DO: - case COMEDI_SUBD_DIO: - bits_per_sample = 8 * bytes_per_sample(subd); - num_samples = (subd->async->cmd.chanlist_len + - bits_per_sample - 1) / bits_per_sample; - break; - default: - num_samples = subd->async->cmd.chanlist_len; - break; - } - return num_samples * bytes_per_sample(subd); -} +unsigned int cfc_handle_events(struct comedi_device *, + struct comedi_subdevice *); /** * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index d539eaf53b63..cd9562556d2c 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -185,7 +185,6 @@ 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; @@ -318,12 +317,8 @@ static int waveform_ai_cmd(struct comedi_device *dev, if (cmd->convert_src == TRIG_NOW) devpriv->convert_period = 0; - else if (cmd->convert_src == TRIG_TIMER) + else /* TRIG_TIMER */ devpriv->convert_period = cmd->convert_arg / nano_per_micro; - else { - comedi_error(dev, "bug setting conversion period"); - return -1; - } do_gettimeofday(&devpriv->last); devpriv->usec_current = devpriv->last.tv_usec % devpriv->usec_period; diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 323a7f39cd97..0a9c32e9db4a 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -92,8 +92,6 @@ static int contec_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = contec_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c new file mode 100644 index 000000000000..df46e0a5bade --- /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 ce153fcb8b2a..a8f6036ad82b 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -333,14 +333,28 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) writeAcqScanListEntry(dev, word3); } +static int daqboard2000_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->daq + acqControl); + if (status & context) + return 0; + return -EBUSY; +} + static int daqboard2000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct daqboard2000_private *devpriv = dev->private; - unsigned int val; - int gain, chan, timeout; + int gain, chan; + int ret; int i; writew(DAQBOARD2000_AcqResetScanListFifo | @@ -367,25 +381,24 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, /* Enable reading from the scanlist FIFO */ writew(DAQBOARD2000_SeqStartScanList, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqConfigPipeFull) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqConfigPipeFull); + if (ret) + return ret; + writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqLogicScanning) - break; - /* udelay(2); */ - } - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqResultsFIFOHasValidData) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqLogicScanning); + if (ret) + return ret; + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqResultsFIFOHasValidData); + if (ret) + return ret; + data[i] = readw(devpriv->daq + acqResultsFIFO); writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); @@ -409,6 +422,21 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev, return i; } +static int daqboard2000_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int status; + + status = readw(devpriv->daq + dacControl); + if ((status & ((chan + 1) * 0x0010)) == 0) + return 0; + return -EBUSY; +} + static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -416,8 +444,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, { struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); - unsigned int val; - int timeout; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -431,12 +458,11 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, udelay(1000); #endif writew(data[i], devpriv->daq + dacSetting(chan)); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + dacControl); - if ((val & ((chan + 1) * 0x0010)) == 0) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; #if 0 /* @@ -737,9 +763,6 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, if (result) return result; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index e5c0ee9a09c2..c5e352fb5555 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -201,17 +201,29 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; -#define TIMEOUT 100000 +static int das08_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS08_STATUS); + if ((status & DAS08_EOC) == 0) + return 0; + return -EBUSY; +} static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das08_board_struct *thisboard = comedi_board(dev); struct das08_private_struct *devpriv = dev->private; - int i, n; + int n; int chan; int range; int lsb, msb; + int ret; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -244,14 +256,10 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); - for (i = 0; i < TIMEOUT; i++) { - if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC)) - break; - } - if (i == TIMEOUT) { - dev_err(dev->class_dev, "timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0); + if (ret) + return ret; + msb = inb(dev->iobase + DAS08_MSB); lsb = inb(dev->iobase + DAS08_LSB); if (thisboard->ai_encoding == das08_encode12) { @@ -529,9 +537,10 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s = &dev->subdevices[4]; /* 8255 */ if (thisboard->i8255_offset != 0) { - subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase + - thisboard-> - i8255_offset)); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + thisboard->i8255_offset); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index a8446ca04110..6a7d652ff564 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -856,18 +856,17 @@ static void das16_ai_munge(struct comedi_device *dev, } } -static int das16_ai_wait_for_conv(struct comedi_device *dev, - unsigned int timeout) +static int das16_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; - int i; - for (i = 0; i < timeout; i++) { - status = inb(dev->iobase + DAS16_STATUS_REG); - if (!(status & DAS16_STATUS_BUSY)) - return 0; - } - return -ETIME; + status = inb(dev->iobase + DAS16_STATUS_REG); + if ((status & DAS16_STATUS_BUSY) == 0) + return 0; + return -EBUSY; } static int das16_ai_insn_read(struct comedi_device *dev, @@ -897,7 +896,7 @@ static int das16_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ outb_p(0, dev->iobase + DAS16_TRIG_REG); - ret = das16_ai_wait_for_conv(dev, 1000); + ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index fee5facff8dd..779225831dc0 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -331,14 +331,27 @@ static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int das16m1_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS16M1_CS); + if (status & IRQDATA) + return 0; + return -EBUSY; +} + static int das16m1_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct das16m1_private_struct *devpriv = dev->private; - int i, n; + int ret; + int n; int byte; - const int timeout = 1000; /* disable interrupts and internal pacer */ devpriv->control_state &= ~INTE & ~PACER_MASK; @@ -356,14 +369,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outb(0, dev->iobase); - for (i = 0; i < timeout; i++) { - if (inb(dev->iobase + DAS16M1_CS) & IRQDATA) - break; - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0); + if (ret) + return ret; + data[n] = munge_sample(inw(dev->iobase)); } @@ -407,7 +416,6 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) s = dev->read_subdev; async = s->async; - async->events = 0; cmd = &async->cmd; /* figure out how many samples are in fifo */ @@ -440,8 +448,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) devpriv->adc_count += num_samples; if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { /* end of acquisition */ - das16m1_cancel(dev, s); + if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { + /* end of acquisition */ async->events |= COMEDI_CB_EOA; } } @@ -449,13 +457,11 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) /* this probably won't catch overruns since the card doesn't generate * overrun interrupts, but we might as well try */ if (status & OVRUN) { - das16m1_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; comedi_error(dev, "fifo overflow"); } - comedi_event(dev, s); - + cfc_handle_events(dev, s); } static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 320d95a5f47b..8e975d6b06db 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -646,7 +646,6 @@ static void das1800_ai_handler(struct comedi_device *dev) struct comedi_cmd *cmd = &async->cmd; unsigned int status = inb(dev->iobase + DAS1800_STATUS); - async->events = 0; /* select adc for base address + 0 */ outb(ADC, dev->iobase + DAS1800_SELECT); /* dma buffer full */ @@ -665,9 +664,8 @@ static void das1800_ai_handler(struct comedi_device *dev) /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); comedi_error(dev, "DAS1800 FIFO overflow"); - das1800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } /* stop taking data if appropriate */ @@ -680,16 +678,12 @@ static void das1800_ai_handler(struct comedi_device *dev) das1800_flush_dma(dev, s); else das1800_handle_fifo_not_empty(dev, s); - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */ - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - - return; + cfc_handle_events(dev, s); } static int das1800_ai_poll(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 43027ee500e3..e0cfb6cb547b 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -1,309 +1,532 @@ /* - Some comments on the code.. - - - it shouldn't be necessary to use outb_p(). - - - ignoreirq creates a race condition. It needs to be fixed. - + * das6402.c + * Comedi driver for DAS6402 compatible boards + * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Rewrite of an experimental driver by: + * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* - comedi/drivers/das6402.c - An experimental driver for Computerboards' DAS6402 I/O card + * Driver: das6402 + * Description: Keithley Metrabyte DAS6402 (& compatibles) + * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12) + * (Keithley Metrabyte) DAS6402-16 (das6402-16) + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Fri, 14 Mar 2014 10:18:43 -0700 + * Status: unknown + * + * Configuration Options: + * [0] - I/O base address + * [1] - IRQ (optional, needed for async command support) + */ - Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> +#include <linux/module.h> +#include <linux/interrupt.h> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +#include "../comedidev.h" +#include "8253.h" - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - */ /* -Driver: das6402 -Description: Keithley Metrabyte DAS6402 (& compatibles) -Author: Oystein Svendsen <svendsen@pvv.org> -Status: bitrotten -Devices: [Keithley Metrabyte] DAS6402 (das6402) + * Register I/O map + */ +#define DAS6402_AI_DATA_REG 0x00 +#define DAS6402_AI_MUX_REG 0x02 +#define DAS6402_AI_MUX_LO(x) (((x) & 0x3f) << 0) +#define DAS6402_AI_MUX_HI(x) (((x) & 0x3f) << 8) +#define DAS6402_DI_DO_REG 0x03 +#define DAS6402_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define DAS6402_STATUS_REG 0x08 +#define DAS6402_STATUS_FFNE (1 << 0) +#define DAS6402_STATUS_FHALF (1 << 1) +#define DAS6402_STATUS_FFULL (1 << 2) +#define DAS6402_STATUS_XINT (1 << 3) +#define DAS6402_STATUS_INT (1 << 4) +#define DAS6402_STATUS_XTRIG (1 << 5) +#define DAS6402_STATUS_INDGT (1 << 6) +#define DAS6402_STATUS_10MHZ (1 << 7) +#define DAS6402_STATUS_W_CLRINT (1 << 0) +#define DAS6402_STATUS_W_CLRXTR (1 << 1) +#define DAS6402_STATUS_W_CLRXIN (1 << 2) +#define DAS6402_STATUS_W_EXTEND (1 << 4) +#define DAS6402_STATUS_W_ARMED (1 << 5) +#define DAS6402_STATUS_W_POSTMODE (1 << 6) +#define DAS6402_STATUS_W_10MHZ (1 << 7) +#define DAS6402_CTRL_REG 0x09 +#define DAS6402_CTRL_SOFT_TRIG (0 << 0) +#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0) +#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0) +#define DAS6402_CTRL_PACER_TRIG (3 << 0) +#define DAS6402_CTRL_BURSTEN (1 << 2) +#define DAS6402_CTRL_XINTE (1 << 3) +#define DAS6402_CTRL_IRQ(x) ((x) << 4) +#define DAS6402_CTRL_INTE (1 << 7) +#define DAS6402_TRIG_REG 0x0a +#define DAS6402_TRIG_TGEN (1 << 0) +#define DAS6402_TRIG_TGSEL (1 << 1) +#define DAS6402_TRIG_TGPOL (1 << 2) +#define DAS6402_TRIG_PRETRIG (1 << 3) +#define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4)) +#define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4)) +#define DAS6402_MODE_REG 0x0b +#define DAS6402_MODE_RANGE(x) ((x) << 0) +#define DAS6402_MODE_POLLED (0 << 2) +#define DAS6402_MODE_FIFONEPTY (1 << 2) +#define DAS6402_MODE_FIFOHFULL (2 << 2) +#define DAS6402_MODE_EOB (3 << 2) +#define DAS6402_MODE_ENHANCED (1 << 4) +#define DAS6402_MODE_SE (1 << 5) +#define DAS6402_MODE_UNI (1 << 6) +#define DAS6402_MODE_DMA1 (0 << 7) +#define DAS6402_MODE_DMA3 (1 << 7) +#define DAS6402_TIMER_BASE 0x0c + +static const struct comedi_lrange das6402_ai_ranges = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } +}; -This driver has suffered bitrot. -*/ +/* + * Analog output ranges are programmable on the DAS6402/12. + * For the DAS6402/16 the range bits have no function, the + * DAC ranges are selected by switches on the board. + */ +static const struct comedi_lrange das6402_ao_ranges = { + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } +}; -#include <linux/module.h> -#include <linux/interrupt.h> -#include "../comedidev.h" +struct das6402_boardinfo { + const char *name; + unsigned int maxdata; +}; -#define DAS6402_SIZE 16 - -#define N_WORDS (3000*64) - -#define STOP 0 -#define START 1 - -#define SCANL 0x3f00 -#define BYTE unsigned char -#define WORD unsigned short - -/*----- register 8 ----*/ -#define CLRINT 0x01 -#define CLRXTR 0x02 -#define CLRXIN 0x04 -#define EXTEND 0x10 -#define ARMED 0x20 /* enable conting of post sample conv */ -#define POSTMODE 0x40 -#define MHZ 0x80 /* 10 MHz clock */ -/*---------------------*/ - -/*----- register 9 ----*/ -#define IRQ (0x04 << 4) /* these two are */ -#define IRQV 10 /* dependent on each other */ - -#define CONVSRC 0x03 /* trig src is Intarnal pacer */ -#define BURSTEN 0x04 /* enable burst */ -#define XINTE 0x08 /* use external int. trig */ -#define INTE 0x80 /* enable analog interrupts */ -/*---------------------*/ - -/*----- register 10 ---*/ -#define TGEN 0x01 /* Use pin DI1 for externl trigging? */ -#define TGSEL 0x02 /* Use edge triggering */ -#define TGPOL 0x04 /* active edge is falling */ -#define PRETRIG 0x08 /* pretrig */ -/*---------------------*/ - -/*----- register 11 ---*/ -#define EOB 0x0c -#define FIFOHFULL 0x08 -#define GAIN 0x01 -#define FIFONEPTY 0x04 -#define MODE 0x10 -#define SEM 0x20 -#define BIP 0x40 -/*---------------------*/ - -#define M0 0x00 -#define M2 0x04 - -#define C0 0x00 -#define C1 0x40 -#define C2 0x80 -#define RWLH 0x30 +struct das6402_boardinfo das6402_boards[] = { + { + .name = "das6402-12", + .maxdata = 0x0fff, + }, { + .name = "das6402-16", + .maxdata = 0xffff, + }, +}; struct das6402_private { - int ai_bytes_to_read; + unsigned int irq; + + unsigned int count; + unsigned int divider1; + unsigned int divider2; - int das6402_ignoreirq; + unsigned int ao_range; + unsigned int ao_readback[2]; }; -static void das6402_ai_fifo_dregs(struct comedi_device *dev, - struct comedi_subdevice *s) +static void das6402_set_mode(struct comedi_device *dev, + unsigned int mode) { - while (1) { - if (!(inb(dev->iobase + 8) & 0x01)) - return; - comedi_buf_put(s->async, inw(dev->iobase)); - } + outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG); } -static void das6402_setcounter(struct comedi_device *dev) +static void das6402_set_extended(struct comedi_device *dev, + unsigned int val) { - BYTE p; - unsigned short ctrlwrd; - - /* set up counter0 first, mode 0 */ - p = M0 | C0 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 2000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 12); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 12); - - /* set up counter1, mode 2 */ - p = M2 | C1 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 10; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 13); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 13); - - /* set up counter1, mode 2 */ - p = M2 | C2 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 1000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 14); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 14); + outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG); + outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG); + outb(val, dev->iobase + DAS6402_STATUS_REG); } -static irqreturn_t intr_handler(int irq, void *d) +static void das6402_clear_all_interrupts(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT | + DAS6402_STATUS_W_CLRXTR | + DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG); +} + +static void das6402_ai_clear_eoc(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG); +} + +static void das6402_enable_counter(struct comedi_device *dev, bool load) { - struct comedi_device *dev = d; struct das6402_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + unsigned long timer_iobase = dev->iobase + DAS6402_TIMER_BASE; - if (!dev->attached || devpriv->das6402_ignoreirq) { - dev_warn(dev->class_dev, "BUG: spurious interrupt\n"); - return IRQ_HANDLED; - } + if (load) { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY); - das6402_ai_fifo_dregs(dev, s); + i8254_write(timer_iobase, 0, 0, devpriv->count); + i8254_write(timer_iobase, 0, 1, devpriv->divider1); + i8254_write(timer_iobase, 0, 2, devpriv->divider2); - if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) { - outw_p(SCANL, dev->iobase + 2); /* clears the fifo */ - outb(0x07, dev->iobase + 8); /* clears all flip-flops */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + } else { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY); } +} - outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */ +static irqreturn_t das6402_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + + das6402_clear_all_interrupts(dev); - comedi_event(dev, s); return IRQ_HANDLED; } -#if 0 -static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) +static int das6402_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { - int i; + return -EINVAL; +} - for (i = 0; i < n; i++) - data[i] = inw(dev->iobase); +static int das6402_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + return -EINVAL; } -#endif static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + return 0; +} + +static void das6402_ai_soft_trig(struct comedi_device *dev) +{ + outw(0, dev->iobase + DAS6402_AI_DATA_REG); +} + +static int das6402_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS6402_STATUS_REG); + if (status & DAS6402_STATUS_FFNE) + return 0; + return -EBUSY; +} + +static int das6402_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned int val; + int ret; + int i; + + val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED; + if (aref == AREF_DIFF) { + if (chan > s->n_chan / 2) + return -EINVAL; + } else { + val |= DAS6402_MODE_SE; + } + if (comedi_range_is_unipolar(s, range)) + val |= DAS6402_MODE_UNI; + + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + das6402_set_mode(dev, val); + + /* load the mux for single channel conversion */ + outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan), + dev->iobase + DAS6402_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + das6402_ai_clear_eoc(dev); + das6402_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0); + if (ret) + break; + + val = inw(dev->iobase + DAS6402_AI_DATA_REG); + + if (s->maxdata == 0x0fff) + val >>= 4; + + data[i] = val; + } + + das6402_ai_clear_eoc(dev); + + return insn->n; +} + +static int das6402_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + /* set the range for this channel */ + val = devpriv->ao_range; + val &= ~DAS6402_AO_RANGE_MASK(chan); + val |= DAS6402_AO_RANGE(chan, range); + if (val != devpriv->ao_range) { + devpriv->ao_range = val; + outb(val, dev->iobase + DAS6402_TRIG_REG); + } /* - * This function should reset the board from whatever condition it - * is in (i.e., acquiring data), to a non-active state. + * The DAS6402/16 has a jumper to select either individual + * update (UPDATE) or simultaneous updating (XFER) of both + * DAC's. In UPDATE mode, when the MSB is written, that DAC + * is updated. In XFER mode, after both DAC's are loaded, + * a read cycle of any DAC register will update both DAC's + * simultaneously. + * + * If you have XFER mode enabled a (*insn_read) will need + * to be performed in order to update the DAC's with the + * last value written. */ + for (i = 0; i < insn->n; i++) { + val = data[i]; + + devpriv->ao_readback[chan] = val; + + if (s->maxdata == 0x0fff) { + /* + * DAS6402/12 has the two 8-bit DAC registers, left + * justified (the 4 LSB bits are don't care). Data + * can be written as one word. + */ + val <<= 4; + outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan)); + } else { + /* + * DAS6402/16 uses both 8-bit DAC registers and needs + * to be written LSB then MSB. + */ + outb(val & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + } + } - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Stopping acquisition\n"); - devpriv->das6402_ignoreirq = 1; - outb_p(0x02, dev->iobase + 10); /* disable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(0, dev->iobase + 9); /* disables interrupts */ - - outw_p(SCANL, dev->iobase + 2); - - return 0; + return insn->n; } -#ifdef unused -static int das6402_ai_mode2(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig *it) +static int das6402_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Starting acquisition\n"); - outb_p(0x03, dev->iobase + 10); /* enable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); + /* + * If XFER mode is enabled, reading any DAC register + * will update both DAC's simultaneously. + */ + inw(dev->iobase + DAS6402_AO_LSB_REG(chan)); - devpriv->ai_bytes_to_read = it->n * sizeof(short); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - /* um... ignoreirq is a nasty race condition */ - devpriv->das6402_ignoreirq = 0; + return insn->n; +} - outw_p(SCANL, dev->iobase + 2); +static int das6402_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + DAS6402_DI_DO_REG); - return 0; + return insn->n; } -#endif -static int board_init(struct comedi_device *dev) +static int das6402_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct das6402_private *devpriv = dev->private; - BYTE b; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS6402_DI_DO_REG); - devpriv->das6402_ignoreirq = 1; + data[1] = s->state; - outb(0x07, dev->iobase + 8); + return insn->n; +} - /* register 11 */ - outb_p(MODE, dev->iobase + 11); - b = BIP | SEM | MODE | GAIN | FIFOHFULL; - outb_p(b, dev->iobase + 11); +static void das6402_reset(struct comedi_device *dev) +{ + struct das6402_private *devpriv = dev->private; - /* register 8 */ - outb_p(EXTEND, dev->iobase + 8); - b = EXTEND | MHZ; - outb_p(b, dev->iobase + 8); - b = MHZ | CLRINT | CLRXTR | CLRXIN; - outb_p(b, dev->iobase + 8); + /* enable "Enhanced" mode */ + outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG); - /* register 9 */ - b = IRQ | CONVSRC | BURSTEN | INTE; - outb_p(b, dev->iobase + 9); + /* enable 10MHz pacer clock */ + das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ); - /* register 10 */ - b = TGSEL | TGEN; - outb_p(b, dev->iobase + 10); + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); - b = 0x07; - outb_p(b, dev->iobase + 8); + /* default ADC to single-ended unipolar 10V inputs */ + das6402_set_mode(dev, DAS6402_MODE_RANGE(0) | + DAS6402_MODE_POLLED | + DAS6402_MODE_SE | + DAS6402_MODE_UNI); - das6402_setcounter(dev); + /* default mux for single channel conversion (channel 0) */ + outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0), + dev->iobase + DAS6402_AI_MUX_REG); - outw_p(SCANL, dev->iobase + 2); /* reset card fifo */ + /* set both DAC's for unipolar 5V output range */ + devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2); + outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG); - devpriv->das6402_ignoreirq = 0; + /* set both DAC's to 0V */ + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + inw(dev->iobase + DAS6402_AO_LSB_REG(0)); - return 0; + das6402_enable_counter(dev, false); + + /* set all digital outputs low */ + outb(0, dev->iobase + DAS6402_DI_DO_REG); + + das6402_clear_all_interrupts(dev); } static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct das6402_boardinfo *board = comedi_board(dev); struct das6402_private *devpriv; - unsigned int irq; - int ret; struct comedi_subdevice *s; - - ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE); - if (ret) - return ret; - - irq = it->options[0]; - dev_dbg(dev->class_dev, "( irq = %u )\n", irq); - ret = request_irq(irq, intr_handler, 0, "das6402", dev); - if (ret < 0) - return ret; - - dev->irq = irq; + int ret; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - /* ai subdevice */ + das6402_reset(dev); + + /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ + if ((1 << it->options[1]) & 0x8cec) { + ret = request_irq(it->options[1], das6402_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = it->options[1]; + + switch (dev->irq) { + case 10: + devpriv->irq = 4; + break; + case 11: + devpriv->irq = 1; + break; + case 15: + devpriv->irq = 6; + break; + default: + devpriv->irq = dev->irq; + break; + } + } + } + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* Analog Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - /* s->trig[2]=das6402_ai_mode2; */ - s->cancel = das6402_ai_cancel; - s->maxdata = (1 << 12) - 1; - s->len_chanlist = 16; /* ? */ - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 64; + s->maxdata = board->maxdata; + s->range_table = &das6402_ai_ranges; + s->insn_read = das6402_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = das6402_ai_cmdtest; + s->do_cmd = das6402_ai_cmd; + s->cancel = das6402_ai_cancel; + } - board_init(dev); + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = board->maxdata; + s->range_table = &das6402_ao_ranges; + s->insn_write = das6402_ao_insn_write; + s->insn_read = das6402_ao_insn_read; + + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_di_insn_bits; + + /* Digital Input subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_do_insn_bits; return 0; } @@ -313,9 +536,12 @@ static struct comedi_driver das6402_driver = { .module = THIS_MODULE, .attach = das6402_attach, .detach = comedi_legacy_detach, + .board_name = &das6402_boards[0].name, + .num_names = ARRAY_SIZE(das6402_boards), + .offset = sizeof(struct das6402_boardinfo), }; module_comedi_driver(das6402_driver) -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 5af0a5764a8c..3e408370dcf3 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -420,17 +420,12 @@ static int das800_ai_do_cmd(struct comedi_device *dev, gain &= 0xf; outb(gain, dev->iobase + DAS800_GAIN); - switch (async->cmd.stop_src) { - case TRIG_COUNT: + if (async->cmd.stop_src == TRIG_COUNT) { devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len; devpriv->forever = false; - break; - case TRIG_NONE: + } else { /* TRIG_NONE */ devpriv->forever = true; devpriv->count = 0; - break; - default: - break; } /* enable auto channel scan, send interrupts on end of conversion @@ -440,26 +435,19 @@ static int das800_ai_do_cmd(struct comedi_device *dev, conv_bits |= EACS | IEOC; if (async->cmd.start_src == TRIG_EXT) conv_bits |= DTEN; - switch (async->cmd.convert_src) { - case TRIG_TIMER: + if (async->cmd.convert_src == TRIG_TIMER) { conv_bits |= CASC | ITE; /* set conversion frequency */ if (das800_set_frequency(dev) < 0) { comedi_error(dev, "Error setting up counters"); return -1; } - break; - case TRIG_EXT: - break; - default: - break; } spin_lock_irqsave(&dev->spinlock, irq_flags); das800_ind_write(dev, conv_bits, CONV_CONTROL); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - async->events = 0; das800_enable(dev); return 0; } @@ -532,10 +520,8 @@ static irqreturn_t das800_interrupt(int irq, void *d) if (fifo_overflow) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); - das800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); - async->events = 0; + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -551,20 +537,21 @@ static irqreturn_t das800_interrupt(int irq, void *d) das800_disable(dev); async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - async->events = 0; + cfc_handle_events(dev, s); return IRQ_HANDLED; } -static int das800_wait_for_conv(struct comedi_device *dev, int timeout) +static int das800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < timeout; i++) { - if (!(inb(dev->iobase + DAS800_STATUS) & BUSY)) - return 0; - } - return -ETIME; + status = inb(dev->iobase + DAS800_STATUS); + if ((status & BUSY) == 0) + return 0; + return -EBUSY; } static int das800_ai_insn_read(struct comedi_device *dev, @@ -599,7 +586,7 @@ static int das800_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ outb_p(0, dev->iobase + DAS800_MSB); - ret = das800_wait_for_conv(dev, 1000); + ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 78a19629ff56..c8a36eb5f015 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -164,16 +164,29 @@ struct dmm32at_private { }; +static int dmm32at_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + context); + if ((status & DMM32AT_STATUS) == 0) + return 0; + return -EBUSY; +} + static int dmm32at_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + int n; unsigned int d; - unsigned char status; unsigned short msb, lsb; unsigned char chan; int range; + int ret; /* get the channel and range number */ @@ -190,26 +203,20 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev, outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ outb(0xff, dev->iobase + DMM32AT_CONV); + /* wait for conversion to end */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AISTAT); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, + DMM32AT_AISTAT); + if (ret) + return ret; /* read data */ lsb = inb(dev->iobase + DMM32AT_AILSB); @@ -403,8 +410,9 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct dmm32at_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int i, range; - unsigned char chanlo, chanhi, status; + int range; + unsigned char chanlo, chanhi; + int ret; if (!cmd->chanlist) return -EINVAL; @@ -439,14 +447,13 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * isr */ } - /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + /* + * wait for circuit to settle + * we don't have the 'insn' here but it's not needed + */ + ret = comedi_timeout(dev, s, NULL, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; if (devpriv->ai_scans_left > 1) { /* start the clock and enable the interrupts */ @@ -525,6 +532,19 @@ static irqreturn_t dmm32at_isr(int irq, void *d) return IRQ_HANDLED; } +static int dmm32at_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + DMM32AT_DACSTAT); + if ((status & DMM32AT_DACBUSY) == 0) + return 0; + return -EBUSY; +} + static int dmm32at_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -533,6 +553,7 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, int i; int chan = CR_CHAN(insn->chanspec); unsigned char hi, lo, status; + int ret; /* Writing a list of values to an AO channel is probably not * very useful, but that's how the interface is defined. */ @@ -549,13 +570,9 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, outb(hi, dev->iobase + DMM32AT_DACMSB); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_DACSTAT); - if ((status & DMM32AT_DACBUSY) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0); + if (ret) + return ret; /* dummy read to update trigger the output */ status = inb(dev->iobase + DMM32AT_DACMSB); diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 4271903facd7..ba7c2ba618e6 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -224,23 +224,32 @@ static const struct comedi_lrange *dac_range_types[] = { &range_unipolar5 }; -#define DT2811_TIMEOUT 5 +static int dt2811_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2811_ADCSR); + if ((status & DT2811_ADBUSY) == 0) + return 0; + return -EBUSY; +} static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); - int timeout = DT2811_TIMEOUT; + int ret; int i; for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + DT2811_ADGCR); - while (timeout - && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) - timeout--; - if (!timeout) - return -ETIME; + ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0); + if (ret) + return ret; data[i] = inb(dev->iobase + DT2811_ADDATLO); data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index abad6e49c1c1..3794b7e52091 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -66,26 +66,35 @@ struct dt2814_private { #define DT2814_TIMEOUT 10 #define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */ +static int dt2814_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2814_CSR); + if (status & DT2814_FINISH) + return 0; + return -EBUSY; +} + static int dt2814_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, hi, lo; + int n, hi, lo; int chan; - int status = 0; + int ret; for (n = 0; n < insn->n; n++) { chan = CR_CHAN(insn->chanspec); outb(chan, dev->iobase + DT2814_CSR); - for (i = 0; i < DT2814_TIMEOUT; i++) { - status = inb(dev->iobase + DT2814_CSR); - udelay(10); - if (status & DT2814_FINISH) - break; - } - if (i >= DT2814_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, dt2814_ai_eoc, 0); + if (ret) + return ret; hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index ee24717821e1..b9ac4ed8babb 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -67,15 +67,17 @@ struct dt2815_private { unsigned int ao_readback[8]; }; -static int dt2815_wait_for_status(struct comedi_device *dev, int status) +static int dt2815_ao_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < 100; i++) { - if (inb(dev->iobase + DT2815_STATUS) == status) - break; - } - return status; + status = inb(dev->iobase + DT2815_STATUS); + if (status == context) + return 0; + return -EBUSY; } static int dt2815_ao_insn_read(struct comedi_device *dev, @@ -98,30 +100,23 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct dt2815_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); - unsigned int status; unsigned int lo, hi; + int ret; for (i = 0; i < insn->n; i++) { lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01; hi = (data[i] & 0xff0) >> 4; - status = dt2815_wait_for_status(dev, 0x00); - if (status != 0) { - dev_dbg(dev->class_dev, - "failed to write low byte on %d reason %x\n", - chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x00); + if (ret) + return ret; outb(lo, dev->iobase + DT2815_DATA); - status = dt2815_wait_for_status(dev, 0x10); - if (status != 0x10) { - dev_dbg(dev->class_dev, - "failed to write high byte on %d reason %x\n", - chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x10); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; } return i; diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 895f73a19023..16cc100531e5 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -63,7 +63,6 @@ Notes: #include "comedi_fc.h" -#define DT2821_TIMEOUT 100 /* 500 us */ #define DT2821_SIZE 0x10 /* @@ -248,27 +247,6 @@ struct dt282x_private { * Some useless abstractions */ #define chan_to_DAC(a) ((a)&1) -#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY) -#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE) - -/* - * danger! macro abuse... a is the expression to wait on, and b is - * the statement(s) to execute if it doesn't happen. - */ -#define wait_for(a, b) \ - do { \ - int _i; \ - for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \ - if (a) { \ - _i = 0; \ - break; \ - } \ - udelay(5); \ - } \ - if (_i) { \ - b \ - } \ - } while (0) static int prep_ai_dma(struct comedi_device *dev, int chan, int size); static int prep_ao_dma(struct comedi_device *dev, int chan, int size); @@ -328,7 +306,6 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); if (size == 0) { dev_err(dev->class_dev, "AO underrun\n"); - dt282x_ao_cancel(dev, s); s->async->events |= COMEDI_CB_OVERFLOW; return; } @@ -363,7 +340,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) dt282x_munge(dev, ptr, size); ret = cfc_write_array_to_buffer(s, ptr, size); if (ret != size) { - dt282x_ai_cancel(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; return; } devpriv->nread -= size / 2; @@ -373,7 +350,6 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) devpriv->nread = 0; } if (!devpriv->nread) { - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; return; } @@ -471,15 +447,13 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) if (adcsr & DT2821_ADERR) { if (devpriv->nread != 0) { comedi_error(dev, "A/D error"); - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_ERROR; } handled = 1; } if (dacsr & DT2821_DAERR) { comedi_error(dev, "D/A error"); - dt282x_ao_cancel(dev, s_ao); - s->async->events |= COMEDI_CB_ERROR; + s_ao->async->events |= COMEDI_CB_ERROR; handled = 1; } #if 0 @@ -508,7 +482,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) handled = 1; } #endif - comedi_event(dev, s); + cfc_handle_events(dev, s); + cfc_handle_events(dev, s_ao); return IRQ_RETVAL(handled); } @@ -530,6 +505,29 @@ static void dt282x_load_changain(struct comedi_device *dev, int n, outw(n - 1, dev->iobase + DT2821_CHANCSR); } +static int dt282x_ai_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + DT2821_ADCSR); + switch (context) { + case DT2821_MUXBUSY: + if ((status & DT2821_MUXBUSY) == 0) + return 0; + break; + case DT2821_ADDONE: + if (status & DT2821_ADDONE) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Performs a single A/D conversion. * - Put channel/gain into channel-gain list @@ -542,6 +540,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, { const struct dt282x_board *board = comedi_board(dev); struct dt282x_private *devpriv = dev->private; + int ret; int i; /* XXX should we really be enabling the ad clock here? */ @@ -551,13 +550,18 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, dt282x_load_changain(dev, 1, &insn->chanspec); outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; for (i = 0; i < insn->n; i++) { outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR); - wait_for(ad_done(), comedi_error(dev, "timeout\n"); - return -ETIME;); + + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, + DT2821_ADDONE); + if (ret) + return ret; data[i] = inw(dev->iobase + @@ -646,6 +650,7 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct dt282x_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int timer; + int ret; if (devpriv->usedma == 0) { comedi_error(dev, @@ -691,7 +696,9 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; if (cmd->scan_begin_src == TRIG_FOLLOW) { outw(devpriv->supcsr | DT2821_STRIG, diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index f52a4476cb73..436e451cadf5 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -369,12 +369,10 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; debug_n_ints++; - if (debug_n_ints >= 10) { - dt3k_ai_cancel(dev, s); + if (debug_n_ints >= 10) s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -767,8 +765,6 @@ static int dt3000_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_PROC; #endif - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index f224825830ba..e5593f8c7406 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -57,18 +57,27 @@ struct dyna_pci10xx_private { unsigned long BADR3; }; -/******************************************************************************/ -/************************** READ WRITE FUNCTIONS ******************************/ -/******************************************************************************/ +static int dyna_pci10xx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw_p(dev->iobase); + if (status & (1 << 15)) + return 0; + return -EBUSY; +} -/* analog input callback */ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; - int n, counter; + int n; u16 d = 0; + int ret = 0; unsigned int chan, range; /* get the channel number and range */ @@ -82,18 +91,13 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, smp_mb(); outw_p(0x0000 + range + chan, dev->iobase + 2); udelay(10); + + ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0); + if (ret) + break; + /* read data */ - for (counter = 0; counter < READ_TIMEOUT; counter++) { - d = inw_p(dev->iobase); - - /* check if read is successful if the EOC bit is set */ - if (d & (1 << 15)) - goto conv_finish; - } - data[n] = 0; - dev_dbg(dev->class_dev, "timeout reading analog input\n"); - continue; -conv_finish: + d = inw_p(dev->iobase); /* mask the first 4 bits - EOC bits */ d &= 0x0FFF; data[n] = d; @@ -101,7 +105,7 @@ conv_finish: mutex_unlock(&devpriv->mutex); /* return the number of samples read/written */ - return n; + return ret ? ret : n; } /* analog output callback */ @@ -232,8 +236,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, s->state = 0; s->insn_bits = dyna_pci10xx_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index a99ddf00ddc4..4e410f3b0e24 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -1,27 +1,49 @@ /* - comedi/drivers/fl512.c - Anders Gnistrup <ex18@kalman.iau.dtu.dk> -*/ + * fl512.c + * Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: fl512 -Description: unknown -Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> -Devices: [unknown] FL512 (fl512) -Status: unknown - -Digital I/O is not supported. - -Configuration options: - [0] - I/O port base address -*/ + * Driver: fl512 + * Description: unknown + * Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * Devices: [unknown] FL512 (fl512) + * Status: unknown + * + * Digital I/O is not supported. + * + * Configuration options: + * [0] - I/O port base address + */ #include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#define FL512_SIZE 16 /* the size of the used memory */ +/* + * Register I/O map + */ +#define FL512_AI_LSB_REG 0x02 +#define FL512_AI_MSB_REG 0x03 +#define FL512_AI_MUX_REG 0x02 +#define FL512_AI_START_CONV_REG 0x03 +#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2)) + struct fl512_private { unsigned short ao_readback[2]; }; @@ -38,72 +60,69 @@ static const struct comedi_lrange range_fl512 = { } }; -/* - * fl512_ai_insn : this is the analog input function - */ -static int fl512_ai_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - unsigned int lo_byte, hi_byte; - char chan = CR_CHAN(insn->chanspec); - unsigned long iobase = dev->iobase; - - for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */ - /* XXX probably can move next step out of for() loop -- will - * make AI a little bit faster. */ - outb(chan, iobase + 2); /* select chan */ - outb(0, iobase + 3); /* start conversion */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + FL512_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + outb(0, dev->iobase + FL512_AI_START_CONV_REG); + /* XXX should test "done" flag instead of delay */ - udelay(30); /* sleep 30 usec */ - lo_byte = inb(iobase + 2); /* low 8 byte */ - hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */ - data[n] = lo_byte + (hi_byte << 8); + udelay(30); + + val = inb(dev->iobase + FL512_AI_LSB_REG); + val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8); + val &= s->maxdata; + + data[i] = val; } - return n; + + return insn->n; } -/* - * fl512_ao_insn : used to write to a DA port n times - */ -static int fl512_ao_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); /* get chan to write */ - unsigned long iobase = dev->iobase; /* get base address */ - - for (n = 0; n < insn->n; n++) { /* write n data set */ - /* write low byte */ - outb(data[n] & 0x0ff, iobase + 4 + 2 * chan); - /* write high byte */ - outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan); - inb(iobase + 4 + 2 * chan); /* trig */ - - devpriv->ao_readback[chan] = data[n]; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* write LSB, MSB then trigger conversion */ + outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan)); + outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan)); + inb(dev->iobase + FL512_AO_TRIG_REG(chan)); } - return n; + devpriv->ao_readback[chan] = val; + + return insn->n; } -/* - * fl512_ao_insn_readback : used to read previous values written to - * DA port - */ -static int fl512_ao_insn_readback(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int fl512_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - return n; + return insn->n; } static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -112,7 +131,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], FL512_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; @@ -124,42 +143,26 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - /* - * this if the definitions of the supdevices, 2 have been defined - */ - /* Analog indput */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* define subdevice as Analog In */ - s->type = COMEDI_SUBD_AI; - /* you can read it from userspace */ - s->subdev_flags = SDF_READABLE | SDF_GROUND; - /* Number of Analog input channels */ - s->n_chan = 16; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when read AD */ - s->insn_read = fl512_ai_insn; - - /* Analog output */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_read = fl512_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* define subdevice as Analog OUT */ - s->type = COMEDI_SUBD_AO; - /* you can write it from userspace */ - s->subdev_flags = SDF_WRITABLE; - /* Number of Analog output channels */ - s->n_chan = 2; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when write DA */ - s->insn_write = fl512_ao_insn; - /* function to call when reading DA */ - s->insn_read = fl512_ao_insn_readback; - - return 1; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_write = fl512_ao_insn_write; + s->insn_read = fl512_ao_insn_read; + + return 0; } static struct comedi_driver fl512_driver = { diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index de60a2871d70..08d7655e24e7 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -1,24 +1,24 @@ /* - comedi/drivers/gsc_hpdi.c - This is a driver for the General Standards Corporation High - Speed Parallel Digital Interface rs485 boards. - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2003 Coherent Imaging Systems - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * gsc_hpdi.c + * Comedi driver the General Standards Corporation + * High Speed Parallel Digital Interface rs485 boards. + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2003 Coherent Imaging Systems + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* * Driver: gsc_hpdi @@ -40,8 +40,6 @@ * support could be added to this driver. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> @@ -52,149 +50,105 @@ #include "plx9080.h" #include "comedi_fc.h" -static void abort_dma(struct comedi_device *dev, unsigned int channel); -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t handle_interrupt(int irq, void *d); -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data); - -#define TIMER_BASE 50 /* 20MHz master clock */ -#define DMA_BUFFER_SIZE 0x10000 -#define NUM_DMA_BUFFERS 4 -#define NUM_DMA_DESCRIPTORS 256 - -enum hpdi_registers { - FIRMWARE_REV_REG = 0x0, - BOARD_CONTROL_REG = 0x4, - BOARD_STATUS_REG = 0x8, - TX_PROG_ALMOST_REG = 0xc, - RX_PROG_ALMOST_REG = 0x10, - FEATURES_REG = 0x14, - FIFO_REG = 0x18, - TX_STATUS_COUNT_REG = 0x1c, - TX_LINE_VALID_COUNT_REG = 0x20, - TX_LINE_INVALID_COUNT_REG = 0x24, - RX_STATUS_COUNT_REG = 0x28, - RX_LINE_COUNT_REG = 0x2c, - INTERRUPT_CONTROL_REG = 0x30, - INTERRUPT_STATUS_REG = 0x34, - TX_CLOCK_DIVIDER_REG = 0x38, - TX_FIFO_SIZE_REG = 0x40, - RX_FIFO_SIZE_REG = 0x44, - TX_FIFO_WORDS_REG = 0x48, - RX_FIFO_WORDS_REG = 0x4c, - INTERRUPT_EDGE_LEVEL_REG = 0x50, - INTERRUPT_POLARITY_REG = 0x54, -}; - -/* bit definitions */ - -enum firmware_revision_bits { - FEATURES_REG_PRESENT_BIT = 0x8000, -}; - -enum board_control_bits { - BOARD_RESET_BIT = 0x1, /* wait 10usec before accessing fifos */ - TX_FIFO_RESET_BIT = 0x2, - RX_FIFO_RESET_BIT = 0x4, - TX_ENABLE_BIT = 0x10, - RX_ENABLE_BIT = 0x20, - DEMAND_DMA_DIRECTION_TX_BIT = 0x40, - /* for ch 0, ch 1 can only transmit (when present) */ - LINE_VALID_ON_STATUS_VALID_BIT = 0x80, - START_TX_BIT = 0x10, - CABLE_THROTTLE_ENABLE_BIT = 0x20, - TEST_MODE_ENABLE_BIT = 0x80000000, -}; - -enum board_status_bits { - COMMAND_LINE_STATUS_MASK = 0x7f, - TX_IN_PROGRESS_BIT = 0x80, - TX_NOT_EMPTY_BIT = 0x100, - TX_NOT_ALMOST_EMPTY_BIT = 0x200, - TX_NOT_ALMOST_FULL_BIT = 0x400, - TX_NOT_FULL_BIT = 0x800, - RX_NOT_EMPTY_BIT = 0x1000, - RX_NOT_ALMOST_EMPTY_BIT = 0x2000, - RX_NOT_ALMOST_FULL_BIT = 0x4000, - RX_NOT_FULL_BIT = 0x8000, - BOARD_JUMPER0_INSTALLED_BIT = 0x10000, - BOARD_JUMPER1_INSTALLED_BIT = 0x20000, - TX_OVERRUN_BIT = 0x200000, - RX_UNDERRUN_BIT = 0x400000, - RX_OVERRUN_BIT = 0x800000, -}; - -static uint32_t almost_full_bits(unsigned int num_words) -{ - /* XXX need to add or subtract one? */ - return (num_words << 16) & 0xff0000; -} - -static uint32_t almost_empty_bits(unsigned int num_words) -{ - return num_words & 0xffff; -} - -enum features_bits { - FIFO_SIZE_PRESENT_BIT = 0x1, - FIFO_WORDS_PRESENT_BIT = 0x2, - LEVEL_EDGE_INTERRUPTS_PRESENT_BIT = 0x4, - GPIO_SUPPORTED_BIT = 0x8, - PLX_DMA_CH1_SUPPORTED_BIT = 0x10, - OVERRUN_UNDERRUN_SUPPORTED_BIT = 0x20, -}; - -enum interrupt_sources { - FRAME_VALID_START_INTR = 0, - FRAME_VALID_END_INTR = 1, - TX_FIFO_EMPTY_INTR = 8, - TX_FIFO_ALMOST_EMPTY_INTR = 9, - TX_FIFO_ALMOST_FULL_INTR = 10, - TX_FIFO_FULL_INTR = 11, - RX_EMPTY_INTR = 12, - RX_ALMOST_EMPTY_INTR = 13, - RX_ALMOST_FULL_INTR = 14, - RX_FULL_INTR = 15, -}; - -static uint32_t intr_bit(int interrupt_source) -{ - return 0x1 << interrupt_source; -} - -static unsigned int fifo_size(uint32_t fifo_size_bits) -{ - return fifo_size_bits & 0xfffff; -} +/* + * PCI BAR2 Register map (devpriv->mmio) + */ +#define FIRMWARE_REV_REG 0x00 +#define FEATURES_REG_PRESENT_BIT (1 << 15) +#define BOARD_CONTROL_REG 0x04 +#define BOARD_RESET_BIT (1 << 0) +#define TX_FIFO_RESET_BIT (1 << 1) +#define RX_FIFO_RESET_BIT (1 << 2) +#define TX_ENABLE_BIT (1 << 4) +#define RX_ENABLE_BIT (1 << 5) +#define DEMAND_DMA_DIRECTION_TX_BIT (1 << 6) /* ch 0 only */ +#define LINE_VALID_ON_STATUS_VALID_BIT (1 << 7) +#define START_TX_BIT (1 << 8) +#define CABLE_THROTTLE_ENABLE_BIT (1 << 9) +#define TEST_MODE_ENABLE_BIT (1 << 31) +#define BOARD_STATUS_REG 0x08 +#define COMMAND_LINE_STATUS_MASK (0x7f << 0) +#define TX_IN_PROGRESS_BIT (1 << 7) +#define TX_NOT_EMPTY_BIT (1 << 8) +#define TX_NOT_ALMOST_EMPTY_BIT (1 << 9) +#define TX_NOT_ALMOST_FULL_BIT (1 << 10) +#define TX_NOT_FULL_BIT (1 << 11) +#define RX_NOT_EMPTY_BIT (1 << 12) +#define RX_NOT_ALMOST_EMPTY_BIT (1 << 13) +#define RX_NOT_ALMOST_FULL_BIT (1 << 14) +#define RX_NOT_FULL_BIT (1 << 15) +#define BOARD_JUMPER0_INSTALLED_BIT (1 << 16) +#define BOARD_JUMPER1_INSTALLED_BIT (1 << 17) +#define TX_OVERRUN_BIT (1 << 21) +#define RX_UNDERRUN_BIT (1 << 22) +#define RX_OVERRUN_BIT (1 << 23) +#define TX_PROG_ALMOST_REG 0x0c +#define RX_PROG_ALMOST_REG 0x10 +#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0) +#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16) +#define FEATURES_REG 0x14 +#define FIFO_SIZE_PRESENT_BIT (1 << 0) +#define FIFO_WORDS_PRESENT_BIT (1 << 1) +#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT (1 << 2) +#define GPIO_SUPPORTED_BIT (1 << 3) +#define PLX_DMA_CH1_SUPPORTED_BIT (1 << 4) +#define OVERRUN_UNDERRUN_SUPPORTED_BIT (1 << 5) +#define FIFO_REG 0x18 +#define TX_STATUS_COUNT_REG 0x1c +#define TX_LINE_VALID_COUNT_REG 0x20, +#define TX_LINE_INVALID_COUNT_REG 0x24 +#define RX_STATUS_COUNT_REG 0x28 +#define RX_LINE_COUNT_REG 0x2c +#define INTERRUPT_CONTROL_REG 0x30 +#define FRAME_VALID_START_INTR (1 << 0) +#define FRAME_VALID_END_INTR (1 << 1) +#define TX_FIFO_EMPTY_INTR (1 << 8) +#define TX_FIFO_ALMOST_EMPTY_INTR (1 << 9) +#define TX_FIFO_ALMOST_FULL_INTR (1 << 10) +#define TX_FIFO_FULL_INTR (1 << 11) +#define RX_EMPTY_INTR (1 << 12) +#define RX_ALMOST_EMPTY_INTR (1 << 13) +#define RX_ALMOST_FULL_INTR (1 << 14) +#define RX_FULL_INTR (1 << 15) +#define INTERRUPT_STATUS_REG 0x34 +#define TX_CLOCK_DIVIDER_REG 0x38 +#define TX_FIFO_SIZE_REG 0x40 +#define RX_FIFO_SIZE_REG 0x44 +#define FIFO_SIZE_MASK (0xfffff << 0) +#define TX_FIFO_WORDS_REG 0x48 +#define RX_FIFO_WORDS_REG 0x4c +#define INTERRUPT_EDGE_LEVEL_REG 0x50 +#define INTERRUPT_POLARITY_REG 0x54 + +#define TIMER_BASE 50 /* 20MHz master clock */ +#define DMA_BUFFER_SIZE 0x10000 +#define NUM_DMA_BUFFERS 4 +#define NUM_DMA_DESCRIPTORS 256 struct hpdi_board { - const char *name; /* board name */ - int device_id; /* pci device id */ - int subdevice_id; /* pci subdevice id */ + const char *name; + int device_id; + int subdevice_id; }; static const struct hpdi_board hpdi_boards[] = { { - .name = "pci-hpdi32", - .device_id = PCI_DEVICE_ID_PLX_9080, - .subdevice_id = 0x2400, + .name = "pci-hpdi32", + .device_id = PCI_DEVICE_ID_PLX_9080, + .subdevice_id = 0x2400, }, #if 0 { - .name = "pxi-hpdi32", - .device_id = 0x9656, - .subdevice_id = 0x2705, + .name = "pxi-hpdi32", + .device_id = 0x9656, + .subdevice_id = 0x2705, }, #endif }; struct hpdi_private { - /* base addresses (ioremapped) */ - void __iomem *plx9080_iobase; - void __iomem *hpdi_iobase; + void __iomem *plx9080_mmio; + void __iomem *mmio; uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ /* physical addresses of dma buffers */ dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; @@ -207,26 +161,334 @@ struct hpdi_private { /* pointer to start of buffers indexed by descriptor */ uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* index of the dma descriptor that is currently being used */ - volatile unsigned int dma_desc_index; + unsigned int dma_desc_index; unsigned int tx_fifo_size; unsigned int rx_fifo_size; - volatile unsigned long dio_count; - /* software copies of values written to hpdi registers */ - volatile uint32_t bits[24]; + unsigned long dio_count; /* number of bytes at which to generate COMEDI_CB_BLOCK events */ - volatile unsigned int block_size; + unsigned int block_size; }; -static int dio_config_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) +{ + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int idx; + unsigned int start; + unsigned int desc; + unsigned int size; + unsigned int next; + + if (channel) + next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG); + else + next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + + idx = devpriv->dma_desc_index; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + /* loop until we have read all the full buffers */ + for (desc = 0; (next < start || next >= start + devpriv->block_size) && + desc < devpriv->num_dma_descriptors; desc++) { + /* transfer data from dma buffer to comedi buffer */ + size = devpriv->block_size / sizeof(uint32_t); + if (cmd->stop_src == TRIG_COUNT) { + if (size > devpriv->dio_count) + size = devpriv->dio_count; + devpriv->dio_count -= size; + } + cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx], + size * sizeof(uint32_t)); + idx++; + idx %= devpriv->num_dma_descriptors; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + + devpriv->dma_desc_index = idx; + } + /* XXX check for buffer overrun somehow */ +} + +static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + uint32_t hpdi_intr_status, hpdi_board_status; + uint32_t plx_status; + uint32_t plx_bits; + uint8_t dma0_status, dma1_status; + unsigned long flags; + + if (!dev->attached) + return IRQ_NONE; + + plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG); + if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) + return IRQ_NONE; + + hpdi_intr_status = readl(devpriv->mmio + INTERRUPT_STATUS_REG); + hpdi_board_status = readl(devpriv->mmio + BOARD_STATUS_REG); + + if (hpdi_intr_status) + writel(hpdi_intr_status, devpriv->mmio + INTERRUPT_STATUS_REG); + + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ + writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + + if (dma0_status & PLX_DMA_EN_BIT) + gsc_hpdi_drain_dma(dev, 0); + } + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ + writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + } + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* clear possible plx9080 interrupt sources */ + if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ + plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + } + + if (hpdi_board_status & RX_OVERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo overrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } + + if (hpdi_board_status & RX_UNDERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo underrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } + + if (devpriv->dio_count == 0) + async->events |= COMEDI_CB_EOA; + + cfc_handle_events(dev, s); + + return IRQ_HANDLED; +} + +static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel) +{ + struct hpdi_private *devpriv = dev->private; + unsigned long flags; + + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); + + plx9080_abort_dma(devpriv->plx9080_mmio, channel); + + spin_unlock_irqrestore(&dev->spinlock, flags); +} + +static int gsc_hpdi_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct hpdi_private *devpriv = dev->private; + + writel(0, devpriv->mmio + BOARD_CONTROL_REG); + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); + + gsc_hpdi_abort_dma(dev, 0); + + return 0; +} + +static int gsc_hpdi_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct hpdi_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned long flags; + uint32_t bits; + + if (s->io_bits) + return -EINVAL; + + writel(RX_FIFO_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + + gsc_hpdi_abort_dma(dev, 0); + + devpriv->dma_desc_index = 0; + + /* + * These register are supposedly unused during chained dma, + * but I have found that left over values from last operation + * occasionally cause problems with transfer of first dma + * block. Initializing them to zero seems to fix the problem. + */ + writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG); + + /* give location of first dma descriptor */ + bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | + PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; + writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG); + + /* enable dma transfer */ + spin_lock_irqsave(&dev->spinlock, flags); + writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + + if (cmd->stop_src == TRIG_COUNT) + devpriv->dio_count = cmd->stop_arg; + else + devpriv->dio_count = 1; + + /* clear over/under run status flags */ + writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, + devpriv->mmio + BOARD_STATUS_REG); + + /* enable interrupts */ + writel(RX_FULL_INTR, devpriv->mmio + INTERRUPT_CONTROL_REG); + + writel(RX_ENABLE_BIT, devpriv->mmio + BOARD_CONTROL_REG); + + return 0; +} + +static int gsc_hpdi_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + int i; + + if (s->io_bits) + return -EINVAL; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + if (!cmd->chanlist_len || !cmd->chanlist) { + cmd->chanlist_len = 32; + err |= -EINVAL; + } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + if (err) + return 4; + + /* step 5: complain about special chanlist considerations */ + + for (i = 0; i < cmd->chanlist_len; i++) { + if (CR_CHAN(cmd->chanlist[i]) != i) { + /* XXX could support 8 or 16 channels */ + dev_err(dev->class_dev, + "chanlist must be ch 0 to 31 in order"); + err |= -EINVAL; + break; + } + } + + if (err) + return 5; + + return 0; + +} + +/* setup dma descriptors so a link completes every 'len' bytes */ +static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, + unsigned int len) +{ + struct hpdi_private *devpriv = dev->private; + dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; + uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | + PLX_XFER_LOCAL_TO_PCI; + unsigned int offset = 0; + unsigned int idx = 0; + unsigned int i; + + if (len > DMA_BUFFER_SIZE) + len = DMA_BUFFER_SIZE; + len -= len % sizeof(uint32_t); + if (len == 0) + return -EINVAL; + + for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) { + devpriv->dma_desc[i].pci_start_addr = + cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset); + devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); + devpriv->dma_desc[i].transfer_size = cpu_to_le32(len); + devpriv->dma_desc[i].next = cpu_to_le32((phys_addr + + (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); + + devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + + (offset / sizeof(uint32_t)); + + offset += len; + if (len + offset > DMA_BUFFER_SIZE) { + offset = 0; + idx++; + } + } + devpriv->num_dma_descriptors = i; + /* fix last descriptor to point back to first */ + devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits); + + devpriv->block_size = len; + + return len; +} + +static int gsc_hpdi_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { int ret; switch (data[0]) { case INSN_CONFIG_BLOCK_SIZE: - return dio_config_block_size(dev, data); + ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]); + if (ret) + return ret; + + data[1] = ret; + break; default: ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff); if (ret) @@ -237,31 +499,53 @@ static int dio_config_insn(struct comedi_device *dev, return insn->n; } -static void disable_plx_interrupts(struct comedi_device *dev) +static int gsc_hpdi_init(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; + uint32_t plx_intcsr_bits; + + /* wait 10usec after reset before accessing fifos */ + writel(BOARD_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + udelay(10); + + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + RX_PROG_ALMOST_REG); + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + TX_PROG_ALMOST_REG); - writel(0, devpriv->plx9080_iobase + PLX_INTRCS_REG); + devpriv->tx_fifo_size = readl(devpriv->mmio + TX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + devpriv->rx_fifo_size = readl(devpriv->mmio + RX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); + + /* enable interrupts */ + plx_intcsr_bits = + ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | + ICS_DMA0_E; + writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG); + + return 0; } -/* initialize plx9080 chip */ -static void init_plx9080(struct comedi_device *dev) +static void gsc_hpdi_init_plx9080(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; uint32_t bits; - void __iomem *plx_iobase = devpriv->plx9080_iobase; + void __iomem *plx_iobase = devpriv->plx9080_mmio; #ifdef __BIG_ENDIAN bits = BIGEND_DMA0 | BIGEND_DMA1; #else bits = 0; #endif - writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG); + writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG); - disable_plx_interrupts(dev); + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); - abort_dma(dev, 0); - abort_dma(dev, 1); + gsc_hpdi_abort_dma(dev, 0); + gsc_hpdi_abort_dma(dev, 1); /* configure dma0 mode */ bits = 0; @@ -285,117 +569,7 @@ static void init_plx9080(struct comedi_device *dev) writel(bits, plx_iobase + PLX_DMA0_MODE_REG); } -/* Allocate and initialize the subdevice structures. - */ -static int setup_subdevices(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int ret; - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; - - s = &dev->subdevices[0]; - /* analog input subdevice */ - dev->read_subdev = s; -/* dev->write_subdev = s; */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | SDF_CMD_READ; - s->n_chan = 32; - s->len_chanlist = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = dio_config_insn; - s->do_cmd = hpdi_cmd; - s->do_cmdtest = hpdi_cmd_test; - s->cancel = hpdi_cancel; - - return 0; -} - -static int init_hpdi(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; - uint32_t plx_intcsr_bits; - - writel(BOARD_RESET_BIT, devpriv->hpdi_iobase + BOARD_CONTROL_REG); - udelay(10); - - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + RX_PROG_ALMOST_REG); - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + TX_PROG_ALMOST_REG); - - devpriv->tx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - TX_FIFO_SIZE_REG)); - devpriv->rx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - RX_FIFO_SIZE_REG)); - - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - /* enable interrupts */ - plx_intcsr_bits = - ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | - ICS_DMA0_E; - writel(plx_intcsr_bits, devpriv->plx9080_iobase + PLX_INTRCS_REG); - - return 0; -} - -/* setup dma descriptors so a link completes every 'transfer_size' bytes */ -static int setup_dma_descriptors(struct comedi_device *dev, - unsigned int transfer_size) -{ - struct hpdi_private *devpriv = dev->private; - unsigned int buffer_index, buffer_offset; - uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI; - unsigned int i; - - if (transfer_size > DMA_BUFFER_SIZE) - transfer_size = DMA_BUFFER_SIZE; - transfer_size -= transfer_size % sizeof(uint32_t); - if (transfer_size == 0) - return -1; - - buffer_offset = 0; - buffer_index = 0; - for (i = 0; i < NUM_DMA_DESCRIPTORS && - buffer_index < NUM_DMA_BUFFERS; i++) { - devpriv->dma_desc[i].pci_start_addr = - cpu_to_le32(devpriv->dio_buffer_phys_addr[buffer_index] + - buffer_offset); - devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); - devpriv->dma_desc[i].transfer_size = - cpu_to_le32(transfer_size); - devpriv->dma_desc[i].next = - cpu_to_le32((devpriv->dma_desc_phys_addr + (i + - 1) * - sizeof(devpriv->dma_desc[0])) | next_bits); - - devpriv->desc_dio_buffer[i] = - devpriv->dio_buffer[buffer_index] + - (buffer_offset / sizeof(uint32_t)); - - buffer_offset += transfer_size; - if (transfer_size + buffer_offset > DMA_BUFFER_SIZE) { - buffer_offset = 0; - buffer_index++; - } - } - devpriv->num_dma_descriptors = i; - /* fix last descriptor to point back to first */ - devpriv->dma_desc[i - 1].next = - cpu_to_le32(devpriv->dma_desc_phys_addr | next_bits); - - devpriv->block_size = transfer_size; - - return transfer_size; -} - -static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev) +static const struct hpdi_board *gsc_hpdi_find_board(struct pci_dev *pcidev) { unsigned int i; @@ -406,16 +580,17 @@ static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev) return NULL; } -static int hpdi_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int gsc_hpdi_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct hpdi_board *thisboard; struct hpdi_private *devpriv; + struct comedi_subdevice *s; int i; int retval; - thisboard = hpdi_find_board(pcidev); + thisboard = gsc_hpdi_find_board(pcidev); if (!thisboard) { dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n", pci_name(pcidev)); @@ -433,17 +608,17 @@ static int hpdi_auto_attach(struct comedi_device *dev, return retval; pci_set_master(pcidev); - devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0); - devpriv->hpdi_iobase = pci_ioremap_bar(pcidev, 2); - if (!devpriv->plx9080_iobase || !devpriv->hpdi_iobase) { + devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0); + devpriv->mmio = pci_ioremap_bar(pcidev, 2); + if (!devpriv->plx9080_mmio || !devpriv->mmio) { dev_warn(dev->class_dev, "failed to remap io memory\n"); return -ENOMEM; } - init_plx9080(dev); + gsc_hpdi_init_plx9080(dev); /* get irq */ - if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, + if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED, dev->board_name, dev)) { dev_warn(dev->class_dev, "unable to allocate irq %u\n", pcidev->irq); @@ -470,18 +645,33 @@ static int hpdi_auto_attach(struct comedi_device *dev, return -EIO; } - retval = setup_dma_descriptors(dev, 0x1000); + retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000); if (retval < 0) return retval; - retval = setup_subdevices(dev); - if (retval < 0) + retval = comedi_alloc_subdevices(dev, 1); + if (retval) return retval; - return init_hpdi(dev); + /* Digital I/O subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | + SDF_CMD_READ; + s->n_chan = 32; + s->len_chanlist = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = gsc_hpdi_dio_insn_config; + s->do_cmd = gsc_hpdi_cmd; + s->do_cmdtest = gsc_hpdi_cmd_test; + s->cancel = gsc_hpdi_cancel; + + return gsc_hpdi_init(dev); } -static void hpdi_detach(struct comedi_device *dev) +static void gsc_hpdi_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct hpdi_private *devpriv = dev->private; @@ -490,12 +680,12 @@ static void hpdi_detach(struct comedi_device *dev) if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { - if (devpriv->plx9080_iobase) { - disable_plx_interrupts(dev); - iounmap(devpriv->plx9080_iobase); + if (devpriv->plx9080_mmio) { + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + iounmap(devpriv->plx9080_mmio); } - if (devpriv->hpdi_iobase) - iounmap(devpriv->hpdi_iobase); + if (devpriv->mmio) + iounmap(devpriv->mmio); /* free pci dma buffers */ for (i = 0; i < NUM_DMA_BUFFERS; i++) { if (devpriv->dio_buffer[i]) @@ -516,318 +706,11 @@ static void hpdi_detach(struct comedi_device *dev) comedi_pci_disable(dev); } -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data) -{ - unsigned int requested_block_size; - int retval; - - requested_block_size = data[1]; - - retval = setup_dma_descriptors(dev, requested_block_size); - if (retval < 0) - return retval; - - data[1] = retval; - - return 2; -} - -static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int i; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - if (!cmd->chanlist_len) { - cmd->chanlist_len = 32; - err |= -EINVAL; - } - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - switch (cmd->stop_src) { - case TRIG_COUNT: - err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); - break; - case TRIG_NONE: - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (err) - return 4; - - if (!cmd->chanlist) - return 0; - - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - /* XXX could support 8 or 16 channels */ - comedi_error(dev, - "chanlist must be ch 0 to 31 in order"); - err++; - break; - } - } - - if (err) - return 5; - - return 0; -} - -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - if (s->io_bits) - return -EINVAL; - else - return di_cmd_test(dev, s, cmd); -} - -static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits, - unsigned int offset) -{ - struct hpdi_private *devpriv = dev->private; - - writel(bits | devpriv->bits[offset / sizeof(uint32_t)], - devpriv->hpdi_iobase + offset); -} - -static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct hpdi_private *devpriv = dev->private; - uint32_t bits; - unsigned long flags; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - - hpdi_writel(dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG); - - abort_dma(dev, 0); - - devpriv->dma_desc_index = 0; - - /* These register are supposedly unused during chained dma, - * but I have found that left over values from last operation - * occasionally cause problems with transfer of first dma - * block. Initializing them to zero seems to fix the problem. */ - writel(0, devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); - /* give location of first dma descriptor */ - bits = - devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; - writel(bits, devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - /* enable dma transfer */ - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - if (cmd->stop_src == TRIG_COUNT) - devpriv->dio_count = cmd->stop_arg; - else - devpriv->dio_count = 1; - - /* clear over/under run status flags */ - writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, - devpriv->hpdi_iobase + BOARD_STATUS_REG); - /* enable interrupts */ - writel(intr_bit(RX_FULL_INTR), - devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - hpdi_writel(dev, RX_ENABLE_BIT, BOARD_CONTROL_REG); - - return 0; -} - -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s->io_bits) - return -EINVAL; - else - return di_cmd(dev, s); -} - -static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - struct comedi_async *async = dev->read_subdev->async; - uint32_t next_transfer_addr; - int j; - int num_samples = 0; - void __iomem *pci_addr_reg; - - if (channel) - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; - else - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - - /* loop until we have read all the full buffers */ - j = 0; - for (next_transfer_addr = readl(pci_addr_reg); - (next_transfer_addr < - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) - || next_transfer_addr >= - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) + devpriv->block_size) - && j < devpriv->num_dma_descriptors; j++) { - /* transfer data from dma buffer to comedi buffer */ - num_samples = devpriv->block_size / sizeof(uint32_t); - if (async->cmd.stop_src == TRIG_COUNT) { - if (num_samples > devpriv->dio_count) - num_samples = devpriv->dio_count; - devpriv->dio_count -= num_samples; - } - cfc_write_array_to_buffer(dev->read_subdev, - devpriv->desc_dio_buffer[devpriv-> - dma_desc_index], - num_samples * sizeof(uint32_t)); - devpriv->dma_desc_index++; - devpriv->dma_desc_index %= devpriv->num_dma_descriptors; - } - /* XXX check for buffer overrun somehow */ -} - -static irqreturn_t handle_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct hpdi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - uint32_t hpdi_intr_status, hpdi_board_status; - uint32_t plx_status; - uint32_t plx_bits; - uint8_t dma0_status, dma1_status; - unsigned long flags; - - if (!dev->attached) - return IRQ_NONE; - - plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG); - if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) - return IRQ_NONE; - - hpdi_intr_status = readl(devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - hpdi_board_status = readl(devpriv->hpdi_iobase + BOARD_STATUS_REG); - - async->events = 0; - - if (hpdi_intr_status) { - writel(hpdi_intr_status, - devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - } - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ - writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - - if (dma0_status & PLX_DMA_EN_BIT) - drain_dma_buffers(dev, 0); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* clear possible plx9080 interrupt sources */ - if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - } - - if (hpdi_board_status & RX_OVERRUN_BIT) { - comedi_error(dev, "rx fifo overrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - } - - if (hpdi_board_status & RX_UNDERRUN_BIT) { - comedi_error(dev, "rx fifo underrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - } - - if (devpriv->dio_count == 0) - async->events |= COMEDI_CB_EOA; - - cfc_handle_events(dev, s); - - return IRQ_HANDLED; -} - -static void abort_dma(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - unsigned long flags; - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - - plx9080_abort_dma(devpriv->plx9080_iobase, channel); - - spin_unlock_irqrestore(&dev->spinlock, flags); -} - -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct hpdi_private *devpriv = dev->private; - - hpdi_writel(dev, 0, BOARD_CONTROL_REG); - - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - abort_dma(dev, 0); - - return 0; -} - static struct comedi_driver gsc_hpdi_driver = { .driver_name = "gsc_hpdi", .module = THIS_MODULE, - .auto_attach = hpdi_auto_attach, - .detach = hpdi_detach, + .auto_attach = gsc_hpdi_auto_attach, + .detach = gsc_hpdi_detach, }; static int gsc_hpdi_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 80539b2bea1a..0b8b2162b76b 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -171,12 +171,27 @@ static void setup_channel_list(struct comedi_device *dev, } } +static int icp_multi_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_ADC_CSR); + if ((status & ADC_BSY) == 0) + return 0; + return -EBUSY; +} + static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, timeout; + int ret = 0; + int n; /* Disable A/D conversion ready interrupt */ devpriv->IntEnable &= ~ADC_READY; @@ -199,33 +214,10 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, udelay(1); /* Wait for conversion to complete, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_ADC_CSR) & ADC_BSY)) - goto conv_finish; - - udelay(1); - } - - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "A/D insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); + ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0); + if (ret) + break; - /* Clear data received */ - data[n] = 0; - - return -ETIME; - -conv_finish: data[n] = (readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff; } @@ -238,7 +230,21 @@ conv_finish: devpriv->IntStatus |= ADC_READY; writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); - return n; + return ret ? ret : n; +} + +static int icp_multi_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_DAC_CSR); + if ((status & DAC_BSY) == 0) + return 0; + return -EBUSY; } static int icp_multi_insn_write_ao(struct comedi_device *dev, @@ -246,7 +252,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, chan, range, timeout; + int n, chan, range; + int ret; /* Disable D/A conversion ready interrupt */ devpriv->IntEnable &= ~DAC_READY; @@ -274,33 +281,24 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* Wait for analogue output data register to be * ready for new data, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_DAC_CSR) & DAC_BSY)) - goto dac_ready; - - udelay(1); + ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0); + if (ret) { + /* Disable interrupt */ + devpriv->IntEnable &= ~DAC_READY; + writew(devpriv->IntEnable, + devpriv->io_addr + ICP_MULTI_INT_EN); + + /* Clear interrupt status */ + devpriv->IntStatus |= DAC_READY; + writew(devpriv->IntStatus, + devpriv->io_addr + ICP_MULTI_INT_STAT); + + /* Clear data received */ + devpriv->ao_data[chan] = 0; + + return ret; } - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "D/A insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); - - /* Clear data received */ - devpriv->ao_data[chan] = 0; - - return -ETIME; - -dac_ready: /* Write data to analogue output data register */ writew(data[n], devpriv->io_addr + ICP_MULTI_AO); @@ -565,9 +563,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, devpriv->valid = 1; - dev_info(dev->class_dev, "%s attached, irq %sabled\n", - dev->board_name, dev->irq ? "en" : "dis"); - return 0; } diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 8577778441fa..3558ab3b6e1f 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -190,20 +190,18 @@ static int ii20k_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int ii20k_ai_wait_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - int timeout) +static int ii20k_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { void __iomem *iobase = ii20k_module_iobase(dev, s); unsigned char status; - do { - status = readb(iobase + II20K_AI_STATUS_REG); - if ((status & II20K_AI_STATUS_INT) == 0) - return 0; - } while (timeout--); - - return -ETIME; + status = readb(iobase + II20K_AI_STATUS_REG); + if ((status & II20K_AI_STATUS_INT) == 0) + return 0; + return -EBUSY; } static void ii20k_ai_setup(struct comedi_device *dev, @@ -263,7 +261,7 @@ static int ii20k_ai_insn_read(struct comedi_device *dev, /* generate a software start convert signal */ readb(iobase + II20K_AI_PACER_RESET_REG); - ret = ii20k_ai_wait_eoc(dev, s, 100); + ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 6100c12c164f..a8db9d86aadc 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -51,23 +51,55 @@ #include "jr3_pci.h" #define PCI_VENDOR_ID_JR3 0x1762 -#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111 -#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111 -#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112 -#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 -#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 -struct jr3_pci_dev_private { - struct jr3_t __iomem *iobase; - int n_channels; - struct timer_list timer; +enum jr3_pci_boardid { + BOARD_JR3_1, + BOARD_JR3_2, + BOARD_JR3_3, + BOARD_JR3_4, }; -struct poll_delay_t { +struct jr3_pci_board { + const char *name; + int n_subdevs; +}; + +static const struct jr3_pci_board jr3_pci_boards[] = { + [BOARD_JR3_1] = { + .name = "jr3_pci_1", + .n_subdevs = 1, + }, + [BOARD_JR3_2] = { + .name = "jr3_pci_2", + .n_subdevs = 2, + }, + [BOARD_JR3_3] = { + .name = "jr3_pci_3", + .n_subdevs = 3, + }, + [BOARD_JR3_4] = { + .name = "jr3_pci_4", + .n_subdevs = 4, + }, +}; + +struct jr3_pci_transform { + struct { + u16 link_type; + s16 link_amount; + } link[8]; +}; + +struct jr3_pci_poll_delay { int min; int max; }; +struct jr3_pci_dev_private { + struct jr3_t __iomem *iobase; + struct timer_list timer; +}; + struct jr3_pci_subdev_private { struct jr3_channel __iomem *channel; unsigned long next_time_min; @@ -79,7 +111,6 @@ struct jr3_pci_subdev_private { state_jr3_init_use_offset_complete, state_jr3_done } state; - int channel_no; int serial_no; int model_no; struct { @@ -92,9 +123,9 @@ struct jr3_pci_subdev_private { int retries; }; -static struct poll_delay_t poll_delay_min_max(int min, int max) +static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max) { - struct poll_delay_t result; + struct jr3_pci_poll_delay result; result.min = min; result.max = max; @@ -106,15 +137,8 @@ static int is_complete(struct jr3_channel __iomem *channel) return get_s16(&channel->command_word0) == 0; } -struct transform_t { - struct { - u16 link_type; - s16 link_amount; - } link[8]; -}; - static void set_transforms(struct jr3_channel __iomem *channel, - struct transform_t transf, short num) + struct jr3_pci_transform transf, short num) { int i; @@ -194,110 +218,99 @@ static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem return result; } +static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int val = 0; + + if (spriv->state != state_jr3_done) + return 0; + + if (chan < 56) { + unsigned int axis = chan % 8; + unsigned filter = chan / 8; + + switch (axis) { + case 0: + val = get_s16(&spriv->channel->filter[filter].fx); + break; + case 1: + val = get_s16(&spriv->channel->filter[filter].fy); + break; + case 2: + val = get_s16(&spriv->channel->filter[filter].fz); + break; + case 3: + val = get_s16(&spriv->channel->filter[filter].mx); + break; + case 4: + val = get_s16(&spriv->channel->filter[filter].my); + break; + case 5: + val = get_s16(&spriv->channel->filter[filter].mz); + break; + case 6: + val = get_s16(&spriv->channel->filter[filter].v1); + break; + case 7: + val = get_s16(&spriv->channel->filter[filter].v2); + break; + } + val += 0x4000; + } else if (chan == 56) { + val = get_u16(&spriv->channel->model_no); + } else if (chan == 57) { + val = get_u16(&spriv->channel->serial_no); + } + + return val; +} + static int jr3_pci_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int result; - struct jr3_pci_subdev_private *p; - int channel; - - p = s->private; - channel = CR_CHAN(insn->chanspec); - if (p == NULL || channel > 57) { - result = -EINVAL; - } else { - int i; - - result = insn->n; - if (p->state != state_jr3_done || - (get_u16(&p->channel->errors) & (watch_dog | watch_dog2 | - sensor_change))) { - /* No sensor or sensor changed */ - if (p->state == state_jr3_done) { - /* Restart polling */ - p->state = state_jr3_poll; - } - result = -EAGAIN; - } - for (i = 0; i < insn->n; i++) { - if (channel < 56) { - int axis, filter; - - axis = channel % 8; - filter = channel / 8; - if (p->state != state_jr3_done) { - data[i] = 0; - } else { - int F = 0; - switch (axis) { - case 0: - F = get_s16(&p->channel-> - filter[filter].fx); - break; - case 1: - F = get_s16(&p->channel-> - filter[filter].fy); - break; - case 2: - F = get_s16(&p->channel-> - filter[filter].fz); - break; - case 3: - F = get_s16(&p->channel-> - filter[filter].mx); - break; - case 4: - F = get_s16(&p->channel-> - filter[filter].my); - break; - case 5: - F = get_s16(&p->channel-> - filter[filter].mz); - break; - case 6: - F = get_s16(&p->channel-> - filter[filter].v1); - break; - case 7: - F = get_s16(&p->channel-> - filter[filter].v2); - break; - } - data[i] = F + 0x4000; - } - } else if (channel == 56) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->model_no); - } else if (channel == 57) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->serial_no); - } + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + u16 errors; + int i; + + if (!spriv) + return -EINVAL; + + errors = get_u16(&spriv->channel->errors); + if (spriv->state != state_jr3_done || + (errors & (watch_dog | watch_dog2 | sensor_change))) { + /* No sensor or sensor changed */ + if (spriv->state == state_jr3_done) { + /* Restart polling */ + spriv->state = state_jr3_poll; } + return -EAGAIN; } - return result; + + for (i = 0; i < insn->n; i++) + data[i] = jr3_pci_ai_read_chan(dev, s, chan); + + return insn->n; } static int jr3_pci_open(struct comedi_device *dev) { + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; int i; - struct jr3_pci_dev_private *devpriv = dev->private; dev_dbg(dev->class_dev, "jr3_pci_open\n"); - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p; - - p = dev->subdevices[i].private; - if (p) { - dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", p, - p->serial_no, p->channel_no); - } + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + if (spriv) + dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", + spriv, spriv->serial_no, s->index); } return 0; } @@ -326,271 +339,262 @@ static int read_idm_word(const u8 *data, size_t size, int *pos, return result; } -static int jr3_download_firmware(struct comedi_device *dev, - const u8 *data, size_t size, - unsigned long context) +static int jr3_check_firmware(struct comedi_device *dev, + const u8 *data, size_t size) { + int more = 1; + int pos = 0; + /* * IDM file format is: * { count, address, data <count> } * * ffff */ - int result, more, pos, OK; - - result = 0; - more = 1; - pos = 0; - OK = 0; while (more) { - unsigned int count, addr; + unsigned int count = 0; + unsigned int addr = 0; more = more && read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) { - OK = 1; - break; - } + if (more && count == 0xffff) + return 0; + more = more && read_idm_word(data, size, &pos, &addr); while (more && count > 0) { - unsigned int dummy; + unsigned int dummy = 0; + more = more && read_idm_word(data, size, &pos, &dummy); count--; } } - if (!OK) { - result = -ENODATA; - } else { - int i; - struct jr3_pci_dev_private *p = dev->private; + return -ENODATA; +} + +static void jr3_write_firmware(struct comedi_device *dev, + int subdev, const u8 *data, size_t size) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_t __iomem *iobase = devpriv->iobase; + u32 __iomem *lo; + u32 __iomem *hi; + int more = 1; + int pos = 0; + + while (more) { + unsigned int count = 0; + unsigned int addr = 0; + + more = more && read_idm_word(data, size, &pos, &count); + if (more && count == 0xffff) + return; + + more = more && read_idm_word(data, size, &pos, &addr); + + dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n", + subdev, count, addr); + + while (more && count > 0) { + if (addr & 0x4000) { + /* 16 bit data, never seen in real life!! */ + unsigned int data1 = 0; - for (i = 0; i < p->n_channels; i++) { - struct jr3_pci_subdev_private *sp; + more = more && + read_idm_word(data, size, &pos, &data1); + count--; + /* jr3[addr + 0x20000 * pnum] = data1; */ + } else { + /* Download 24 bit program */ + unsigned int data1 = 0; + unsigned int data2 = 0; + + lo = &iobase->channel[subdev].program_lo[addr]; + hi = &iobase->channel[subdev].program_hi[addr]; - sp = dev->subdevices[i].private; - more = 1; - pos = 0; - while (more) { - unsigned int count, addr; more = more && - read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) - break; + read_idm_word(data, size, &pos, &data1); more = more && - read_idm_word(data, size, &pos, &addr); - dev_dbg(dev->class_dev, - "Loading#%d %4.4x bytes at %4.4x\n", - i, count, addr); - while (more && count > 0) { - if (addr & 0x4000) { - /* 16 bit data, never seen - * in real life!! */ - unsigned int data1; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - count--; - /* jr3[addr + 0x20000 * pnum] = - data1; */ - } else { - /* Download 24 bit program */ - unsigned int data1, data2; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - more = more && - read_idm_word(data, size, - &pos, - &data2); - count -= 2; - if (more) { - set_u16(&p-> - iobase->channel - [i].program_low - [addr], data1); - udelay(1); - set_u16(&p-> - iobase->channel - [i].program_high - [addr], data2); - udelay(1); - } - } - addr++; + read_idm_word(data, size, &pos, &data2); + count -= 2; + if (more) { + set_u16(lo, data1); + udelay(1); + set_u16(hi, data2); + udelay(1); } } + addr++; } } - return result; } -static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s) +static int jr3_download_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { - struct poll_delay_t result = poll_delay_min_max(1000, 2000); - struct jr3_pci_subdev_private *p = s->private; - int i; + int subdev; + int ret; - if (p) { - struct jr3_channel __iomem *channel = p->channel; - int errors = get_u16(&channel->errors); - - if (errors != p->errors) - p->errors = errors; - - if (errors & (watch_dog | watch_dog2 | sensor_change)) - /* Sensor communication lost, force poll mode */ - p->state = state_jr3_poll; - - switch (p->state) { - case state_jr3_poll: { - u16 model_no = get_u16(&channel->model_no); - u16 serial_no = get_u16(&channel->serial_no); - if ((errors & (watch_dog | watch_dog2)) || - model_no == 0 || serial_no == 0) { - /* - * Still no sensor, keep on polling. - * Since it takes up to 10 seconds - * for offsets to stabilize, polling - * each second should suffice. - */ - result = poll_delay_min_max(1000, 2000); - } else { - p->retries = 0; - p->state = - state_jr3_init_wait_for_offset; - result = poll_delay_min_max(1000, 2000); - } - } - break; - case state_jr3_init_wait_for_offset: - p->retries++; - if (p->retries < 10) { - /* Wait for offeset to stabilize - * (< 10 s according to manual) */ - result = poll_delay_min_max(1000, 2000); - } else { - struct transform_t transf; + /* verify IDM file format */ + ret = jr3_check_firmware(dev, data, size); + if (ret) + return ret; - p->model_no = get_u16(&channel->model_no); - p->serial_no = get_u16(&channel->serial_no); + /* write firmware to each subdevice */ + for (subdev = 0; subdev < dev->n_subdevices; subdev++) + jr3_write_firmware(dev, subdev, data, size); - /* Transformation all zeros */ - for (i = 0; i < ARRAY_SIZE(transf.link); i++) { - transf.link[i].link_type = - (enum link_types)0; - transf.link[i].link_amount = 0; - } + return 0; +} - set_transforms(channel, transf, 0); - use_transform(channel, 0); - p->state = state_jr3_init_transform_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_transform_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - /* Set full scale */ - struct six_axis_t min_full_scale; - struct six_axis_t max_full_scale; - - min_full_scale = get_min_full_scales(channel); - max_full_scale = get_max_full_scales(channel); - set_full_scales(channel, max_full_scale); - - p->state = - state_jr3_init_set_full_scale_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_set_full_scale_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - struct force_array __iomem *full_scale; - - /* Use ranges in kN or we will - * overflow around 2000N! */ - full_scale = &channel->full_scale; - p->range[0].range.min = - -get_s16(&full_scale->fx) * 1000; - p->range[0].range.max = - get_s16(&full_scale->fx) * 1000; - p->range[1].range.min = - -get_s16(&full_scale->fy) * 1000; - p->range[1].range.max = - get_s16(&full_scale->fy) * 1000; - p->range[2].range.min = - -get_s16(&full_scale->fz) * 1000; - p->range[2].range.max = - get_s16(&full_scale->fz) * 1000; - p->range[3].range.min = - -get_s16(&full_scale->mx) * 100; - p->range[3].range.max = - get_s16(&full_scale->mx) * 100; - p->range[4].range.min = - -get_s16(&full_scale->my) * 100; - p->range[4].range.max = - get_s16(&full_scale->my) * 100; - p->range[5].range.min = - -get_s16(&full_scale->mz) * 100; - p->range[5].range.max = - get_s16(&full_scale->mz) * 100; /* ?? */ - p->range[6].range.min = - -get_s16(&full_scale->v1) * 100;/* ?? */ - p->range[6].range.max = - get_s16(&full_scale->v1) * 100; /* ?? */ - p->range[7].range.min = - -get_s16(&full_scale->v2) * 100;/* ?? */ - p->range[7].range.max = - get_s16(&full_scale->v2) * 100; /* ?? */ - p->range[8].range.min = 0; - p->range[8].range.max = 65535; - - use_offset(channel, 0); - p->state = state_jr3_init_use_offset_complete; - /* Allow 40 ms for completion */ - result = poll_delay_min_max(40, 100); - } - break; - case state_jr3_init_use_offset_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - set_s16(&channel->offsets.fx, 0); - set_s16(&channel->offsets.fy, 0); - set_s16(&channel->offsets.fz, 0); - set_s16(&channel->offsets.mx, 0); - set_s16(&channel->offsets.my, 0); - set_s16(&channel->offsets.mz, 0); +static struct jr3_pci_poll_delay jr3_pci_poll_subdevice(struct comedi_subdevice *s) +{ + struct jr3_pci_subdev_private *spriv = s->private; + struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000); + struct jr3_channel __iomem *channel; + u16 model_no; + u16 serial_no; + int errors; + int i; - set_offset(channel); + if (!spriv) + return result; - p->state = state_jr3_done; + channel = spriv->channel; + errors = get_u16(&channel->errors); + + if (errors != spriv->errors) + spriv->errors = errors; + + /* Sensor communication lost? force poll mode */ + if (errors & (watch_dog | watch_dog2 | sensor_change)) + spriv->state = state_jr3_poll; + + switch (spriv->state) { + case state_jr3_poll: + model_no = get_u16(&channel->model_no); + serial_no = get_u16(&channel->serial_no); + + if ((errors & (watch_dog | watch_dog2)) || + model_no == 0 || serial_no == 0) { + /* + * Still no sensor, keep on polling. + * Since it takes up to 10 seconds for offsets to + * stabilize, polling each second should suffice. + */ + } else { + spriv->retries = 0; + spriv->state = state_jr3_init_wait_for_offset; + } + break; + case state_jr3_init_wait_for_offset: + spriv->retries++; + if (spriv->retries < 10) { + /* + * Wait for offeset to stabilize + * (< 10 s according to manual) + */ + } else { + struct jr3_pci_transform transf; + + spriv->model_no = get_u16(&channel->model_no); + spriv->serial_no = get_u16(&channel->serial_no); + + /* Transformation all zeros */ + for (i = 0; i < ARRAY_SIZE(transf.link); i++) { + transf.link[i].link_type = (enum link_types)0; + transf.link[i].link_amount = 0; } - break; - case state_jr3_done: - poll_delay_min_max(10000, 20000); - break; - default: - poll_delay_min_max(1000, 2000); - break; + + set_transforms(channel, transf, 0); + use_transform(channel, 0); + spriv->state = state_jr3_init_transform_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_transform_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + /* Set full scale */ + struct six_axis_t min_full_scale; + struct six_axis_t max_full_scale; + + min_full_scale = get_min_full_scales(channel); + max_full_scale = get_max_full_scales(channel); + set_full_scales(channel, max_full_scale); + + spriv->state = state_jr3_init_set_full_scale_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_set_full_scale_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + struct force_array __iomem *fs = &channel->full_scale; + + /* Use ranges in kN or we will overflow around 2000N! */ + spriv->range[0].range.min = -get_s16(&fs->fx) * 1000; + spriv->range[0].range.max = get_s16(&fs->fx) * 1000; + spriv->range[1].range.min = -get_s16(&fs->fy) * 1000; + spriv->range[1].range.max = get_s16(&fs->fy) * 1000; + spriv->range[2].range.min = -get_s16(&fs->fz) * 1000; + spriv->range[2].range.max = get_s16(&fs->fz) * 1000; + spriv->range[3].range.min = -get_s16(&fs->mx) * 100; + spriv->range[3].range.max = get_s16(&fs->mx) * 100; + spriv->range[4].range.min = -get_s16(&fs->my) * 100; + spriv->range[4].range.max = get_s16(&fs->my) * 100; + spriv->range[5].range.min = -get_s16(&fs->mz) * 100; + /* the next five are questionable */ + spriv->range[5].range.max = get_s16(&fs->mz) * 100; + spriv->range[6].range.min = -get_s16(&fs->v1) * 100; + spriv->range[6].range.max = get_s16(&fs->v1) * 100; + spriv->range[7].range.min = -get_s16(&fs->v2) * 100; + spriv->range[7].range.max = get_s16(&fs->v2) * 100; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65535; + + use_offset(channel, 0); + spriv->state = state_jr3_init_use_offset_complete; + /* Allow 40 ms for completion */ + result = poll_delay_min_max(40, 100); + } + break; + case state_jr3_init_use_offset_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + set_s16(&channel->offsets.fx, 0); + set_s16(&channel->offsets.fy, 0); + set_s16(&channel->offsets.fz, 0); + set_s16(&channel->offsets.mx, 0); + set_s16(&channel->offsets.my, 0); + set_s16(&channel->offsets.mz, 0); + + set_offset(channel); + + spriv->state = state_jr3_done; } + break; + case state_jr3_done: + result = poll_delay_min_max(10000, 20000); + break; + default: + break; } + return result; } static void jr3_pci_poll_dev(unsigned long data) { - unsigned long flags; struct comedi_device *dev = (struct comedi_device *)data; struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + unsigned long flags; unsigned long now; int delay; int i; @@ -598,18 +602,22 @@ static void jr3_pci_poll_dev(unsigned long data) spin_lock_irqsave(&dev->spinlock, flags); delay = 1000; now = jiffies; - /* Poll all channels that are ready to be polled */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *subdevpriv = - dev->subdevices[i].private; - if (now > subdevpriv->next_time_min) { - struct poll_delay_t sub_delay; - - sub_delay = jr3_pci_poll_subdevice(&dev->subdevices[i]); - subdevpriv->next_time_min = - jiffies + msecs_to_jiffies(sub_delay.min); - subdevpriv->next_time_max = - jiffies + msecs_to_jiffies(sub_delay.max); + + /* Poll all channels that are ready to be polled */ + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + + if (now > spriv->next_time_min) { + struct jr3_pci_poll_delay sub_delay; + + sub_delay = jr3_pci_poll_subdevice(s); + + spriv->next_time_min = jiffies + + msecs_to_jiffies(sub_delay.min); + spriv->next_time_max = jiffies + + msecs_to_jiffies(sub_delay.max); + if (sub_delay.max && sub_delay.max < delay) /* * Wake up as late as possible -> @@ -624,13 +632,58 @@ static void jr3_pci_poll_dev(unsigned long data) add_timer(&devpriv->timer); } +static struct jr3_pci_subdev_private * +jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + int j; + int k; + + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) + return NULL; + + spriv->channel = &devpriv->iobase->channel[s->index].data; + + for (j = 0; j < 8; j++) { + spriv->range[j].length = 1; + spriv->range[j].range.min = -1000000; + spriv->range[j].range.max = 1000000; + + for (k = 0; k < 7; k++) { + spriv->range_table_list[j + k * 8] = + (struct comedi_lrange *)&spriv->range[j]; + spriv->maxdata_list[j + k * 8] = 0x7fff; + } + } + spriv->range[8].length = 1; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65536; + + spriv->range_table_list[56] = (struct comedi_lrange *)&spriv->range[8]; + spriv->range_table_list[57] = (struct comedi_lrange *)&spriv->range[8]; + spriv->maxdata_list[56] = 0xffff; + spriv->maxdata_list[57] = 0xffff; + + dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", + spriv->channel, devpriv->iobase, + ((char __iomem *)spriv->channel - + (char __iomem *)devpriv->iobase)); + + return spriv; +} + static int jr3_pci_auto_attach(struct comedi_device *dev, - unsigned long context_unused) + unsigned long context) { - int result; struct pci_dev *pcidev = comedi_to_pci_dev(dev); - int i; + static const struct jr3_pci_board *board = NULL; struct jr3_pci_dev_private *devpriv; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + int ret; + int i; if (sizeof(struct jr3_channel) != 0xc00) { dev_err(dev->class_dev, @@ -639,106 +692,56 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, return -EINVAL; } + if (context < ARRAY_SIZE(jr3_pci_boards)) + board = &jr3_pci_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; init_timer(&devpriv->timer); - switch (pcidev->device) { - case PCI_DEVICE_ID_JR3_1_CHANNEL: - case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW: - devpriv->n_channels = 1; - break; - case PCI_DEVICE_ID_JR3_2_CHANNEL: - devpriv->n_channels = 2; - break; - case PCI_DEVICE_ID_JR3_3_CHANNEL: - devpriv->n_channels = 3; - break; - case PCI_DEVICE_ID_JR3_4_CHANNEL: - devpriv->n_channels = 4; - break; - default: - dev_err(dev->class_dev, "jr3_pci: pci %s not supported\n", - pci_name(pcidev)); - return -EINVAL; - break; - } - result = comedi_pci_enable(dev); - if (result) - return result; + ret = comedi_pci_enable(dev); + if (ret) + return ret; devpriv->iobase = pci_ioremap_bar(pcidev, 0); if (!devpriv->iobase) return -ENOMEM; - result = comedi_alloc_subdevices(dev, devpriv->n_channels); - if (result) - return result; + ret = comedi_alloc_subdevices(dev, board->n_subdevs); + if (ret) + return ret; dev->open = jr3_pci_open; - for (i = 0; i < devpriv->n_channels; i++) { - dev->subdevices[i].type = COMEDI_SUBD_AI; - dev->subdevices[i].subdev_flags = SDF_READABLE | SDF_GROUND; - dev->subdevices[i].n_chan = 8 * 7 + 2; - dev->subdevices[i].insn_read = jr3_pci_ai_insn_read; - dev->subdevices[i].private = - kzalloc(sizeof(struct jr3_pci_subdev_private), - GFP_KERNEL); - if (dev->subdevices[i].private) { - struct jr3_pci_subdev_private *p; - int j; - - p = dev->subdevices[i].private; - p->channel = &devpriv->iobase->channel[i].data; - dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", - p->channel, devpriv->iobase, - ((char __iomem *)p->channel - - (char __iomem *)devpriv->iobase)); - p->channel_no = i; - for (j = 0; j < 8; j++) { - int k; - - p->range[j].length = 1; - p->range[j].range.min = -1000000; - p->range[j].range.max = 1000000; - for (k = 0; k < 7; k++) { - p->range_table_list[j + k * 8] = - (struct comedi_lrange *)&p-> - range[j]; - p->maxdata_list[j + k * 8] = 0x7fff; - } - } - p->range[8].length = 1; - p->range[8].range.min = 0; - p->range[8].range.max = 65536; - - p->range_table_list[56] = - (struct comedi_lrange *)&p->range[8]; - p->range_table_list[57] = - (struct comedi_lrange *)&p->range[8]; - p->maxdata_list[56] = 0xffff; - p->maxdata_list[57] = 0xffff; - /* Channel specific range and maxdata */ - dev->subdevices[i].range_table = NULL; - dev->subdevices[i].range_table_list = - p->range_table_list; - dev->subdevices[i].maxdata = 0; - dev->subdevices[i].maxdata_list = p->maxdata_list; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8 * 7 + 2; + s->insn_read = jr3_pci_ai_insn_read; + + spriv = jr3_pci_alloc_spriv(dev, s); + if (spriv) { + /* Channel specific range and maxdata */ + s->range_table_list = spriv->range_table_list; + s->maxdata_list = spriv->maxdata_list; } } /* Reset DSP card */ writel(0, &devpriv->iobase->channel[0].reset); - result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, - "comedi/jr3pci.idm", - jr3_download_firmware, 0); - dev_dbg(dev->class_dev, "Firmare load %d\n", result); - - if (result < 0) - return result; + ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + "comedi/jr3pci.idm", + jr3_download_firmware, 0); + dev_dbg(dev->class_dev, "Firmare load %d\n", ret); + if (ret < 0) + return ret; /* * TODO: use firmware to load preferred offset tables. Suggested * format: @@ -761,11 +764,12 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, } /* Start card timer */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p = dev->subdevices[i].private; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; - p->next_time_min = jiffies + msecs_to_jiffies(500); - p->next_time_max = jiffies + msecs_to_jiffies(2000); + spriv->next_time_min = jiffies + msecs_to_jiffies(500); + spriv->next_time_max = jiffies + msecs_to_jiffies(2000); } devpriv->timer.data = (unsigned long)dev; @@ -773,21 +777,16 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, devpriv->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&devpriv->timer); - return result; + return 0; } static void jr3_pci_detach(struct comedi_device *dev) { - int i; struct jr3_pci_dev_private *devpriv = dev->private; if (devpriv) { del_timer_sync(&devpriv->timer); - if (dev->subdevices) { - for (i = 0; i < devpriv->n_channels; i++) - kfree(dev->subdevices[i].private); - } if (devpriv->iobase) iounmap(devpriv->iobase); } @@ -808,11 +807,11 @@ static int jr3_pci_pci_probe(struct pci_dev *dev, } static const struct pci_device_id jr3_pci_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) }, + { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, + { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, + { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, { 0 } }; MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index 3317f7a04c48..20478ae8fad6 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.h +++ b/drivers/staging/comedi/drivers/jr3_pci.h @@ -671,11 +671,11 @@ struct jr3_channel { struct jr3_t { struct { - u32 program_low[0x4000]; /* 0x00000 - 0x10000 */ + u32 program_lo[0x4000]; /* 0x00000 - 0x10000 */ struct jr3_channel data; /* 0x10000 - 0x10c00 */ char pad2[0x30000 - 0x00c00]; /* 0x10c00 - 0x40000 */ - u32 program_high[0x8000]; /* 0x40000 - 0x60000 */ - u32 reset; /* 0x60000 - 0x60004 */ + u32 program_hi[0x8000]; /* 0x40000 - 0x60000 */ + u32 reset; /* 0x60000 - 0x60004 */ char pad3[0x20000 - 0x00004]; /* 0x60004 - 0x80000 */ } channel[4]; }; diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 6b9846fd8c48..ec43c38958de 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -1,92 +1,113 @@ /* - comedi/drivers/ke_counter.c - Comedi driver for Kolter-Electronic PCI Counter 1 Card - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ke_counter -Description: Driver for Kolter Electronic Counter Card -Devices: [Kolter Electronic] PCI Counter Card (ke_counter) -Author: Michael Hillmann -Updated: Mon, 14 Apr 2008 15:42:42 +0100 -Status: tested - -Configuration Options: not applicable, uses PCI auto config + * ke_counter.c + * Comedi driver for Kolter-Electronic PCI Counter 1 Card + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -This driver is a simple driver to read the counter values from -Kolter Electronic PCI Counter Card. -*/ +/* + * Driver: ke_counter + * Description: Driver for Kolter Electronic Counter Card + * Devices: (Kolter Electronic) PCI Counter Card [ke_counter] + * Author: Michael Hillmann + * Updated: Mon, 14 Apr 2008 15:42:42 +0100 + * Status: tested + * + * Configuration Options: not applicable, uses PCI auto config + */ #include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" -#define CNT_CARD_DEVICE_ID 0x0014 +/* + * PCI BAR 0 Register I/O map + */ +#define KE_RESET_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LSB_REG(x) (0x04 + ((x) * 0x20)) +#define KE_MID_REG(x) (0x08 + ((x) * 0x20)) +#define KE_MSB_REG(x) (0x0c + ((x) * 0x20)) +#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20)) +#define KE_OSC_SEL_REG 0xf8 +#define KE_OSC_SEL_EXT (1 << 0) +#define KE_OSC_SEL_4MHZ (2 << 0) +#define KE_OSC_SEL_20MHZ (3 << 0) +#define KE_DO_REG 0xfc + +static int ke_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; -/*-- counter write ----------------------------------------------------------*/ + for (i = 0; i < insn->n; i++) { + val = data[0]; -/* This should be used only for resetting the counters; maybe it is better - to make a special command 'reset'. */ -static int cnt_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - - outb((unsigned char)((data[0] >> 24) & 0xff), - dev->iobase + chan * 0x20 + 0x10); - outb((unsigned char)((data[0] >> 16) & 0xff), - dev->iobase + chan * 0x20 + 0x0c); - outb((unsigned char)((data[0] >> 8) & 0xff), - dev->iobase + chan * 0x20 + 0x08); - outb((unsigned char)((data[0] >> 0) & 0xff), - dev->iobase + chan * 0x20 + 0x04); - - /* return the number of samples written */ - return 1; -} + /* Order matters */ + outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan)); + outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan)); + outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan)); + } -/*-- counter read -----------------------------------------------------------*/ + return insn->n; +} -static int cnt_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int ke_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char a0, a1, a2, a3, a4; - int chan = CR_CHAN(insn->chanspec); - int result; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - a0 = inb(dev->iobase + chan * 0x20); - a1 = inb(dev->iobase + chan * 0x20 + 0x04); - a2 = inb(dev->iobase + chan * 0x20 + 0x08); - a3 = inb(dev->iobase + chan * 0x20 + 0x0c); - a4 = inb(dev->iobase + chan * 0x20 + 0x10); + for (i = 0; i < insn->n; i++) { + /* Order matters */ + inb(dev->iobase + KE_LATCH_REG(chan)); - result = (a1 + (a2 * 256) + (a3 * 65536)); - if (a4 > 0) - result = result - s->maxdata; + val = inb(dev->iobase + KE_LSB_REG(chan)); + val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8); + val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16); + val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24); - *data = (unsigned int)result; + data[i] = val; + } - /* return the number of samples read */ - return 1; + return insn->n; } -static int cnt_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int ke_counter_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + KE_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int ke_counter_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct comedi_subdevice *s; @@ -97,30 +118,32 @@ static int cnt_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 0); - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; - - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; - s->n_chan = 3; - s->maxdata = 0x00ffffff; - s->insn_read = cnt_rinsn; - s->insn_write = cnt_winsn; - - /* select 20MHz clock */ - outb(3, dev->iobase + 248); - - /* reset all counters */ - outb(0, dev->iobase); - outb(0, dev->iobase + 0x20); - outb(0, dev->iobase + 0x40); - - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0x01ffffff; + s->range_table = &range_unknown; + s->insn_read = ke_counter_insn_read; + s->insn_write = ke_counter_insn_write; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ke_counter_do_insn_bits; + + outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG); + + outb(0, dev->iobase + KE_RESET_REG(0)); + outb(0, dev->iobase + KE_RESET_REG(1)); + outb(0, dev->iobase + KE_RESET_REG(2)); return 0; } @@ -128,7 +151,7 @@ static int cnt_auto_attach(struct comedi_device *dev, static struct comedi_driver ke_counter_driver = { .driver_name = "ke_counter", .module = THIS_MODULE, - .auto_attach = cnt_auto_attach, + .auto_attach = ke_counter_auto_attach, .detach = comedi_pci_disable, }; @@ -140,7 +163,7 @@ static int ke_counter_pci_probe(struct pci_dev *dev, } static const struct pci_device_id ke_counter_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) }, { 0 } }; MODULE_DEVICE_TABLE(pci, ke_counter_pci_table); @@ -154,5 +177,5 @@ static struct pci_driver ke_counter_pci_driver = { module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index e739bcd66a04..f02b31b317ec 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1112,9 +1112,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (!dev->attached) return IRQ_NONE; - /* Reset all events */ - s->async->events = 0; - if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { /* Read status register to find out what happened */ diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 7f6687896401..0ff126b1fdfd 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -248,6 +248,20 @@ static int me_dio_insn_bits(struct comedi_device *dev, return insn->n; } +static int me_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct me_private_data *dev_private = dev->private; + unsigned int status; + + status = readw(dev_private->me_regbase + ME_STATUS); + if ((status & 0x0004) == 0) + return 0; + return -EBUSY; +} + static int me_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -258,7 +272,7 @@ static int me_ai_insn_read(struct comedi_device *dev, unsigned int rang = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned short val; - int i; + int ret; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -290,19 +304,14 @@ static int me_ai_insn_read(struct comedi_device *dev, readw(dev_private->me_regbase + ME_ADC_START); /* wait for ADC fifo not empty flag */ - for (i = 100000; i > 0; i--) - if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004)) - break; + ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); + if (ret) + return ret; /* get value from ADC fifo */ - if (i) { - val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); - val = (val ^ 0x800) & 0x0fff; - data[0] = val; - } else { - dev_err(dev->class_dev, "Cannot get single value\n"); - return -EIO; - } + val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); + val = (val ^ 0x800) & 0x0fff; + data[0] = val; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -542,9 +551,6 @@ static int me_auto_attach(struct comedi_device *dev, s->insn_bits = me_dio_insn_bits; s->insn_config = me_dio_insn_config; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c index 81b78e053f4e..a4f7d6f138df 100644 --- a/drivers/staging/comedi/drivers/mf6x4.c +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -133,21 +133,18 @@ static int mf6x4_do_insn_bits(struct comedi_device *dev, return insn->n; } -static int mf6x4_ai_wait_for_eoc(struct comedi_device *dev, - unsigned int timeout) +static int mf6x4_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { struct mf6x4_private *devpriv = dev->private; - unsigned int eolc; + unsigned int status; - while (timeout--) { - eolc = ioread32(devpriv->gpioc_R) & MF6X4_GPIOC_EOLC; - if (eolc) - return 0; - - udelay(1); - } - - return -ETIME; + status = ioread32(devpriv->gpioc_R); + if (status & MF6X4_GPIOC_EOLC) + return 0; + return -EBUSY; } static int mf6x4_ai_insn_read(struct comedi_device *dev, @@ -168,7 +165,7 @@ static int mf6x4_ai_insn_read(struct comedi_device *dev, /* Trigger ADC conversion by reading ADSTART */ ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R); - ret = mf6x4_ai_wait_for_eoc(dev, 100); + ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index 9c9a0ee432cf..1a572c83f996 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -527,9 +527,9 @@ EXPORT_SYMBOL_GPL(mite_dma_disarm); int mite_sync_input_dma(struct mite_channel *mite_chan, struct comedi_async *async) { + struct comedi_subdevice *s = async->subdevice; 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 */ @@ -538,7 +538,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, nbytes = mite_bytes_written_to_memory_lb(mite_chan); if ((int)(mite_bytes_written_to_memory_ub(mite_chan) - old_alloc_count) > 0) { - dev_warn(async->subdevice->device->class_dev, + dev_warn(s->device->class_dev, "mite: DMA overwrite of free area\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; @@ -551,12 +551,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, 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; - } + cfc_inc_scan_progress(s, count); async->events |= COMEDI_CB_BLOCK; return 0; } diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index bcf2f972376e..78f235747991 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -29,9 +29,9 @@ #define MAX_MITE_DMA_CHANNELS 8 struct mite_dma_descriptor { - u32 count; - u32 addr; - u32 next; + __le32 count; + __le32 addr; + __le32 next; u32 dar; }; diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index fe4621ea65c3..f770400a0e81 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -142,8 +142,18 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { } }; -/* Timeout 200ms */ -#define TIMEOUT 200 +static int mpc624_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + MPC624_ADC); + if ((status & MPC624_ADBUSY) == 0) + return 0; + return -EBUSY; +} static int mpc624_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -152,7 +162,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, struct mpc624_private *devpriv = dev->private; int n, i; unsigned long int data_in, data_out; - unsigned char ucPort; + int ret; /* * WARNING: @@ -170,15 +180,9 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, udelay(1); /* Wait for the conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - ucPort = inb(dev->iobase + MPC624_ADC); - if (ucPort & MPC624_ADBUSY) - udelay(1000); - else - break; - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0); + if (ret) + return ret; /* Start reading data */ data_in = 0; @@ -341,7 +345,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->insn_read = mpc624_ai_rinsn; - return 1; + return 0; } static struct comedi_driver mpc624_driver = { diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 3ca755eca285..b74b9e9bfd4a 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -81,34 +81,44 @@ struct multiq3_private { unsigned int ao_readback[2]; }; +static int multiq3_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + MULTIQ3_STATUS); + if (status & context) + return 0; + return -EBUSY; +} + static int multiq3_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, n; + int n; int chan; unsigned int hi, lo; + int ret; chan = CR_CHAN(insn->chanspec); outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3), dev->iobase + MULTIQ3_CONTROL); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC); + if (ret) + return ret; for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + MULTIQ3_AD_CS); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + - MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC_I) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC_I); + if (ret) + return ret; hi = inb(dev->iobase + MULTIQ3_AD_CS); lo = inb(dev->iobase + MULTIQ3_AD_CS); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index df42e3906171..0d4b9019f76a 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -40,6 +40,7 @@ #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" #include "ni_tio.h" @@ -789,13 +790,7 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, struct ni_gpct *counter = s->private; ni_tio_handle_interrupt(counter, s); - if (s->async->events) { - if (s->async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_660x_cancel(dev, s); - } - comedi_event(dev, s); - } + cfc_handle_events(dev, s); } static irqreturn_t ni_660x_interrupt(int irq, void *d) @@ -1187,7 +1182,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev, global_interrupt_config_bits |= Cascade_Int_Enable_Bit; ni_660x_write_register(dev, 0, global_interrupt_config_bits, NI660X_GLOBAL_INT_CFG); - dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name); + return 0; } diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 8550fdc4ccd3..1002ceacfdcc 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -246,9 +246,6 @@ static int ni_670x_auto_attach(struct comedi_device *dev, /* Config of ao registers */ writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET); - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index f83eb9ebe278..4e39b1f63d81 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -184,7 +184,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) } /* initialize async here to make sure s is not NULL */ async = s->async; - async->events = 0; cmd = &async->cmd; status = inw(dev->iobase + STATUS_REG); @@ -196,15 +195,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d) if (status & OVFL_BIT) { comedi_error(dev, "fifo overflow"); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); } if ((status & DMA_TC_BIT) == 0) { comedi_error(dev, "caught non-dma interrupt? Aborting."); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -249,7 +247,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) cfc_write_to_buffer(s, dpnt); if (cmd->stop_src == TRIG_COUNT) { if (--devpriv->count == 0) { /* end of acquisition */ - a2150_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -265,7 +262,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); /* clear interrupt */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); @@ -488,13 +485,25 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int a2150_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STATUS_REG); + if (status & FNE_BIT) + return 0; + return -EBUSY; +} + static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct a2150_private *devpriv = dev->private; - unsigned int i, n; - static const int timeout = 100000; - static const int filter_delay = 36; + unsigned int n; + int ret; /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); @@ -524,30 +533,20 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, * there is a 35.6 sample delay for data to get through the * antialias filter */ - for (n = 0; n < filter_delay; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + for (n = 0; n < 36; n++) { + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + inw(dev->iobase + FIFO_DATA_REG); } /* read data */ for (n = 0; n < insn->n; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + data[n] = inw(dev->iobase + FIFO_DATA_REG); data[n] ^= 0x8000; } diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index e8cd5ddb85c5..4262385e4f46 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -96,7 +96,6 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) #define CLOCK_100_HZ 0x8F25 /* Other miscellaneous defines */ #define ATMIO16D_SIZE 32 /* bus address range */ -#define ATMIO16D_TIMEOUT 10 struct atmio16_board_t { @@ -448,16 +447,32 @@ static int atmio16d_ai_cancel(struct comedi_device *dev, return 0; } -/* Mode 0 is used to get a single conversion on demand */ +static int atmio16d_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STAT_REG); + if (status & STAT_AD_CONVAVAIL) + return 0; + if (status & STAT_AD_OVERFLOW) { + outw(0, dev->iobase + AD_CLEAR_REG); + return -EOVERFLOW; + } + return -EBUSY; +} + static int atmio16d_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct atmio16d_private *devpriv = dev->private; - int i, t; + int i; int chan; int gain; - int status; + int ret; chan = CR_CHAN(insn->chanspec); gain = CR_RANGE(insn->chanspec); @@ -473,26 +488,17 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { /* start the conversion */ outw(0, dev->iobase + START_CONVERT_REG); + /* wait for it to finish */ - for (t = 0; t < ATMIO16D_TIMEOUT; t++) { - /* check conversion status */ - status = inw(dev->iobase + STAT_REG); - if (status & STAT_AD_CONVAVAIL) { - /* read the data now */ - data[i] = inw(dev->iobase + AD_FIFO_REG); - /* change to two's complement if need be */ - if (devpriv->adc_coding == adc_2comp) - data[i] ^= 0x800; - break; - } - if (status & STAT_AD_OVERFLOW) { - outw(0, dev->iobase + AD_CLEAR_REG); - return -ETIME; - } - } - /* end waiting, now check if it timed out */ - if (t == ATMIO16D_TIMEOUT) - return -ETIME; + ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0); + if (ret) + return ret; + + /* read the data now */ + data[i] = inw(dev->iobase + AD_FIFO_REG); + /* change to two's complement if need be */ + if (devpriv->adc_coding == adc_2comp) + data[i] ^= 0x800; } return i; @@ -723,10 +729,13 @@ static int atmio16d_attach(struct comedi_device *dev, /* 8255 subdevice */ s = &dev->subdevices[3]; - if (board->has_8255) - subdev_8255_init(dev, s, NULL, dev->iobase); - else + if (board->has_8255) { + ret = subdev_8255_init(dev, s, NULL, dev->iobase); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* don't yet know how to deal with counter/timers */ #if 0 diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index e4cdca349157..171a71d20c88 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -109,14 +109,31 @@ static int daq700_dio_insn_config(struct comedi_device *dev, return insn->n; } +static int daq700_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + STA_R2); + if ((status & 0x03)) + return -EOVERFLOW; + status = inb(dev->iobase + STA_R1); + if ((status & 0x02)) + return -ENODATA; + if ((status & 0x11) == 0x01) + return 0; + return -EBUSY; +} + static int daq700_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, chan; + int n, chan; int d; - unsigned int status; - enum { TIMEOUT = 100 }; + int ret; chan = CR_CHAN(insn->chanspec); /* write channel to multiplexer */ @@ -130,30 +147,12 @@ static int daq700_ai_rinsn(struct comedi_device *dev, outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */ /* mode 1 out0 H, L to H, start conversion */ outb(0x32, dev->iobase + CMO_R); + /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inb(dev->iobase + STA_R2); - if ((status & 0x03) != 0) { - dev_info(dev->class_dev, - "Overflow/run Error\n"); - return -EOVERFLOW; - } - status = inb(dev->iobase + STA_R1); - if ((status & 0x02) != 0) { - dev_info(dev->class_dev, "Data Error\n"); - return -ENODATA; - } - if ((status & 0x11) == 0x01) { - /* ADC conversion complete */ - break; - } - udelay(1); - } - if (i == TIMEOUT) { - dev_info(dev->class_dev, - "timeout during ADC conversion\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0); + if (ret) + return ret; + /* read data */ d = inw(dev->iobase + ADFIFO_R); /* mangle the data as necessary */ @@ -229,11 +228,6 @@ static int daq700_auto_attach(struct comedi_device *dev, s->insn_read = daq700_ai_rinsn; daq700_ai_config(dev, s); - dev_info(dev->class_dev, "%s: %s, io 0x%lx\n", - dev->driver->driver_name, - dev->board_name, - dev->iobase); - return 0; } diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 335ea34fa57c..925e82c65b2d 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -3,8 +3,8 @@ Driver for National Instruments PCMCIA DAQ-Card DIO-24 Copyright (C) 2002 Daniel Vecino Castel <dvecino@able.es> - PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13 - from the pcmcia package. + PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 + 2001/08/24 12:13:13 from the pcmcia package. The initial developer of the pcmcia dummy_cs.c code is David A. Hinds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 0512445df08e..f4216e825f03 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -73,7 +73,6 @@ #include "ni_labpc_isadma.h" #define LABPC_SIZE 0x20 /* size of ISA io region */ -#define LABPC_ADC_TIMEOUT 1000 enum scan_mode { MODE_SINGLE_CHAN, @@ -308,19 +307,17 @@ static void labpc_clear_adc_fifo(struct comedi_device *dev) labpc_read_adc_fifo(dev); } -static int labpc_ai_wait_for_data(struct comedi_device *dev, - int timeout) +static int labpc_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { struct labpc_private *devpriv = dev->private; - int i; - for (i = 0; i < timeout; i++) { - devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); - if (devpriv->stat1 & STAT1_DAVAIL) - return 0; - udelay(1); - } - return -ETIME; + devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); + if (devpriv->stat1 & STAT1_DAVAIL) + return 0; + return -EBUSY; } static int labpc_ai_insn_read(struct comedi_device *dev, @@ -363,7 +360,7 @@ static int labpc_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG); - ret = labpc_ai_wait_for_data(dev, LABPC_ADC_TIMEOUT); + ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0); if (ret) return ret; @@ -950,7 +947,6 @@ static irqreturn_t labpc_interrupt(int irq, void *d) async = s->async; cmd = &async->cmd; - async->events = 0; /* read board status */ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); @@ -968,7 +964,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overrun"); return IRQ_HANDLED; } @@ -988,7 +984,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overflow"); return IRQ_HANDLED; } @@ -996,20 +992,17 @@ static irqreturn_t labpc_interrupt(int irq, void *d) if (cmd->stop_src == TRIG_EXT) { if (devpriv->stat2 & STAT2_OUTA1) { labpc_drain_dregs(dev); - labpc_cancel(dev, s); async->events |= COMEDI_CB_EOA; } } /* TRIG_COUNT end of acquisition */ if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->count == 0) { - labpc_cancel(dev, s); + if (devpriv->count == 0) async->events |= COMEDI_CB_EOA; - } } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 457b88481db0..8a0e3b7236ad 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -256,7 +256,6 @@ static int ni_rtsi_insn_config(struct comedi_device *dev, static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_read_eeprom(struct comedi_device *dev, int addr); -static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s); #ifndef PCIDMA static void ni_handle_fifo_half_full(struct comedi_device *dev); static int ni_ao_fifo_half_empty(struct comedi_device *dev, @@ -272,15 +271,12 @@ static void shutdown_ai_command(struct comedi_device *dev); static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s); - static int ni_8255_callback(int dir, int port, int data, unsigned long arg); #ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s); #endif -static int ni_gpct_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index); @@ -687,12 +683,22 @@ static void ni_clear_ai_fifo(struct comedi_device *dev) { const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; + static const int timeout = 10000; + int i; if (board->reg_type == ni_reg_6143) { /* Flush the 6143 data FIFO */ ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */ ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */ - while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */ + /* Wait for complete */ + for (i = 0; i < timeout; i++) { + if (!(ni_readl(AIFIFO_Status_6143) & 0x10)) + break; + udelay(1); + } + if (i == timeout) { + comedi_error(dev, "FIFO flush timeout."); + } } else { devpriv->stc_writew(dev, 1, ADC_FIFO_Clear); if (board->reg_type == ni_reg_625x) { @@ -937,32 +943,6 @@ static void shutdown_ai_command(struct comedi_device *dev) s->async->events |= COMEDI_CB_EOA; } -static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | - COMEDI_CB_EOA)) { - switch (s->index) { - case NI_AI_SUBDEV: - ni_ai_reset(dev, s); - break; - case NI_AO_SUBDEV: - ni_ao_reset(dev, s); - break; - case NI_GPCT0_SUBDEV: - case NI_GPCT1_SUBDEV: - ni_gpct_cancel(dev, s); - break; - case NI_DIO_SUBDEV: - ni_cdio_cancel(dev, s); - break; - default: - break; - } - } - comedi_event(dev, s); -} - static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index) { @@ -974,8 +954,7 @@ static void handle_gpct_interrupt(struct comedi_device *dev, ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index], s); - if (s->async->events) - ni_event(dev, s); + cfc_handle_events(dev, s); #endif } @@ -1033,7 +1012,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (comedi_is_subdevice_running(s)) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - ni_event(dev, s); + cfc_handle_events(dev, s); } return; } @@ -1048,8 +1027,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (status & (AI_Overrun_St | AI_Overflow_St)) s->async->events |= COMEDI_CB_OVERFLOW; - ni_event(dev, s); - + cfc_handle_events(dev, s); return; } if (status & AI_SC_TC_St) { @@ -1076,7 +1054,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if ((status & AI_STOP_St)) ni_handle_eos(dev, s); - ni_event(dev, s); + cfc_handle_events(dev, s); } static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) @@ -1151,7 +1129,7 @@ static void handle_b_interrupt(struct comedi_device *dev, } #endif - ni_event(dev, s); + cfc_handle_events(dev, s); } #ifndef PCIDMA @@ -3662,7 +3640,7 @@ static void handle_cdio_interrupt(struct comedi_device *dev) M_Offset_CDIO_Command); /* s->async->events |= COMEDI_CB_EOA; */ } - ni_event(dev, s); + cfc_handle_events(dev, s); } static int ni_serial_insn_config(struct comedi_device *dev, @@ -4282,10 +4260,14 @@ static int ni_E_init(struct comedi_device *dev) /* 8255 device */ s = &dev->subdevices[NI_8255_DIO_SUBDEV]; - if (board->has_8255) - subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev); - else + if (board->has_8255) { + ret = subdev_8255_init(dev, s, ni_8255_callback, + (unsigned long)dev); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* formerly general purpose counter/timer device, but no longer used */ s = &dev->subdevices[NI_UNUSED_SUBDEV]; @@ -4393,6 +4375,9 @@ static int ni_E_init(struct comedi_device *dev) &ni_gpct_read_register, counter_variant, NUM_GPCT); + if (!devpriv->counter_dev) + return -ENOMEM; + /* General purpose counters */ for (j = 0; j < NUM_GPCT; ++j) { s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; @@ -4483,7 +4468,6 @@ static int ni_E_init(struct comedi_device *dev) ni_writeb(0x0, M_Offset_AO_Calibration); } - printk("\n"); return 0; } @@ -4992,9 +4976,9 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } #endif +#ifdef PCIDMA static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { -#ifdef PCIDMA struct ni_gpct *counter = s->private; int retval; @@ -5002,10 +4986,8 @@ static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) ni_e_series_enable_second_irq(dev, counter->counter_index, 0); ni_release_gpct_mite_channel(dev, counter->counter_index); return retval; -#else - return 0; -#endif } +#endif /* * diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 30c46a3c1767..85ac2d964f5c 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -263,9 +263,6 @@ enum FPGA_Control_Bits { #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -static int ni_pcidio_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - enum nidio_boardid { BOARD_PCIDIO_32HS, BOARD_PXI6533, @@ -353,17 +350,6 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } -static void ni_pcidio_event(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_pcidio_cancel(dev, s); - } - comedi_event(dev, s); -} - static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct nidio96_private *devpriv = dev->private; @@ -501,7 +487,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) } out: - ni_pcidio_event(dev, s); + cfc_handle_events(dev, s); #if 0 if (!tag) { writeb(0x03, diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 0ed980455875..d40df072583c 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1551,7 +1551,7 @@ static int pcimio_auto_attach(struct comedi_device *dev, dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change; dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change; - return ret; + return 0; } static int pcimio_ai_change(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h index 68378dab4e70..1056bf001e5e 100644 --- a/drivers/staging/comedi/drivers/ni_tio.h +++ b/drivers/staging/comedi/drivers/ni_tio.h @@ -115,10 +115,10 @@ struct ni_gpct { struct ni_gpct_device { struct comedi_device *dev; - void (*write_register) (struct ni_gpct *counter, unsigned bits, - enum ni_gpct_register reg); - unsigned (*read_register) (struct ni_gpct *counter, - enum ni_gpct_register reg); + void (*write_register)(struct ni_gpct *counter, unsigned bits, + enum ni_gpct_register reg); + unsigned (*read_register)(struct ni_gpct *counter, + enum ni_gpct_register reg); enum ni_gpct_variant variant; struct ni_gpct *counters; unsigned num_counters; diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index f0fc123ef566..7c03a5d17b1b 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -253,18 +253,17 @@ static void pcl711_set_changain(struct comedi_device *dev, outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG); } -static int pcl711_ai_wait_for_eoc(struct comedi_device *dev, - unsigned int timeout) +static int pcl711_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned int msb; + unsigned int status; - while (timeout--) { - msb = inb(dev->iobase + PCL711_AI_MSB_REG); - if ((msb & PCL711_AI_MSB_DRDY) == 0) - return 0; - udelay(1); - } - return -ETIME; + status = inb(dev->iobase + PCL711_AI_MSB_REG); + if ((status & PCL711_AI_MSB_DRDY) == 0) + return 0; + return -EBUSY; } static int pcl711_ai_insn_read(struct comedi_device *dev, @@ -282,7 +281,7 @@ static int pcl711_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG); - ret = pcl711_ai_wait_for_eoc(dev, 100); + ret = comedi_timeout(dev, s, insn, pcl711_ai_eoc, 0); if (ret) return ret; @@ -336,11 +335,8 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) { + if (cmd->stop_src == TRIG_NONE) err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } else { - /* ignore */ - } if (err) return 3; diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 53613b385f35..160eac8083db 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -131,34 +131,32 @@ #define boardACL8216 8 /* and ICP DAS A-826PG */ #define boardA821 9 /* PGH, PGL, PGL/NDA versions */ -#define PCLx1x_IORANGE 16 - -#define PCL812_CTR0 0 -#define PCL812_CTR1 1 -#define PCL812_CTR2 2 -#define PCL812_CTRCTL 3 -#define PCL812_AD_LO 4 -#define PCL812_DA1_LO 4 -#define PCL812_AD_HI 5 -#define PCL812_DA1_HI 5 -#define PCL812_DA2_LO 6 -#define PCL812_DI_LO 6 -#define PCL812_DA2_HI 7 -#define PCL812_DI_HI 7 -#define PCL812_CLRINT 8 -#define PCL812_GAIN 9 -#define PCL812_MUX 10 -#define PCL812_MODE 11 -#define PCL812_CNTENABLE 10 -#define PCL812_SOFTTRIG 12 -#define PCL812_DO_LO 13 -#define PCL812_DO_HI 14 - -#define PCL812_DRDY 0x10 /* =0 data ready */ - -#define ACL8216_STATUS 8 /* 5. bit signalize data ready */ - -#define ACL8216_DRDY 0x20 /* =0 data ready */ +/* + * Register I/O map + */ +#define PCL812_TIMER_BASE 0x00 +#define PCL812_AI_LSB_REG 0x04 +#define PCL812_AI_MSB_REG 0x05 +#define PCL812_AI_MSB_DRDY (1 << 4) +#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL812_DI_LSB_REG 0x06 +#define PCL812_DI_MSB_REG 0x07 +#define PCL812_STATUS_REG 0x08 +#define PCL812_STATUS_DRDY (1 << 5) +#define PCL812_RANGE_REG 0x09 +#define PCL812_MUX_REG 0x0a +#define PCL812_MUX_CHAN(x) ((x) << 0) +#define PCL812_MUX_CS0 (1 << 4) +#define PCL812_MUX_CS1 (1 << 5) +#define PCL812_CTRL_REG 0x0b +#define PCL812_CTRL_DISABLE_TRIG (0 << 0) +#define PCL812_CTRL_SOFT_TRIG (1 << 0) +#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0) +#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0) +#define PCL812_SOFTTRIG_REG 0x0c +#define PCL812_DO_LSB_REG 0x0d +#define PCL812_DO_MSB_REG 0x0e #define MAX_CHANLIST_LEN 256 /* length of scan list */ @@ -331,213 +329,391 @@ static const struct comedi_lrange range_a821pgh_ai = { }; struct pcl812_board { + const char *name; + int board_type; + int n_aichan; + int n_aochan; + unsigned int ai_ns_min; + const struct comedi_lrange *rangelist_ai; + unsigned int IRQbits; + unsigned int has_dma:1; + unsigned int has_16bit_ai:1; + unsigned int has_mpc508_mux:1; + unsigned int has_dio:1; +}; - const char *name; /* board name */ - int board_type; /* type of this board */ - int n_aichan; /* num of AI chans in S.E. */ - int n_aichan_diff; /* DIFF num of chans */ - int n_aochan; /* num of DA chans */ - int n_dichan; /* DI and DO chans */ - int n_dochan; - int ai_maxdata; /* AI resolution */ - unsigned int ai_ns_min; /* max sample speed of card v ns */ - unsigned int i8254_osc_base; /* clock base */ - const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ - unsigned int IRQbits; /* allowed IRQ */ - unsigned char DMAbits; /* allowed DMA chans */ - unsigned char io_range; /* iorange for this board */ - unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ +static const struct pcl812_board boardtypes[] = { + { + .name = "pcl812", + .board_type = boardPCL812, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_bipolar10, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl812pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112dg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "acl8112hg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a821pgl", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a821pglnda", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + }, { + .name = "a821pgh", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_a821pgh_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a822pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a822pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl813", + .board_type = boardPCL813, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "pcl813b", + .board_type = boardPCL813B, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "acl8113", + .board_type = boardACL8113, + .n_aichan = 32, + .rangelist_ai = &range_acl8113_1_ai, + }, { + .name = "iso813", + .board_type = boardISO813, + .n_aichan = 32, + .rangelist_ai = &range_iso813_1_ai, + }, { + .name = "acl8216", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a826pg", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_dio = 1, + }, }; struct pcl812_private { - - unsigned char valid; /* =1 device is OK */ unsigned char dma; /* >0 use dma ( usedDMA channel) */ - unsigned char use_diff; /* =1 diff inputs */ - unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */ - unsigned char use_ext_trg; /* 1=board uses external trigger */ unsigned char range_correction; /* =1 we must add 1 to range number */ - unsigned char old_chan_reg; /* lastly used chan/gain pair */ - unsigned char old_gain_reg; + unsigned int last_ai_chanspec; unsigned char mode_reg_int; /* there is stored INT number for some card */ - unsigned char ai_neverending; /* =1 we do unlimited AI */ - unsigned char ai_eos; /* 1=EOS wake up */ - unsigned char ai_dma; /* =1 we use DMA */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - unsigned int ai_scans; /* len of scanlist */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - unsigned int ai_is16b; /* =1 we have 16 bit card */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* PTR to DMA buf */ - unsigned int dmapages[2]; /* how many pages we have allocated */ unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ - unsigned int hwdmasize[2]; /* DMA buf size in bytes */ unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */ int next_dma_buf; /* which buffer is next to use */ unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ unsigned int ao_readback[2]; /* data for AO readback */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int use_diff:1; + unsigned int use_mpc508:1; + unsigned int use_ext_trg:1; + unsigned int ai_dma:1; + unsigned int ai_eos:1; }; -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait); -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -/* -============================================================================== -*/ -static int pcl812_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers) { struct pcl812_private *devpriv = dev->private; - int n; - int timeout, hi; - - /* select software trigger */ - outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - hi = inb(dev->iobase + PCL812_AD_HI); - if (!(hi & PCL812_DRDY)) - goto conv_finish; - udelay(1); - } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return -ETIME; + unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); -conv_finish: - data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO); + if (load_timers) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return n; } -/* -============================================================================== -*/ -static int acl8216_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - int n; - int timeout; - - /* select software trigger */ - outb(1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) - goto conv_finish; - udelay(1); + struct pcl812_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; + + /* we use EOS, so adapt DMA buffer to one scan */ + if (devpriv->ai_eos) { + devpriv->dmabytestomove[0] = + cmd->chanlist_len * sizeof(short); + devpriv->dmabytestomove[1] = + cmd->chanlist_len * sizeof(short); + devpriv->dma_runs_to_end = 1; + } else { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + if (s->async->prealloc_bufsz < devpriv->hwdmasize) { + devpriv->dmabytestomove[0] = + s->async->prealloc_bufsz; + devpriv->dmabytestomove[1] = + s->async->prealloc_bufsz; } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(0, dev->iobase + PCL812_MODE); - return -ETIME; - -conv_finish: - data[n] = - (inb(dev->iobase + - PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO); + if (cmd->stop_src == TRIG_NONE) { + devpriv->dma_runs_to_end = 1; + } else { + /* how many samples we must transfer? */ + bytes = cmd->chanlist_len * + cmd->stop_arg * 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) { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->ai_eos = 0; } - outb(0, dev->iobase + PCL812_MODE); - return n; + if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) { + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + devpriv->ai_eos = 0; + } + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int i; + unsigned long dma_flags; - for (i = 0; i < insn->n; i++) { - outb((data[i] & 0xff), - dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO)); - outb((data[i] >> 8) & 0x0f, - dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI)); - devpriv->ao_readback[chan] = data[i]; + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + disable_dma(devpriv->dma); + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->ai_eos) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv->next_dma_buf]); + } else { + if (devpriv->dma_runs_to_end) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv-> + next_dma_buf]); + } else { + set_dma_count(devpriv->dma, devpriv->last_dma_run); + } + devpriv->dma_runs_to_end--; } - - return i; + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_set_chan_range(struct comedi_device *dev, + unsigned int chanspec, char wait) { struct pcl812_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int i; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int mux = 0; - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + if (chanspec == devpriv->last_ai_chanspec) + return; + + devpriv->last_ai_chanspec = chanspec; + + if (devpriv->use_mpc508) { + if (devpriv->use_diff) { + mux |= PCL812_MUX_CS0 | PCL812_MUX_CS1; + } else { + if (chan < 8) + mux |= PCL812_MUX_CS0; + else + mux |= PCL812_MUX_CS1; + } + } + + outb(mux | PCL812_MUX_CHAN(chan), dev->iobase + PCL812_MUX_REG); + outb(range + devpriv->range_correction, dev->iobase + PCL812_RANGE_REG); - return i; + if (wait) + /* + * XXX this depends on selected range and can be very long for + * some high gain ranges! + */ + udelay(devpriv->max_812_ai_mode0_rangewait); } -/* -============================================================================== -*/ -static int pcl812_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_clear_eoc(struct comedi_device *dev) { - data[1] = inb(dev->iobase + PCL812_DI_LO); - data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8; + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL812_STATUS_REG); +} - return insn->n; +static void pcl812_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(255, dev->iobase + PCL812_SOFTTRIG_REG); } -static int pcl812_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static unsigned int pcl812_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) { - if (comedi_dio_update_state(s, data)) { - outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); - outb((s->state >> 8), dev->iobase + PCL812_DO_HI); - } + unsigned int val; - data[1] = s->state; + val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL812_AI_LSB_REG); - return insn->n; + return val & s->maxdata; +} + +static int pcl812_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + if (s->maxdata > 0x0fff) { + status = inb(dev->iobase + PCL812_STATUS_REG); + if ((status & PCL812_STATUS_DRDY) == 0) + return 0; + } else { + status = inb(dev->iobase + PCL812_AI_MSB_REG); + if ((status & PCL812_AI_MSB_DRDY) == 0) + return 0; + } + return -EBUSY; } -/* -============================================================================== -*/ static int pcl812_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -545,7 +721,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, struct pcl812_private *devpriv = dev->private; int err = 0; unsigned int flags; - int tmp, divisor1, divisor2; + int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -600,8 +776,9 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor1, + &devpriv->divisor2, &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < board->ai_ns_min) cmd->convert_arg = board->ai_ns_min; @@ -615,54 +792,21 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl = 0; + unsigned int i; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (devpriv->use_ext_trg) { - if (cmd->convert_src != TRIG_EXT) - return -EINVAL; - } else { - if (cmd->convert_src != TRIG_TIMER) - return -EINVAL; - } - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; - if (cmd->chanlist_len > MAX_CHANLIST_LEN) - return -EINVAL; - - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, cmd->flags); - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl812_start_pacer(dev, false); - devpriv->ai_n_chan = cmd->chanlist_len; - memcpy(devpriv->ai_chanlist, cmd->chanlist, - sizeof(unsigned int) * cmd->scan_end_arg); - /* select first channel and range */ - setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); + pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1); if (devpriv->dma) { /* check if we can use DMA transfer */ devpriv->ai_dma = 1; - for (i = 1; i < devpriv->ai_n_chan; i++) - if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) { + for (i = 1; i < cmd->chanlist_len; i++) + if (cmd->chanlist[0] != cmd->chanlist[i]) { /* we cann't use DMA :-( */ devpriv->ai_dma = 0; break; @@ -670,212 +814,105 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } else devpriv->ai_dma = 0; - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; - } - devpriv->ai_act_scan = 0; devpriv->ai_poll_ptr = 0; s->async->cur_chan = 0; /* don't we want wake up every scan? */ - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { + if (cmd->flags & TRIG_WAKE_EOS) { devpriv->ai_eos = 1; /* DMA is useless for this situation */ - if (devpriv->ai_n_chan == 1) + if (cmd->chanlist_len == 1) devpriv->ai_dma = 0; } - if (devpriv->ai_dma) { - /* we use EOS, so adapt DMA buffer to one scan */ - if (devpriv->ai_eos) { - devpriv->dmabytestomove[0] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dmabytestomove[1] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dma_runs_to_end = 1; - } else { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - if (devpriv->ai_data_len < devpriv->hwdmasize[0]) - devpriv->dmabytestomove[0] = - devpriv->ai_data_len; - if (devpriv->ai_data_len < devpriv->hwdmasize[1]) - devpriv->dmabytestomove[1] = - devpriv->ai_data_len; - if (devpriv->ai_neverending) { - devpriv->dma_runs_to_end = 1; - } else { - /* how many samples we must transfer? */ - bytes = devpriv->ai_n_chan * - devpriv->ai_scans * sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = - bytes / devpriv->dmabytestomove[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = - bytes % devpriv->dmabytestomove[0]; - if (devpriv->dma_runs_to_end == 0) - devpriv->dmabytestomove[0] = - devpriv->last_dma_run; - devpriv->dma_runs_to_end--; - } - } - if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->ai_eos = 0; - } - if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) { - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - devpriv->ai_eos = 0; - } - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } + if (devpriv->ai_dma) + pcl812_ai_setup_dma(dev, s); switch (cmd->convert_src) { case TRIG_TIMER: - start_pacer(dev, 1, divisor1, divisor2); + pcl812_start_pacer(dev, true); break; } - if (devpriv->ai_dma) /* let's go! */ - outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); - else /* let's go! */ - outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); + if (devpriv->ai_dma) + ctrl |= PCL812_CTRL_PACER_DMA_TRIG; + else + ctrl |= PCL812_CTRL_PACER_EOC_TRIG; + outb(devpriv->mode_reg_int | ctrl, dev->iobase + PCL812_CTRL_REG); return 0; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) +static bool pcl812_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) { - char err = 1; - unsigned int mask, timeout; - struct comedi_device *dev = d; struct pcl812_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned int next_chan; + struct comedi_cmd *cmd = &s->async->cmd; - s->async->events = 0; + s->async->events |= COMEDI_CB_BLOCK; - timeout = 50; /* wait max 50us, it must finish under 33us */ - if (devpriv->ai_is16b) { - mask = 0xffff; - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } else { - mask = 0x0fff; - while (timeout--) { - if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { - err = 0; - break; - } - udelay(1); - } + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; + } + + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - if (err) { + return true; +} + +static void pcl812_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int next_chan; + + if (pcl812_ai_eoc(dev, s, NULL, 0)) { dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); - pcl812_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - comedi_buf_put(s->async, - ((inb(dev->iobase + PCL812_AD_HI) << 8) | - inb(dev->iobase + PCL812_AD_LO)) & mask); + comedi_buf_put(s->async, 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, unsigned short *ptr, unsigned int bufptr, unsigned int len) { - struct pcl812_private *devpriv = dev->private; unsigned int i; - s->async->events = 0; for (i = len; i; i--) { - /* get one sample */ comedi_buf_put(s->async, ptr[bufptr++]); - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - break; - } - } + if (!pcl812_ai_next_chan(dev, s)) + break; } - - comedi_event(dev, s); } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) +static void pcl812_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl812_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned long dma_flags; int len, bufptr; unsigned short *ptr; @@ -883,58 +920,36 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - devpriv->ai_poll_ptr; - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - disable_dma(devpriv->dma); - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->ai_eos) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv->next_dma_buf]); - } else { - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - devpriv->dma_runs_to_end--; - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + pcl812_ai_setup_next_dma(dev, s); bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); - - return IRQ_HANDLED; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812(int irq, void *d) +static irqreturn_t pcl812_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; struct pcl812_private *devpriv = dev->private; if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); + pcl812_ai_clear_eoc(dev); return IRQ_HANDLED; } + if (devpriv->ai_dma) - return interrupt_pcl812_ai_dma(irq, d); + pcl812_handle_dma(dev, s); else - return interrupt_pcl812_ai_int(irq, d); + pcl812_handle_eoc(dev, s); + + pcl812_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; @@ -979,204 +994,308 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== -*/ -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait) +static int pcl812_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; - unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */ - /* gain index */ - unsigned char gain_reg = CR_RANGE(rangechan) + - devpriv->range_correction; - if ((chan_reg == devpriv->old_chan_reg) - && (gain_reg == devpriv->old_gain_reg)) - return; /* we can return, no change */ + if (devpriv->ai_dma) + disable_dma(devpriv->dma); - devpriv->old_chan_reg = chan_reg; - devpriv->old_gain_reg = gain_reg; + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_start_pacer(dev, false); + pcl812_ai_clear_eoc(dev); + return 0; +} - if (devpriv->use_MPC) { - if (devpriv->use_diff) { - chan_reg = chan_reg | 0x30; /* DIFF inputs */ - } else { - if (chan_reg & 0x80) - /* SE inputs 8-15 */ - chan_reg = chan_reg | 0x20; - else - /* SE inputs 0-7 */ - chan_reg = chan_reg | 0x10; - } - } +static int pcl812_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl812_private *devpriv = dev->private; + int ret = 0; + int i; - outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */ - outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ + outb(devpriv->mode_reg_int | PCL812_CTRL_SOFT_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_set_chan_range(dev, insn->chanspec, 1); - if (wait) - /* - * XXX this depends on selected range and can be very long for - * some high gain ranges! - */ - udelay(devpriv->max_812_ai_mode0_rangewait); + for (i = 0; i < insn->n; i++) { + pcl812_ai_clear_eoc(dev); + pcl812_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl812_ai_get_sample(dev, s); + } + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + + return ret ? ret : insn->n; } -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static int pcl812_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - outb(0xb4, dev->iobase + PCL812_CTRCTL); - outb(0x74, dev->iobase + PCL812_CTRCTL); - udelay(1); + struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); + for (i = 0; i < insn->n; i++) { + outb((data[i] & 0xff), + dev->iobase + PCL812_AO_LSB_REG(chan)); + outb((data[i] >> 8) & 0x0f, + dev->iobase + PCL812_AO_MSB_REG(chan)); + devpriv->ao_readback[chan] = data[i]; } + + return insn->n; } -/* -============================================================================== -*/ -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int pcl812_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - if (devpriv->ai_dma) - disable_dma(devpriv->dma); - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - /* Stop A/D */ - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - return 0; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int pcl812_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL812_DI_LSB_REG) | + (inb(dev->iobase + PCL812_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl812_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL812_DO_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL812_DO_MSB_REG); + } + + data[1] = s->state; + + return insn->n; } -/* -============================================================================== -*/ static void pcl812_reset(struct comedi_device *dev) { const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv = dev->private; + unsigned int chan; + + /* disable analog input trigger */ + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + + /* stop pacer */ + if (board->IRQbits) + pcl812_start_pacer(dev, false); + + /* + * Invalidate last_ai_chanspec then set analog input to + * known channel/range. + */ + devpriv->last_ai_chanspec = CR_PACK(16, 0, 0); + pcl812_ai_set_chan_range(dev, CR_PACK(0, 0, 0), 0); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL812_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL812_AO_MSB_REG(chan)); + } - outb(0, dev->iobase + PCL812_MUX); - outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN); - devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */ - devpriv->old_gain_reg = -1; + /* set all digital outputs low */ + if (board->has_dio) { + outb(0, dev->iobase + PCL812_DO_MSB_REG); + outb(0, dev->iobase + PCL812_DO_LSB_REG); + } +} +static void pcl812_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl812_board *board = comedi_board(dev); + struct pcl812_private *devpriv = dev->private; + + /* default to the range table from the boardinfo */ + s->range_table = board->rangelist_ai; + + /* now check the user config option based on the boardtype */ switch (board->board_type) { case boardPCL812PG: + if (it->options[4] == 1) + s->range_table = &range_pcl812pg2_ai; + break; case boardPCL812: - case boardACL8112: - case boardACL8216: - outb(0, dev->iobase + PCL812_DA2_LO); - outb(0, dev->iobase + PCL812_DA2_HI); - case boardA821: - outb(0, dev->iobase + PCL812_DA1_LO); - outb(0, dev->iobase + PCL812_DA1_HI); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_DO_HI); - outb(0, dev->iobase + PCL812_DO_LO); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - outb(0, dev->iobase + PCL812_CLRINT); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range812_bipolar1_25; + break; + case 4: + s->range_table = &range812_bipolar0_625; + break; + case 5: + s->range_table = &range812_bipolar0_3125; + break; + default: + s->range_table = &range_bipolar10; + break; + } break; case boardPCL813B: - case boardPCL813: + if (it->options[1] == 1) + s->range_table = &range_pcl813b2_ai; + break; case boardISO813: + switch (it->options[1]) { + case 0: + s->range_table = &range_iso813_1_ai; + break; + case 1: + s->range_table = &range_iso813_1_2_ai; + break; + case 2: + s->range_table = &range_iso813_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_iso813_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_iso813_1_ai; + break; + } + break; case boardACL8113: - udelay(5); + switch (it->options[1]) { + case 0: + s->range_table = &range_acl8113_1_ai; + break; + case 1: + s->range_table = &range_acl8113_1_2_ai; + break; + case 2: + s->range_table = &range_acl8113_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_acl8113_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_acl8113_1_ai; + break; + } break; } - udelay(5); } static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv; - int ret, subdev; - unsigned int dma; - unsigned long pages; struct comedi_subdevice *s; int n_subdevices; - - ret = comedi_request_region(dev, it->options[0], board->io_range); - if (ret) - return ret; + int subdev; + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl812, 0, + ret = request_irq(it->options[1], pcl812_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (((1 << dma) & board->DMAbits) == 0) { - dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { dev_err(dev->class_dev, - "unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ - } - devpriv->dma = dma; - pages = 1; /* we want 8KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages); - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages); + devpriv->dma = it->options[2]; + + devpriv->dmapages = 1; /* we want 8KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } } -no_dma: - n_subdevices = 0; - if (board->n_aichan > 0) - n_subdevices++; + /* differential analog inputs? */ + switch (board->board_type) { + case boardA821: + if (it->options[2] == 1) + devpriv->use_diff = 1; + break; + case boardACL8112: + case boardACL8216: + if (it->options[4] == 1) + devpriv->use_diff = 1; + break; + } + + n_subdevices = 1; /* all boardtypes have analog inputs */ if (board->n_aochan > 0) n_subdevices++; - if (board->n_dichan > 0) - n_subdevices++; - if (board->n_dochan > 0) - n_subdevices++; + if (board->has_dio) + n_subdevices += 2; ret = comedi_alloc_subdevices(dev, n_subdevices); if (ret) @@ -1184,146 +1303,47 @@ no_dma: subdev = 0; - /* analog input */ - if (board->n_aichan > 0) { - s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - switch (board->board_type) { - case boardA821: - if (it->options[2] == 1) { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - case boardACL8112: - case boardACL8216: - if (it->options[4] == 1) { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - default: - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - break; - } - s->maxdata = board->ai_maxdata; - s->range_table = board->rangelist_ai; - if (board->board_type == boardACL8216) - s->insn_read = acl8216_ai_insn_read; - else - s->insn_read = pcl812_ai_insn_read; - - devpriv->use_MPC = board->haveMPC508; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = MAX_CHANLIST_LEN; - s->do_cmdtest = pcl812_ai_cmdtest; - s->do_cmd = pcl812_ai_cmd; - s->poll = pcl812_ai_poll; - s->cancel = pcl812_ai_cancel; - } - switch (board->board_type) { - case boardPCL812PG: - if (it->options[4] == 1) - s->range_table = &range_pcl812pg2_ai; - break; - case boardPCL812: - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range812_bipolar1_25; - break; - case 4: - s->range_table = &range812_bipolar0_625; - break; - case 5: - s->range_table = &range812_bipolar0_3125; - break; - default: - s->range_table = &range_bipolar10; - break; - } - break; - break; - case boardPCL813B: - if (it->options[1] == 1) - s->range_table = &range_pcl813b2_ai; - break; - case boardISO813: - switch (it->options[1]) { - case 0: - s->range_table = &range_iso813_1_ai; - break; - case 1: - s->range_table = &range_iso813_1_2_ai; - break; - case 2: - s->range_table = &range_iso813_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_iso813_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_iso813_1_ai; - break; - } - break; - case boardACL8113: - switch (it->options[1]) { - case 0: - s->range_table = &range_acl8113_1_ai; - break; - case 1: - s->range_table = &range_acl8113_1_2_ai; - break; - case 2: - s->range_table = &range_acl8113_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_acl8113_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_acl8113_1_ai; - break; - } - break; - } - subdev++; + /* Analog Input subdevice */ + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (devpriv->use_diff) { + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan / 2; + } else { + s->subdev_flags |= SDF_GROUND; + s->n_chan = board->n_aichan; + } + s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff; + + pcl812_set_ai_range_table(dev, s, it); + + s->insn_read = pcl812_ai_insn_read; + + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = MAX_CHANLIST_LEN; + s->do_cmdtest = pcl812_ai_cmdtest; + s->do_cmd = pcl812_ai_cmd; + s->poll = pcl812_ai_poll; + s->cancel = pcl812_ai_cancel; } + devpriv->use_mpc508 = board->has_mpc508_mux; + + subdev++; + /* analog output */ if (board->n_aochan > 0) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->range_table = board->rangelist_ao; - s->insn_read = pcl812_ao_insn_read; - s->insn_write = pcl812_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &range_unipolar5; + s->insn_read = pcl812_ao_insn_read; + s->insn_write = pcl812_ao_insn_write; switch (board->board_type) { case boardA821: if (it->options[3] == 1) @@ -1342,33 +1362,30 @@ no_dma: subdev++; } - /* digital input */ - if (board->n_dichan > 0) { + if (board->has_dio) { + /* Digital Input subdevice */ s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl812_di_insn_bits; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_di_insn_bits; subdev++; - } - /* digital output */ - if (board->n_dochan > 0) { + /* Digital Output subdevice */ s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl812_do_insn_bits; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_do_insn_bits; subdev++; } switch (board->board_type) { case boardACL8216: - devpriv->ai_is16b = 1; case boardPCL812PG: case boardPCL812: case boardACL8112: @@ -1390,8 +1407,6 @@ no_dma: break; } - devpriv->valid = 1; - pcl812_reset(dev); return 0; @@ -1403,72 +1418,15 @@ static void pcl812_detach(struct comedi_device *dev) if (devpriv) { if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); if (devpriv->dma) free_dma(devpriv->dma); } comedi_legacy_detach(dev); } -static const struct pcl812_board boardtypes[] = { - {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, - 33000, I8254_OSC_BASE_2MHZ, &range_bipolar10, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 33000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, NULL, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_a821pgh_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_acl8113_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_iso813_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, -}; - static struct comedi_driver pcl812_driver = { .driver_name = "pcl812", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index e9d470459933..6f276f23fabe 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -44,40 +44,38 @@ Configuration Options: #include "comedi_fc.h" #include "8253.h" -/* boards constants */ -/* IO space len */ -#define PCLx1x_RANGE 16 - -/* INTEL 8254 counters */ -#define PCL816_CTR0 4 -#define PCL816_CTR1 5 -#define PCL816_CTR2 6 -/* R: counter read-back register W: counter control */ -#define PCL816_CTRCTL 7 - -/* R: A/D high byte W: A/D range control */ -#define PCL816_RANGE 9 -/* W: clear INT request */ -#define PCL816_CLRINT 10 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL816_MUX 11 -/* R/W: operation control register */ -#define PCL816_CONTROL 12 - -/* R: return status byte W: set DMA/IRQ */ -#define PCL816_STATUS 13 -#define PCL816_STATUS_DRDY_MASK 0x80 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL816_AD_LO 8 -/* R: high byte of A/D W: A/D range control */ -#define PCL816_AD_HI 9 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 +/* + * Register I/O map + */ +#define PCL816_DO_DI_LSB_REG 0x00 +#define PCL816_DO_DI_MSB_REG 0x01 +#define PCL816_TIMER_BASE 0x04 +#define PCL816_AI_LSB_REG 0x08 +#define PCL816_AI_MSB_REG 0x09 +#define PCL816_RANGE_REG 0x09 +#define PCL816_CLRINT_REG 0x0a +#define PCL816_MUX_REG 0x0b +#define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL816_CTRL_REG 0x0c +#define PCL816_CTRL_DISABLE_TRIG (0 << 0) +#define PCL816_CTRL_SOFT_TRIG (1 << 0) +#define PCL816_CTRL_PACER_TRIG (1 << 1) +#define PCL816_CTRL_EXT_TRIG (1 << 2) +#define PCL816_CTRL_POE (1 << 3) +#define PCL816_CTRL_DMAEN (1 << 4) +#define PCL816_CTRL_INTEN (1 << 5) +#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6) +#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6) +#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6) +#define PCL816_STATUS_REG 0x0d +#define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL816_STATUS_INTSRC_MASK (3 << 4) +#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4) +#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4) +#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4) +#define PCL816_STATUS_INTSRC_DMA (3 << 4) +#define PCL816_STATUS_INTACT (1 << 6) +#define PCL816_STATUS_DRDY (1 << 7) #define MAGIC_DMA_WORD 0x5a5a @@ -95,314 +93,284 @@ static const struct comedi_lrange range_pcl816 = { }; struct pcl816_board { + const char *name; + int ai_maxdata; + int ao_maxdata; + int ai_chanlist; +}; - const char *name; /* board name */ - int n_ranges; /* len of range list */ - int n_aichan; /* num of A/D chans in diferencial mode */ - unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - int ai_chanlist; /* allowed len of channel list A/D */ - int ao_chanlist; /* allowed len of channel list D/A */ - int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ +static const struct pcl816_board boardtypes[] = { + { + .name = "pcl816", + .ai_maxdata = 0xffff, + .ao_maxdata = 0xffff, + .ai_chanlist = 1024, + }, { + .name = "pcl814b", + .ai_maxdata = 0x3fff, + .ao_maxdata = 0x3fff, + .ai_chanlist = 1024, + }, }; struct pcl816_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ - unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - - unsigned int ai_scans; /* len of scanlist */ - unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */ - int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */ - unsigned int ai_act_chanlist_len; /* how long is actual MUX list */ - unsigned int ai_act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_n_chan; /* how many channels per scan */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -/* -============================================================================== -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int chanlen); -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int seglen); -static int pcl816_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static int pcl816_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); - -/* -============================================================================== - ANALOG INPUT MODE0, 816 cards, slow version -*/ -static int pcl816_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; - - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL816_CONTROL); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Set the input channel */ - outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); - - for (n = 0; n < insn->n; n++) { - - outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */ - - timeout = 100; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) { - /* return read value */ - data[n] = - ((inb(dev->iobase + - PCL816_AD_HI) << 8) | - (inb(dev->iobase + PCL816_AD_LO))); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - break; - } - udelay(1); - } - /* Return timeout error */ - if (!timeout) { - comedi_error(dev, "A/D insn timeout\n"); - data[0] = 0; - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - return -EIO; - } + struct pcl816_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 0, I8254_MODE1 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x00ff); + udelay(1); + + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - return n; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) +static void pcl816_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl816_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned char low, hi; - int timeout = 50; /* wait max 50us */ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) - break; - udelay(1); + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + /* how many */ + bytes = 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; + + /* on last dma transfer must be moved */ + devpriv->last_dma_run = bytes % devpriv->hwdmasize; + devpriv->dma_runs_to_end--; + if (devpriv->dma_runs_to_end >= 0) + bytes = devpriv->hwdmasize; + } else + devpriv->dma_runs_to_end = -1; + + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, bytes); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); +} + +static void pcl816_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long dma_flags; + + disable_dma(devpriv->dma); + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, + devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->dma_runs_to_end) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else + set_dma_count(devpriv->dma, devpriv->last_dma_run); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } - if (!timeout) { /* timeout, bail error */ - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + devpriv->dma_runs_to_end--; +} + +static void pcl816_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) +{ + outb(chan, dev->iobase + PCL816_MUX_REG); + outb(range, dev->iobase + PCL816_RANGE_REG); +} + +static void pcl816_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL816_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL816_MUX_REG); +} + +static void pcl816_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) +{ + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + unsigned int i; + + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + pcl816_ai_set_chan_range(dev, last_chan, range); } - /* get the sample */ - low = inb(dev->iobase + PCL816_AD_LO); - hi = inb(dev->iobase + PCL816_AD_HI); + udelay(1); + + pcl816_ai_set_chan_scan(dev, first_chan, last_chan); +} + +static void pcl816_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL816_CLRINT_REG); +} + +static void pcl816_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL816_AI_LSB_REG); +} - comedi_buf_put(s->async, (hi << 8) | low); +static unsigned int pcl816_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ + val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL816_AI_LSB_REG); - if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len) - devpriv->ai_act_chanlist_pos = 0; + return val & s->maxdata; +} + +static int pcl816_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + PCL816_STATUS_REG); + if ((status & PCL816_STATUS_DRDY) == 0) + return 0; + return -EBUSY; +} + +static bool pcl816_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { + if (s->async->cur_chan >= cmd->chanlist_len) { s->async->cur_chan = 0; devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; } - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); - return IRQ_HANDLED; + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; + } + + return true; } -/* -============================================================================== - analog input dma mode 1 & 3, 816 cards -*/ static void transfer_from_dma_buf(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short *ptr, unsigned int bufptr, unsigned int len) { - struct pcl816_private *devpriv = dev->private; int i; - s->async->events = 0; - for (i = 0; i < len; i++) { - comedi_buf_put(s->async, ptr[bufptr++]); - if (++devpriv->ai_act_chanlist_pos >= - devpriv->ai_act_chanlist_len) { - devpriv->ai_act_chanlist_pos = 0; - } - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - } - - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_BLOCK; - break; - } + if (!pcl816_ai_next_chan(dev, s)) + return; } - - comedi_event(dev, s); } -static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) +static irqreturn_t pcl816_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct pcl816_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - int len, bufptr, this_dma_buf; - unsigned long dma_flags; + struct pcl816_private *devpriv = dev->private; unsigned short *ptr; + unsigned int bufptr; + unsigned int len; - disable_dma(devpriv->dma); - this_dma_buf = devpriv->next_dma_buf; - - /* switch dma bufs */ - if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; + } - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); -/* clear_dma_ff (devpriv->dma); */ - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); + if (devpriv->ai_cmd_canceled) { + devpriv->ai_cmd_canceled = 0; + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; } - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; - ptr = (unsigned short *)devpriv->dmabuf[this_dma_buf]; + pcl816_ai_setup_next_dma(dev, s); - len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr; + len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr; bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); - return IRQ_HANDLED; -} - -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl816(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl816_private *devpriv = dev->private; - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; - } - - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl816_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl816_ai_mode13_int(irq, d); - } + pcl816_ai_clear_eoc(dev); - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - if (!dev->irq || !devpriv->irq_blocked || !devpriv->int816_mode) { - if (devpriv->irq_was_now_closed) { - devpriv->irq_was_now_closed = 0; - /* comedi_error(dev,"last IRQ.."); */ - return IRQ_HANDLED; - } - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl816_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcl816_board *board = comedi_board(dev); + struct pcl816_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; + int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -432,8 +400,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); if (cmd->convert_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - board->ai_ns_min); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); else /* TRIG_EXT */ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); @@ -451,11 +418,12 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, &cmd->convert_arg, cmd->flags); - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; + if (cmd->convert_arg < 10000) + cmd->convert_arg = 10000; if (tmp != cmd->convert_arg) err++; } @@ -477,120 +445,40 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl; unsigned int seglen; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; -/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */ - if (devpriv->irq_blocked) + if (devpriv->ai_cmd_running) return -EBUSY; - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, cmd->flags); - - /* PCL816 crash if any divisor is set to 1 */ - if (divisor1 == 1) { - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl816_start_pacer(dev, false); seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); if (seglen < 1) return -EINVAL; - setup_channel_list(dev, s, cmd->chanlist, seglen); + pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen); udelay(1); - devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->irq_blocked = 1; + devpriv->ai_cmd_running = 1; devpriv->ai_poll_ptr = 0; - devpriv->irq_was_now_closed = 0; + devpriv->ai_cmd_canceled = 0; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; - } - - if (devpriv->dma) { - bytes = devpriv->hwdmasize[0]; - if (!devpriv->ai_neverending) { - /* how many */ - bytes = s->async->cmd.chanlist_len * - s->async->cmd.chanlist_len * - sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = bytes / - devpriv->hwdmasize[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } else - devpriv->dma_runs_to_end = -1; - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } - - start_pacer(dev, 1, divisor1, divisor2); - dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7); - - switch (cmd->convert_src) { - case TRIG_TIMER: - devpriv->int816_mode = INT_TYPE_AI1_DMA; - - /* Pacer+IRQ+DMA */ - outb(0x32, dev->iobase + PCL816_CONTROL); + pcl816_ai_setup_dma(dev, s); - /* write irq and DMA to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; + pcl816_start_pacer(dev, true); - default: - devpriv->int816_mode = INT_TYPE_AI3_DMA; - - /* Ext trig+IRQ+DMA */ - outb(0x34, dev->iobase + PCL816_CONTROL); + ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL816_CTRL_PACER_TRIG; + else /* TRIG_EXT */ + ctrl |= PCL816_CTRL_EXT_TRIG; - /* write irq to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; - } + outb(ctrl, dev->iobase + PCL816_CTRL_REG); + outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG); return 0; } @@ -601,9 +489,6 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) unsigned long flags; unsigned int top1, top2, i; - if (!devpriv->dma) - return 0; /* poll is valid only for DMA transfer */ - spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < 20; i++) { @@ -618,7 +503,7 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) } /* where is now DMA in buffer */ - top1 = devpriv->hwdmasize[0] - top1; + top1 = devpriv->hwdmasize - top1; top1 >>= 1; /* sample position */ top2 = top1 - devpriv->ai_poll_ptr; if (top2 < 1) { /* no new samples */ @@ -634,134 +519,34 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_poll_ptr = top1; /* new buffer position */ spin_unlock_irqrestore(&dev->spinlock, flags); + cfc_handle_events(dev, s); + return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl816_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; - if (devpriv->irq_blocked > 0) { - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, - dev->iobase + PCL816_CONTROL); /* Stop A/D */ - udelay(1); - outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ - - /* Stop pacer */ - outb(0xb0, dev->iobase + PCL816_CTRCTL); - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_HI); - - /* clear INT request */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Stop A/D */ - outb(0, dev->iobase + PCL816_CONTROL); - devpriv->irq_blocked = 0; - devpriv->irq_was_now_closed = devpriv->int816_mode; - devpriv->int816_mode = 0; - devpriv->last_int_sub = s; -/* s->busy = 0; */ - break; - } - } - return 0; -} - -/* -============================================================================== - chech for PCL816 -*/ -static int pcl816_check(unsigned long iobase) -{ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - outb(0x18, iobase + PCL816_CONTROL); - udelay(1); - if (inb(iobase + PCL816_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ -} - -/* -============================================================================== - reset whole PCL-816 cards -*/ -static void pcl816_reset(struct comedi_device *dev) -{ -/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */ -/* outb (0, dev->iobase + PCL818_DA_HI); */ -/* udelay (1); */ -/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */ -/* outb (0, dev->iobase + PCL818_DO_LO); */ -/* udelay (1); */ - outb(0, dev->iobase + PCL816_CONTROL); - outb(0, dev->iobase + PCL816_MUX); - outb(0, dev->iobase + PCL816_CLRINT); - outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0x30, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_RANGE); -} + if (!devpriv->ai_cmd_running) + return 0; -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void -start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, - unsigned int divisor2) -{ - outb(0x32, dev->iobase + PCL816_CTRCTL); - outb(0xff, dev->iobase + PCL816_CTR0); - outb(0x00, dev->iobase + PCL816_CTR0); - udelay(1); + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - /* set counter 2 as mode 3 */ - outb(0xb4, dev->iobase + PCL816_CTRCTL); - /* set counter 1 as mode 3 */ - outb(0x74, dev->iobase + PCL816_CTRCTL); - udelay(1); + /* Stop pacer */ + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 1, I8254_MODE0 | I8254_BINARY); - if (mode == 1) { - dev_dbg(dev->class_dev, "mode %d, divisor1 %d, divisor2 %d\n", - mode, divisor1, divisor2); - outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1); - } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 1; - /* clear pending interrupts (just in case) */ -/* outb(0, dev->iobase + PCL816_CLRINT); */ + return 0; } -/* -============================================================================== - Check if channel list from user is built correctly - If it's ok, then return non-zero length of repeated segment of channel list -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, @@ -818,180 +603,181 @@ check_channel_list(struct comedi_device *dev, return seglen; /* we can serve this with MUX logic */ } -/* -============================================================================== - Program scan/gain logic with channel list. -*/ -static void -setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int *chanlist, - unsigned int seglen) +static int pcl816_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pcl816_private *devpriv = dev->private; - unsigned int i; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; - devpriv->ai_act_chanlist_len = seglen; - devpriv->ai_act_chanlist_pos = 0; + outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG); - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); + pcl816_ai_set_chan_range(dev, chan, range); + pcl816_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl816_ai_clear_eoc(dev); + pcl816_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl816_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl816_ai_get_sample(dev, s); } + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - udelay(1); - /* select channel interval to scan */ - outb(devpriv->ai_act_chanlist[0] | - (devpriv->ai_act_chanlist[seglen - 1] << 4), - dev->iobase + PCL816_MUX); + return ret ? ret : insn->n; +} + +static int pcl816_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl816_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG); + } + + data[1] = s->state; + + return insn->n; +} + +static void pcl816_reset(struct comedi_device *dev) +{ + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_set_chan_range(dev, 0, 0); + pcl816_ai_clear_eoc(dev); + + /* Stop pacer */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL816_DO_DI_LSB_REG); + outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); } static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv; - int ret; - unsigned int dma; - unsigned long pages; - /* int i; */ struct comedi_subdevice *s; - - ret = comedi_request_region(dev, it->options[0], board->io_range); - if (ret) - return ret; - - if (pcl816_check(dev->iobase)) { - dev_err(dev->class_dev, "I can't detect board. FAIL!\n"); - return -EIO; - } + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl816, 0, + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl816_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->int816_mode = 0; /* mode of irq */ - - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - - if (((1 << dma) & board->DMAbits) == 0) { - dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { dev_err(dev->class_dev, - "unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ + "unable to request DMA channel %d\n", + it->options[2]); + return -EBUSY; } + devpriv->dma = it->options[2]; - devpriv->dma = dma; - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; - if (!devpriv->dmabuf[0]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; + for (i = 0; i < 2; i++) { + unsigned long dmabuf; - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - return -EBUSY; + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; } -no_dma: - -/* if (board->n_aochan > 0) - subdevs[1] = COMEDI_SUBD_AO; - if (board->n_dichan > 0) - subdevs[2] = COMEDI_SUBD_DI; - if (board->n_dochan > 0) - subdevs[3] = COMEDI_SUBD_DO; -*/ - - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (board->n_aichan > 0) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_CMD_READ | SDF_DIFF; - s->n_chan = board->n_aichan; - s->maxdata = board->ai_maxdata; - s->range_table = board->ai_range_type; - s->insn_read = pcl816_ai_insn_read; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = board->ai_chanlist; - s->do_cmdtest = pcl816_ai_cmdtest; - s->do_cmd = pcl816_ai_cmd; - s->poll = pcl816_ai_poll; - s->cancel = pcl816_ai_cancel; - } - } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_CMD_READ | SDF_DIFF; + s->n_chan = 16; + s->maxdata = board->ai_maxdata; + s->range_table = &range_pcl816; + s->insn_read = pcl816_ai_insn_read; + if (devpriv->dma) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = board->ai_chanlist; + s->do_cmdtest = pcl816_ai_cmdtest; + s->do_cmd = pcl816_ai_cmd; + s->poll = pcl816_ai_poll; + s->cancel = pcl816_ai_cancel; } + /* Analog OUtput subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_UNUSED; #if 0 -case COMEDI_SUBD_AO: + subdevs[1] = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; + s->n_chan = 1; s->maxdata = board->ao_maxdata; - s->len_chanlist = board->ao_chanlist; - s->range_table = board->ao_range_type; - break; - -case COMEDI_SUBD_DI: - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->len_chanlist = board->n_dichan; - s->range_table = &range_digital; - break; - -case COMEDI_SUBD_DO: - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->len_chanlist = board->n_dochan; - s->range_table = &range_digital; - break; + s->range_table = &range_pcl816; #endif + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_do_insn_bits; + pcl816_reset(dev); return 0; @@ -1007,34 +793,13 @@ static void pcl816_detach(struct comedi_device *dev) if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl816_board boardtypes[] = { - {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, /* IRQ mask */ - 0x0a, /* DMA mask */ - 0xffff, /* 16-bit card */ - 0xffff, /* D/A maxdata */ - 1024, - 1, /* ao chan list */ - I8254_OSC_BASE_10MHZ}, - {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, - 0x0a, - 0x3fff, /* 14 bit card */ - 0x3fff, - 1024, - 1, - I8254_OSC_BASE_10MHZ}, -}; - static struct comedi_driver pcl816_driver = { .driver_name = "pcl816", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index fa1758ad49d5..6463476ce45a 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -110,8 +110,6 @@ A word or two about DMA. Driver support DMA operations at two ways: #include "comedi_fc.h" #include "8253.h" -/* #define PCL818_MODE13_AO 1 */ - /* boards constants */ #define boardPCL818L 0 @@ -121,46 +119,38 @@ A word or two about DMA. Driver support DMA operations at two ways: #define boardPCL818 4 #define boardPCL718 5 -/* IO space len */ -#define PCLx1x_RANGE 16 -/* IO space len if we use FIFO */ -#define PCLx1xFIFO_RANGE 32 - -/* W: clear INT request */ -#define PCL818_CLRINT 8 -/* R: return status byte */ -#define PCL818_STATUS 8 -/* R: A/D high byte W: A/D range control */ -#define PCL818_RANGE 1 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL818_MUX 2 -/* R/W: operation control register */ -#define PCL818_CONTROL 9 -/* W: counter enable */ -#define PCL818_CNTENABLE 10 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL818_AD_LO 0 -/* R: high byte of A/D W: A/D range control */ -#define PCL818_AD_HI 1 -/* W: D/A low&high byte */ -#define PCL818_DA_LO 4 -#define PCL818_DA_HI 5 -/* R: low&high byte of DI */ -#define PCL818_DI_LO 3 -#define PCL818_DI_HI 11 -/* W: low&high byte of DO */ -#define PCL818_DO_LO 3 -#define PCL818_DO_HI 11 -/* W: PCL718 second D/A */ -#define PCL718_DA2_LO 6 -#define PCL718_DA2_HI 7 -/* counters */ -#define PCL818_CTR0 12 -#define PCL818_CTR1 13 -#define PCL818_CTR2 14 -/* W: counter control */ -#define PCL818_CTRCTL 15 +/* + * Register I/O map + */ +#define PCL818_AI_LSB_REG 0x00 +#define PCL818_AI_MSB_REG 0x01 +#define PCL818_RANGE_REG 0x01 +#define PCL818_MUX_REG 0x02 +#define PCL818_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL818_DO_DI_LSB_REG 0x03 +#define PCL818_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL818_STATUS_REG 0x08 +#define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL818_STATUS_INT (1 << 4) +#define PCL818_STATUS_MUX (1 << 5) +#define PCL818_STATUS_UNI (1 << 6) +#define PCL818_STATUS_EOC (1 << 7) +#define PCL818_CTRL_REG 0x09 +#define PCL818_CTRL_DISABLE_TRIG (0 << 0) +#define PCL818_CTRL_SOFT_TRIG (1 << 0) +#define PCL818_CTRL_EXT_TRIG (2 << 0) +#define PCL818_CTRL_PACER_TRIG (3 << 0) +#define PCL818_CTRL_DMAE (1 << 2) +#define PCL818_CTRL_IRQ(x) ((x) << 4) +#define PCL818_CTRL_INTE (1 << 7) +#define PCL818_CNTENABLE_REG 0x0a +#define PCL818_CNTENABLE_PACER_ENA (0 << 0) +#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0) +#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1) +#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1) +#define PCL818_DO_DI_MSB_REG 0x0b +#define PCL818_TIMER_BASE 0x0c /* W: fifo enable/disable */ #define PCL818_FI_ENABLE 6 @@ -172,19 +162,7 @@ A word or two about DMA. Driver support DMA operations at two ways: #define PCL818_FI_STATUS 25 /* R: one record from FIFO */ #define PCL818_FI_DATALO 23 -#define PCL818_FI_DATAHI 23 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI1_FIFO 3 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 -#define INT_TYPE_AI3_FIFO 6 -#ifdef PCL818_MODE13_AO -#define INT_TYPE_AO1_INT 7 -#define INT_TYPE_AO3_INT 8 -#endif +#define PCL818_FI_DATAHI 24 #define MAGIC_DMA_WORD 0x5a5a @@ -262,630 +240,439 @@ static const struct comedi_lrange range718_unipolar1 = { }; struct pcl818_board { + const char *name; + unsigned int ns_min; + int n_aochan; + const struct comedi_lrange *ai_range_type; + unsigned int has_dma:1; + unsigned int has_fifo:1; + unsigned int is_818:1; +}; - const char *name; /* driver name */ - int n_ranges; /* len of range list */ - int n_aichan_se; /* num of A/D chans in single ended mode */ - int n_aichan_diff; /* num of A/D chans in diferencial mode */ - unsigned int ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - unsigned char fifo; /* 1=board has FIFO */ - int is_818; +static const struct pcl818_board boardtypes[] = { + { + .name = "pcl818l", + .ns_min = 25000, + .n_aochan = 1, + .ai_range_type = &range_pcl818l_l_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818h", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818hd", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818hg", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818hg_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818", + .ns_min = 10000, + .n_aochan = 2, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl718", + .ns_min = 16000, + .n_aochan = 2, + .ai_range_type = &range_unipolar5, + .has_dma = 1, + }, { + .name = "pcm3718", + .ns_min = 10000, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, }; struct pcl818_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ - unsigned int io_range; + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */ unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */ int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */ - int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ int ai_act_chan; /* actual position in actual scan */ unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ unsigned int act_chanlist_len; /* how long is actual MUX list */ unsigned int act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; - unsigned char usefifo; /* 1=use fifo */ unsigned int ao_readback[2]; + unsigned int divisor1; + unsigned int divisor2; + unsigned int usefifo:1; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */ - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff -}; - -/* -============================================================================== -*/ -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen); -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); - -static int pcl818_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); - -/* -============================================================================== - ANALOG INPUT MODE0, 818 cards, slow version -*/ -static int pcl818_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; + struct pcl818_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL818_CONTROL); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); - /* select channel */ - outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX); + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + } +} - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE); +static void pcl818_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int flags; + unsigned int bytes; - for (n = 0; n < insn->n; n++) { + disable_dma(devpriv->dma); /* disable dma */ + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + bytes = cmd->chanlist_len * cmd->stop_arg * sizeof(short); + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; + devpriv->last_dma_run = bytes % devpriv->hwdmasize; + devpriv->dma_runs_to_end--; + if (devpriv->dma_runs_to_end >= 0) + bytes = devpriv->hwdmasize; + } - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, bytes); + release_dma_lock(flags); + enable_dma(devpriv->dma); +} - /* start conversion */ - outb(0, dev->iobase + PCL818_AD_LO); +static void pcl818_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long flags; - timeout = 100; - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - comedi_error(dev, "A/D insn timeout"); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); - return -EIO; - -conv_finish: - data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) | - (inb(dev->iobase + PCL818_AD_LO) >> 4)); + disable_dma(devpriv->dma); + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ + set_dma_mode(devpriv->dma, DMA_MODE_READ); + flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, + devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else + set_dma_count(devpriv->dma, devpriv->last_dma_run); + release_dma_lock(flags); + enable_dma(devpriv->dma); } - return n; + devpriv->dma_runs_to_end--; } -/* -============================================================================== - ANALOG OUTPUT MODE0, 818 cards - only one sample per call is supported -*/ -static int pcl818_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) { - struct pcl818_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + outb(chan, dev->iobase + PCL818_MUX_REG); + outb(range, dev->iobase + PCL818_RANGE_REG); +} - return n; +static void pcl818_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL818_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL818_MUX_REG); } -static int pcl818_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) { struct pcl818_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - devpriv->ao_readback[chan] = data[n]; - outb((data[n] & 0x000f) << 4, dev->iobase + - (chan ? PCL718_DA2_LO : PCL818_DA_LO)); - outb((data[n] & 0x0ff0) >> 4, dev->iobase + - (chan ? PCL718_DA2_HI : PCL818_DA_HI)); + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + int i; + + devpriv->act_chanlist_len = seglen; + devpriv->act_chanlist_pos = 0; + + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + devpriv->act_chanlist[i] = last_chan; + + pcl818_ai_set_chan_range(dev, last_chan, range); } - return n; + udelay(1); + + pcl818_ai_set_chan_scan(dev, first_chan, last_chan); } -/* -============================================================================== - DIGITAL INPUT MODE0, 818 cards +static void pcl818_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL818_STATUS_REG); +} - only one sample per call is supported -*/ -static int pcl818_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_soft_trig(struct comedi_device *dev) { - data[1] = inb(dev->iobase + PCL818_DI_LO) | - (inb(dev->iobase + PCL818_DI_HI) << 8); + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL818_AI_LSB_REG); +} - return insn->n; +static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) +{ + unsigned int val; + + val = inb(dev->iobase + PCL818_FI_DATALO); + val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8); + + if (chan) + *chan = val & 0xf; + + return (val >> 4) & s->maxdata; } -static int pcl818_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static unsigned int pcl818_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) { - if (comedi_dio_update_state(s, data)) { - outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); - outb((s->state >> 8), dev->iobase + PCL818_DO_HI); - } + unsigned int val; - data[1] = s->state; + val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL818_AI_LSB_REG); - return insn->n; + if (chan) + *chan = val & 0xf; + + return (val >> 4) & s->maxdata; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) +static int pcl818_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned char low; - int timeout = 50; /* wait max 50us */ + unsigned int status; - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + status = inb(dev->iobase + PCL818_STATUS_REG); + if (status & PCL818_STATUS_INT) + return 0; + return -EBUSY; +} -conv_finish: - low = inb(dev->iobase + PCL818_AD_LO); - comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */ - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ +static bool pcl818_ai_dropout(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int expected_chan; - if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ + expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos]; + if (chan != expected_chan) { dev_dbg(dev->class_dev, - "A/D mode1/3 IRQ - channel dropout %x!=%x !\n", - (low & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); + "A/D mode1/3 %s - channel dropout %d!=%d !\n", + (devpriv->dma) ? "DMA" : + (devpriv->usefifo) ? "FIFO" : "IRQ", + chan, expected_chan); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return true; } + return false; +} + +static bool pcl818_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; + devpriv->act_chanlist_pos++; if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) devpriv->act_chanlist_pos = 0; s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { + if (s->async->cur_chan >= cmd->chanlist_len) { s->async->cur_chan = 0; devpriv->ai_act_scan--; + s->async->events |= COMEDI_CB_EOS; } - if (!devpriv->neverending_ai) { - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - comedi_event(dev, s); - return IRQ_HANDLED; + + return true; } -/* -============================================================================== - analog input dma mode 1 & 3, 818 cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) +static void pcl818_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int chan; + unsigned int val; + + if (pcl818_ai_eoc(dev, s, NULL, 0)) { + comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; + } + + val = pcl818_ai_get_sample(dev, s, &chan); + + if (pcl818_ai_dropout(dev, s, chan)) + return; + + comedi_buf_put(s->async, val); + + pcl818_ai_next_chan(dev, s); +} + +static void pcl818_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - int i, len, bufptr; - unsigned long flags; unsigned short *ptr; + unsigned int chan; + unsigned int val; + int i, len, bufptr; - disable_dma(devpriv->dma); - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */ - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end || devpriv->neverending_ai) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(flags); - enable_dma(devpriv->dma); - } + pcl818_ai_setup_next_dma(dev, s); - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; - len = devpriv->hwdmasize[0] >> 1; + len = devpriv->hwdmasize >> 1; bufptr = 0; for (i = 0; i < len; i++) { - if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - dev_dbg(dev->class_dev, - "A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n", - (ptr[bufptr] & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos], - devpriv->act_chanlist_pos); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } + val = ptr[bufptr++]; + chan = val & 0xf; + val = (val >> 4) & s->maxdata; - comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ + if (pcl818_ai_dropout(dev, s, chan)) + break; - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; + comedi_buf_put(s->async, val); - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } - - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } + if (!pcl818_ai_next_chan(dev, s)) + break; } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818HD/HG cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) +static void pcl818_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; + unsigned int status; + unsigned int chan; + unsigned int val; int i, len; - unsigned char lo; - outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ + status = inb(dev->iobase + PCL818_FI_STATUS); - lo = inb(dev->iobase + PCL818_FI_STATUS); - - if (lo & 4) { + if (status & 4) { comedi_error(dev, "A/D mode1/3 FIFO overflow!"); - pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - if (lo & 1) { + if (status & 1) { comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); - pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - if (lo & 2) + if (status & 2) len = 512; else len = 0; for (i = 0; i < len; i++) { - lo = inb(dev->iobase + PCL818_FI_DATALO); - if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - dev_dbg(dev->class_dev, - "A/D mode1/3 FIFO - channel dropout %d!=%d !\n", - (lo & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } + val = pcl818_ai_get_fifo_sample(dev, s, &chan); - comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ - - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; + if (pcl818_ai_dropout(dev, s, chan)) + break; - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } + comedi_buf_put(s->async, val); - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } + if (!pcl818_ai_next_chan(dev, s)) + break; } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; } -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl818(int irq, void *d) +static irqreturn_t pcl818_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl818_ai_clear_eoc(dev); return IRQ_HANDLED; } - if (devpriv->irq_blocked && devpriv->irq_was_now_closed) { - if ((devpriv->neverending_ai || (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) && - (devpriv->ai_mode == INT_TYPE_AI1_DMA || - devpriv->ai_mode == INT_TYPE_AI3_DMA)) { - /* The cleanup from ai_cancel() has been delayed - until now because the card doesn't seem to like - being reprogrammed while a DMA transfer is in - progress. - */ - devpriv->ai_act_scan = 0; - devpriv->neverending_ai = 0; - pcl818_ai_cancel(dev, dev->read_subdev); - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - + if (devpriv->ai_cmd_canceled) { + /* + * The cleanup from ai_cancel() has been delayed + * until now because the card doesn't seem to like + * being reprogrammed while a DMA transfer is in + * progress. + */ + devpriv->ai_act_scan = 0; + s->cancel(dev, s); return IRQ_HANDLED; } - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl818_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl818_ai_mode13_int(irq, d); - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: - return interrupt_pcl818_ai_mode13_fifo(irq, d); -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: - return interrupt_pcl818_ao_mode13_int(irq, d); -#endif - default: - break; - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - if (!devpriv->irq_blocked || !devpriv->ai_mode) { - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; -} - -/* -============================================================================== - ANALOG INPUT MODE 1 or 3 DMA , 818 cards -*/ -static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl818_private *devpriv = dev->private; - unsigned int flags; - unsigned int bytes; - - disable_dma(devpriv->dma); /* disable dma */ - bytes = devpriv->hwdmasize[0]; - if (!devpriv->neverending_ai) { - bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */ - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(flags); - enable_dma(devpriv->dma); - - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_DMA; - outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */ - } else { - devpriv->ai_mode = INT_TYPE_AI3_DMA; - outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */ - } -} - -/* -============================================================================== - ANALOG INPUT MODE 1 or 3, 818 cards -*/ -static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl818_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - int divisor1 = 0, divisor2 = 0; - unsigned int seglen; - - if (devpriv->irq_blocked) - return -EBUSY; - - start_pacer(dev, -1, 0, 0); /* stop pacer */ - - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); - - udelay(1); - - devpriv->ai_act_scan = devpriv->ai_scans; - devpriv->ai_act_chan = 0; - devpriv->irq_blocked = 1; - devpriv->irq_was_now_closed = 0; - devpriv->neverending_ai = 0; - devpriv->act_chanlist_pos = 0; - devpriv->dma_runs_to_end = 0; - - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; /* well, user want neverending */ - - if (mode == 1) { - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, - TRIG_ROUND_NEAREST); - if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */ - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ - - switch (devpriv->dma) { - case 1: /* DMA */ - case 3: - pcl818_ai_mode13dma_int(mode, dev, s); - break; - case 0: - if (!devpriv->usefifo) { - /* IRQ */ - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_INT; - /* Pacer+IRQ */ - outb(0x83 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_INT; - /* Ext trig+IRQ */ - outb(0x82 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } - } else { - /* FIFO */ - /* enable FIFO */ - outb(1, dev->iobase + PCL818_FI_ENABLE); - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_FIFO; - /* Pacer */ - outb(0x03, dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_FIFO; - outb(0x02, dev->iobase + PCL818_CONTROL); - } - } - } - - start_pacer(dev, mode, divisor1, divisor2); - - return 0; -} + if (devpriv->dma) + pcl818_handle_dma(dev, s); + else if (devpriv->usefifo) + pcl818_handle_fifo(dev, s); + else + pcl818_handle_eoc(dev, s); -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - outb(0xb4, dev->iobase + PCL818_CTRCTL); - outb(0x74, dev->iobase + PCL818_CTRCTL); - udelay(1); + pcl818_ai_clear_eoc(dev); - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1); - } + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== - Check if channel list from user is builded correctly - If it's ok, then program scan/gain logic -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) @@ -941,52 +728,20 @@ static int check_channel_list(struct comedi_device *dev, return seglen; } -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) -{ - struct pcl818_private *devpriv = dev->private; - int i; - - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */ - outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */ - } - - udelay(1); - - /* select channel interval to scan */ - outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen - - 1] << 4), - dev->iobase + PCL818_MUX); -} - -/* -============================================================================== - Check if board is switched to SE (1) or DIFF(0) mode -*/ static int check_single_ended(unsigned int port) { - if (inb(port + PCL818_STATUS) & 0x20) + if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX) return 1; return 0; } -/* -============================================================================== -*/ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcl818_board *board = comedi_board(dev); struct pcl818_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; + int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -1035,7 +790,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, - &divisor1, &divisor2, + &devpriv->divisor1, + &devpriv->divisor2, &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < board->ns_min) cmd->convert_arg = board->ns_min; @@ -1057,152 +813,272 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* -============================================================================== -*/ -static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int pcl818_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int retval; + unsigned int ctrl = 0; + unsigned int seglen; + + if (devpriv->ai_cmd_running) + return -EBUSY; + + pcl818_start_pacer(dev, false); + + seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); + if (seglen < 1) + return -EINVAL; + pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen); - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; + devpriv->ai_act_scan = cmd->stop_arg; + devpriv->ai_act_chan = 0; + devpriv->ai_cmd_running = 1; + devpriv->ai_cmd_canceled = 0; + devpriv->act_chanlist_pos = 0; + devpriv->dma_runs_to_end = 0; - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans = cmd->stop_arg; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL818_CTRL_PACER_TRIG; else - devpriv->ai_scans = 0; + ctrl |= PCL818_CTRL_EXT_TRIG; - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ - devpriv->ai_timer1 = cmd->convert_arg; - retval = pcl818_ai_cmd_mode(1, dev, s); - return retval; - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pcl818_ai_cmd_mode(3, dev, s); - } + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + + if (devpriv->dma) { + pcl818_ai_setup_dma(dev, s); + + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) | + PCL818_CTRL_DMAE; + } else if (devpriv->usefifo) { + /* enable FIFO */ + outb(1, dev->iobase + PCL818_FI_ENABLE); + } else { + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq); } + outb(ctrl, dev->iobase + PCL818_CTRL_REG); + + if (cmd->convert_src == TRIG_TIMER) + pcl818_start_pacer(dev, true); - return -1; + return 0; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (devpriv->irq_blocked > 0) { - devpriv->irq_was_now_closed = 1; - - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - if (devpriv->neverending_ai || - (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) { - /* wait for running dma transfer to end, do cleanup in interrupt */ - goto end; - } - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: -#endif - outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - udelay(1); - start_pacer(dev, -1, 0, 0); - outb(0, dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_HI); - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - if (devpriv->usefifo) { /* FIFO shutdown */ - outb(0, dev->iobase + PCL818_FI_INTCLR); - outb(0, dev->iobase + PCL818_FI_FLUSH); - outb(0, dev->iobase + PCL818_FI_ENABLE); + if (!devpriv->ai_cmd_running) + return 0; + + if (devpriv->dma) { + if (cmd->stop_src == TRIG_NONE || + (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) { + if (!devpriv->ai_cmd_canceled) { + /* + * Wait for running dma transfer to end, + * do cleanup in interrupt. + */ + devpriv->ai_cmd_canceled = 1; + return 0; } - devpriv->irq_blocked = 0; - devpriv->last_int_sub = s; - devpriv->neverending_ai = 0; - devpriv->ai_mode = 0; - devpriv->irq_was_now_closed = 0; - break; } + disable_dma(devpriv->dma); + } + + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_start_pacer(dev, false); + pcl818_ai_clear_eoc(dev); + + if (devpriv->usefifo) { /* FIFO shutdown */ + outb(0, dev->iobase + PCL818_FI_INTCLR); + outb(0, dev->iobase + PCL818_FI_FLUSH); + outb(0, dev->iobase + PCL818_FI_ENABLE); } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 0; -end: return 0; } -/* -============================================================================== - chech for PCL818 -*/ -static int pcl818_check(unsigned long iobase) +static int pcl818_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - outb(0x00, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL818_MUX); - udelay(1); - outb(0x18, iobase + PCL818_CONTROL); - udelay(1); - if (inb(iobase + PCL818_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; + + outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG); + + pcl818_ai_set_chan_range(dev, chan, range); + pcl818_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl818_ai_clear_eoc(dev); + pcl818_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl818_ai_get_sample(dev, s, NULL); + } + pcl818_ai_clear_eoc(dev); + + return ret ? ret : insn->n; +} + +static int pcl818_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) { + devpriv->ao_readback[chan] = data[i]; + outb((data[i] & 0x000f) << 4, + dev->iobase + PCL818_AO_LSB_REG(chan)); + outb((data[i] & 0x0ff0) >> 4, + dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + return insn->n; +} + +static int pcl818_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int pcl818_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl818_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG); + } + + data[1] = s->state; + + return insn->n; } -/* -============================================================================== - reset whole PCL-818 cards -*/ static void pcl818_reset(struct comedi_device *dev) { const struct pcl818_board *board = comedi_board(dev); - struct pcl818_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; + unsigned int chan; - if (devpriv->usefifo) { /* FIFO shutdown */ + /* flush and disable the FIFO */ + if (board->has_fifo) { outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); } - outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */ - outb(0, dev->iobase + PCL818_DA_HI); - udelay(1); - outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */ - outb(0, dev->iobase + PCL818_DO_LO); - udelay(1); - outb(0, dev->iobase + PCL818_CONTROL); - outb(0, dev->iobase + PCL818_CNTENABLE); - outb(0, dev->iobase + PCL818_MUX); - outb(0, dev->iobase + PCL818_CLRINT); - outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL818_CTRCTL); - outb(0x30, dev->iobase + PCL818_CTRCTL); + + /* disable analog input trigger */ + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_ai_clear_eoc(dev); + + pcl818_ai_set_chan_range(dev, 0, 0); + + /* stop pacer */ + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL818_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL818_DO_DI_MSB_REG); + outb(0, dev->iobase + PCL818_DO_DI_LSB_REG); +} + +static void pcl818_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl818_board *board = comedi_board(dev); + + /* default to the range table from the boardinfo */ + s->range_table = board->ai_range_type; + + /* now check the user config option based on the boardtype */ if (board->is_818) { - outb(0, dev->iobase + PCL818_RANGE); + if (it->options[4] == 1 || it->options[4] == 10) { + /* secondary range list jumper selectable */ + s->range_table = &range_pcl818l_h_ai; + } } else { - outb(0, dev->iobase + PCL718_DA2_LO); - outb(0, dev->iobase + PCL718_DA2_HI); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range718_bipolar1; + break; + case 4: + s->range_table = &range718_bipolar0_5; + break; + case 6: + s->range_table = &range_unipolar10; + break; + case 7: + s->range_table = &range_unipolar5; + break; + case 8: + s->range_table = &range718_unipolar2; + break; + case 9: + s->range_table = &range718_unipolar1; + break; + default: + s->range_table = &range_unknown; + break; + } } } @@ -1210,154 +1086,96 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl818_board *board = comedi_board(dev); struct pcl818_private *devpriv; - int ret; - int dma; - unsigned long pages; struct comedi_subdevice *s; + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - devpriv->io_range = board->io_range; - if ((board->fifo) && (it->options[2] == -1)) { - /* we've board with FIFO and we want to use FIFO */ - devpriv->io_range = PCLx1xFIFO_RANGE; - devpriv->usefifo = 1; - } - ret = comedi_request_region(dev, it->options[0], devpriv->io_range); + ret = comedi_request_region(dev, it->options[0], + board->has_fifo ? 0x20 : 0x10); if (ret) return ret; - if (pcl818_check(dev->iobase)) { - comedi_error(dev, "I can't detect board. FAIL!\n"); - return -EIO; - } - - if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl818, 0, + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl818_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->ai_mode = 0; /* mode of irq */ - - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - if (((1 << dma) & board->DMAbits) == 0) { + /* should we use the FIFO? */ + if (dev->irq && board->has_fifo && it->options[2] == -1) + devpriv->usefifo = 1; + + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); + if (ret) { dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); - if (ret) - return -EBUSY; /* DMA isn't free */ - devpriv->dma = dma; - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) - /* maybe experiment with try_to_free_pages() will help .... */ - return -EBUSY; /* no buffer :-( */ - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; - } + } + devpriv->dma = it->options[2]; + + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; -no_dma: + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } + } ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (!board->n_aichan_se) { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (check_single_ended(dev->iobase)) { + s->n_chan = 16; + s->subdev_flags |= SDF_COMMON | SDF_GROUND; } else { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - if (check_single_ended(dev->iobase)) { - s->n_chan = board->n_aichan_se; - s->subdev_flags |= SDF_COMMON | SDF_GROUND; - } else { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - } - s->maxdata = board->ai_maxdata; - s->range_table = board->ai_range_type; - s->insn_read = pcl818_ai_insn_read; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = s->n_chan; - s->do_cmdtest = ai_cmdtest; - s->do_cmd = ai_cmd; - s->cancel = pcl818_ai_cancel; - } - if (board->is_818) { - if ((it->options[4] == 1) || (it->options[4] == 10)) - s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */ - } else { - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range718_bipolar1; - break; - case 4: - s->range_table = &range718_bipolar0_5; - break; - case 6: - s->range_table = &range_unipolar10; - break; - case 7: - s->range_table = &range_unipolar5; - break; - case 8: - s->range_table = &range718_unipolar2; - break; - case 9: - s->range_table = &range718_unipolar1; - break; - default: - s->range_table = &range_unknown; - break; - } - } + s->n_chan = 8; + s->subdev_flags |= SDF_DIFF; + } + s->maxdata = 0x0fff; + + pcl818_set_ai_range_table(dev, s, it); + + s->insn_read = pcl818_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = ai_cmdtest; + s->do_cmd = pcl818_ai_cmd; + s->cancel = pcl818_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (!board->n_aochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = board->ao_maxdata; - s->range_table = board->ao_range_type; - s->insn_read = pcl818_ao_insn_read; - s->insn_write = pcl818_ao_insn_write; + if (board->n_aochan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0x0fff; + s->range_table = &range_unipolar5; + s->insn_read = pcl818_ao_insn_read; + s->insn_write = pcl818_ao_insn_write; if (board->is_818) { if ((it->options[4] == 1) || (it->options[4] == 10)) s->range_table = &range_unipolar10; @@ -1369,31 +1187,27 @@ no_dma: if (it->options[5] == 2) s->range_table = &range_unknown; } - } - - s = &dev->subdevices[2]; - if (!board->n_dichan) { - s->type = COMEDI_SUBD_UNUSED; } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl818_di_insn_bits; + s->type = COMEDI_SUBD_UNUSED; } + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - if (!board->n_dochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl818_do_insn_bits; - } + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_do_insn_bits; /* select 1/10MHz oscilator */ if ((it->options[3] == 0) || (it->options[3] == 10)) @@ -1424,38 +1238,13 @@ static void pcl818_detach(struct comedi_device *dev) if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl818_board boardtypes[] = { - {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 0}, - /* pcm3718 */ - {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, -}; - static struct comedi_driver pcl818_driver = { .driver_name = "pcl818", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index f4a49bd649f0..53e73737a906 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -225,8 +225,10 @@ static int pcm3724_attach(struct comedi_device *dev, for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; - subdev_8255_init(dev, s, subdev_8255_cb, - (unsigned long)(dev->iobase + SIZE_8255 * i)); + ret = subdev_8255_init(dev, s, subdev_8255_cb, + dev->iobase + SIZE_8255 * i); + if (ret) + return ret; s->insn_config = subdev_3724_insn_config; } return 0; diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index fe482fdd512e..87c61d9b11da 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -61,18 +61,17 @@ static const struct pcmad_board_struct pcmad_boards[] = { }, }; -#define TIMEOUT 100 - -static int pcmad_ai_wait_for_eoc(struct comedi_device *dev, - int timeout) +static int pcmad_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < timeout; i++) { - if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMAD_STATUS); + if ((status & 0x3) == 0x3) + return 0; + return -EBUSY; } static int pcmad_ai_insn_read(struct comedi_device *dev, @@ -89,7 +88,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + PCMAD_CONVERT); - ret = pcmad_ai_wait_for_eoc(dev, TIMEOUT); + ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index c388f7f32227..e89bca845349 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -589,16 +589,17 @@ static int pcmmio_cmdtest(struct comedi_device *dev, return 0; } -static int pcmmio_ai_wait_for_eoc(unsigned long iobase, unsigned int timeout) +static int pcmmio_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - while (timeout--) { - status = inb(iobase + PCMMIO_AI_STATUS_REG); - if (status & PCMMIO_AI_STATUS_DATA_READY) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMMIO_AI_STATUS_REG); + if (status & PCMMIO_AI_STATUS_DATA_READY) + return 0; + return -EBUSY; } static int pcmmio_ai_insn_read(struct comedi_device *dev, @@ -643,7 +644,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev, cmd |= PCMMIO_AI_CMD_RANGE(range); outb(cmd, iobase + PCMMIO_AI_CMD_REG); - ret = pcmmio_ai_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); if (ret) return ret; @@ -652,7 +654,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(cmd, iobase + PCMMIO_AI_CMD_REG); - ret = pcmmio_ai_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); if (ret) return ret; @@ -684,16 +687,17 @@ static int pcmmio_ao_insn_read(struct comedi_device *dev, return insn->n; } -static int pcmmio_ao_wait_for_eoc(unsigned long iobase, unsigned int timeout) +static int pcmmio_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - while (timeout--) { - status = inb(iobase + PCMMIO_AO_STATUS_REG); - if (status & PCMMIO_AO_STATUS_DATA_READY) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMMIO_AO_STATUS_REG); + if (status & PCMMIO_AO_STATUS_DATA_READY) + return 0; + return -EBUSY; } static int pcmmio_ao_insn_write(struct comedi_device *dev, @@ -726,7 +730,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG); outb(0, iobase + PCMMIO_AO_MSB_REG); outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG); - ret = pcmmio_ao_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); if (ret) return ret; @@ -738,7 +743,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG); outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE, iobase + PCMMIO_AO_CMD_REG); - ret = pcmmio_ao_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 55e3c2e2bc52..25706531b885 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -29,13 +29,13 @@ /* descriptor block used for chained dma transfers */ struct plx_dma_desc { - volatile uint32_t pci_start_addr; - volatile uint32_t local_start_addr; + __le32 pci_start_addr; + __le32 local_start_addr; /* transfer_size is in bytes, only first 23 bits of register are used */ - volatile uint32_t transfer_size; + __le32 transfer_size; /* address of next descriptor (quad word aligned), plus some * additional bits (see PLX_DMA0_DESCRIPTOR_REG) */ - volatile uint32_t next; + __le32 next; }; /********************************************************************** diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c deleted file mode 100644 index 2ae4ee15704c..000000000000 --- a/drivers/staging/comedi/drivers/poc.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - comedi/drivers/poc.c - Mini-drivers for POC (Piece of Crap) boards - Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: poc -Description: Generic driver for very simple devices -Author: ds -Devices: [Keithley Metrabyte] DAC-02 (dac02) -Updated: Sat, 16 Mar 2002 17:34:48 -0800 -Status: unknown - -This driver is indended to support very simple ISA-based devices, -including: - dac02 - Keithley DAC-02 analog output board - -Configuration options: - [0] - I/O port base -*/ - -#include <linux/module.h> -#include "../comedidev.h" - -struct boarddef_struct { - const char *name; - unsigned int iosize; - int (*setup) (struct comedi_device *); - int type; - int n_chan; - int n_bits; - int (*winsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - const struct comedi_lrange *range; -}; - -struct poc_private { - unsigned int ao_readback[32]; -}; - -static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int chan; - - chan = CR_CHAN(insn->chanspec); - data[0] = devpriv->ao_readback[chan]; - - return 1; -} - -/* DAC-02 registers */ -#define DAC02_LSB(a) (2 * a) -#define DAC02_MSB(a) (2 * a + 1) - -static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int temp; - int chan; - int output; - - chan = CR_CHAN(insn->chanspec); - devpriv->ao_readback[chan] = data[0]; - output = data[0]; -#ifdef wrong - /* convert to complementary binary if range is bipolar */ - if ((CR_RANGE(insn->chanspec) & 0x2) == 0) - output = ~output; -#endif - temp = (output << 4) & 0xf0; - outb(temp, dev->iobase + DAC02_LSB(chan)); - temp = (output >> 4) & 0xff; - outb(temp, dev->iobase + DAC02_MSB(chan)); - - return 1; -} - -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct boarddef_struct *board = comedi_board(dev); - struct poc_private *devpriv; - struct comedi_subdevice *s; - int ret; - - ret = comedi_request_region(dev, it->options[0], board->iosize); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - /* analog output subdevice */ - s = &dev->subdevices[0]; - s->type = board->type; - s->n_chan = board->n_chan; - s->maxdata = (1 << board->n_bits) - 1; - s->range_table = board->range; - s->insn_write = board->winsn; - s->insn_read = board->rinsn; - s->insn_bits = board->insnbits; - if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) - s->subdev_flags = SDF_WRITABLE; - - return 0; -} - -static const struct boarddef_struct boards[] = { - { - .name = "dac02", - .iosize = 8, - /* .setup = dac02_setup, */ - .type = COMEDI_SUBD_AO, - .n_chan = 2, - .n_bits = 12, - .winsn = dac02_ao_winsn, - .rinsn = readback_insn, - .range = &range_unknown, - }, -}; - -static struct comedi_driver poc_driver = { - .driver_name = "poc", - .module = THIS_MODULE, - .attach = poc_attach, - .detach = comedi_legacy_detach, - .board_name = &boards[0].name, - .num_names = ARRAY_SIZE(boards), - .offset = sizeof(boards[0]), -}; -module_comedi_driver(poc_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 96a46954b3c0..298dba03f902 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -214,7 +214,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) s->async->events |= COMEDI_CB_EOA | COMEDI_CB_OVERFLOW; dev_warn(dev->class_dev, "data lost\n"); - daqp_ai_cancel(dev, s); break; } @@ -231,7 +230,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) if (devpriv->count > 0) { devpriv->count--; if (devpriv->count == 0) { - daqp_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; break; } @@ -244,13 +242,12 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) if (loop_limit <= 0) { dev_warn(dev->class_dev, "loop_limit reached in daqp_interrupt()\n"); - daqp_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } s->async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); } return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 0f026afde9be..cd3fdf973bdd 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -237,20 +237,6 @@ /* The board support a channel list up to the FIFO length (1K or 8K) */ #define RTD_MAX_CHANLIST 128 /* max channel list that we allow */ -/* tuning for ai/ao instruction done polling */ -#ifdef FAST_SPIN -#define WAIT_QUIETLY /* as nothing, spin on done bit */ -#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */ -#define RTD_DAC_TIMEOUT 66000 -#define RTD_DMA_TIMEOUT 33000 /* 1 msec */ -#else -/* by delaying, power and electrical noise are reduced somewhat */ -#define WAIT_QUIETLY udelay(1) -#define RTD_ADC_TIMEOUT 2000 /* in usec */ -#define RTD_DAC_TIMEOUT 2000 /* in usec */ -#define RTD_DMA_TIMEOUT 1000 /* in usec */ -#endif - /*====================================================================== Board specific stuff ======================================================================*/ @@ -562,21 +548,27 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) return fifo_size; } -/* - "instructions" read/write data in "one-shot" or "software-triggered" - mode (simplest case). - This doesn't use interrupts. +static int rtd_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & FS_ADC_NOT_EMPTY) + return 0; + return -EBUSY; +} - Note, we don't do any settling delays. Use a instruction list to - select, delay, then read. - */ static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct rtd_private *devpriv = dev->private; - int n, ii; - int stat; + int ret; + int n; /* clear any old fifo data */ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); @@ -593,14 +585,9 @@ static int rtd_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ writew(0, devpriv->las0 + LAS0_ADC); - for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) { - stat = readl(devpriv->las0 + LAS0_ADC); - if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */ - break; - WAIT_QUIETLY; - } - if (ii >= RTD_ADC_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0); + if (ret) + return ret; /* read data */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); @@ -1116,9 +1103,22 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* - Output one (or more) analog values to a single port as fast as possible. -*/ +static int rtd_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int bit = (chan == 0) ? FS_DAC1_NOT_EMPTY : FS_DAC2_NOT_EMPTY; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & bit) + return 0; + return -EBUSY; +} + static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1127,6 +1127,7 @@ static int rtd_ao_winsn(struct comedi_device *dev, int i; int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); + int ret; /* Configure the output range (table index matches the range values) */ writew(range & 7, devpriv->las0 + @@ -1136,8 +1137,6 @@ static int rtd_ao_winsn(struct comedi_device *dev, * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; ++i) { int val = data[i] << 3; - int stat = 0; /* initialize to avoid bogus warning */ - int ii; /* VERIFY: comedi range and offset conversions */ @@ -1157,16 +1156,9 @@ static int rtd_ao_winsn(struct comedi_device *dev, devpriv->ao_readback[chan] = data[i]; - for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) { - stat = readl(devpriv->las0 + LAS0_ADC); - /* 1 -> not empty */ - if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY : - FS_DAC2_NOT_EMPTY)) - break; - WAIT_QUIETLY; - } - if (ii >= RTD_DAC_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0); + if (ret) + return ret; } /* return the number of samples read/written */ @@ -1382,8 +1374,6 @@ static int rtd_auto_attach(struct comedi_device *dev, if (dev->irq) writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index e1f3671ac056..bd447b2add7b 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -83,8 +83,6 @@ #define RTI800_IOSIZE 0x10 -#define RTI800_AI_TIMEOUT 100 - static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, { BIP_RANGE(10), @@ -145,23 +143,21 @@ struct rti800_private { unsigned char muxgain_bits; }; -static int rti800_ai_wait_for_conversion(struct comedi_device *dev, - int timeout) +static int rti800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - int i; - for (i = 0; i < timeout; i++) { - status = inb(dev->iobase + RTI800_CSR); - if (status & RTI800_CSR_OVERRUN) { - outb(0, dev->iobase + RTI800_CLRFLAGS); - return -EIO; - } - if (status & RTI800_CSR_DONE) - return 0; - udelay(1); + status = inb(dev->iobase + RTI800_CSR); + if (status & RTI800_CSR_OVERRUN) { + outb(0, dev->iobase + RTI800_CLRFLAGS); + return -EOVERFLOW; } - return -ETIME; + if (status & RTI800_CSR_DONE) + return 0; + return -EBUSY; } static int rti800_ai_insn_read(struct comedi_device *dev, @@ -198,7 +194,8 @@ static int rti800_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(0, dev->iobase + RTI800_CONVERT); - ret = rti800_ai_wait_for_conversion(dev, RTI800_AI_TIMEOUT); + + ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index a3fa2a4baef4..605a31d702e0 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -1,45 +1,44 @@ /* - comedi/drivers/rti802.c - Hardware driver for Analog Devices RTI-802 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * rti802.c + * Comedi driver for Analog Devices RTI-802 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: rti802 -Description: Analog Devices RTI-802 -Author: Anders Blomdell <anders.blomdell@control.lth.se> -Devices: [Analog Devices] RTI-802 (rti802) -Status: works - -Configuration Options: - [0] - i/o base - [1] - unused - [2] - dac#0 0=two's comp, 1=straight - [3] - dac#0 0=bipolar, 1=unipolar - [4] - dac#1 ... - ... - [17] - dac#7 ... -*/ + * Driver: rti802 + * Description: Analog Devices RTI-802 + * Author: Anders Blomdell <anders.blomdell@control.lth.se> + * Devices: (Analog Devices) RTI-802 [rti802] + * Status: works + * + * Configuration Options: + * [0] - i/o base + * [1] - unused + * [2,4,6,8,10,12,14,16] - dac#[0-7] 0=two's comp, 1=straight + * [3,5,7,9,11,13,15,17] - dac#[0-7] 0=bipolar, 1=unipolar + */ #include <linux/module.h> #include "../comedidev.h" -#define RTI802_SIZE 4 - -#define RTI802_SELECT 0 -#define RTI802_DATALOW 1 -#define RTI802_DATAHIGH 2 +/* + * Register I/O map + */ +#define RTI802_SELECT 0x00 +#define RTI802_DATALOW 0x01 +#define RTI802_DATAHIGH 0x02 struct rti802_private { enum { @@ -51,34 +50,45 @@ struct rti802_private { static int rti802_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; + data[i] = devpriv->ao_readback[chan]; - return i; + return insn->n; } static int rti802_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; - int i, d; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + RTI802_SELECT); for (i = 0; i < insn->n; i++) { - d = devpriv->ao_readback[chan] = data[i]; + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* munge offset binary to two's complement if needed */ if (devpriv->dac_coding[chan] == dac_2comp) - d ^= 0x800; - outb(chan, dev->iobase + RTI802_SELECT); - outb(d & 0xff, dev->iobase + RTI802_DATALOW); - outb(d >> 8, dev->iobase + RTI802_DATAHIGH); + val = comedi_offset_munge(s, val); + + outb(val & 0xff, dev->iobase + RTI802_DATALOW); + outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH); } - return i; + + return insn->n; } static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -88,7 +98,7 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) int i; int ret; - ret = comedi_request_region(dev, it->options[0], RTI802_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x04); if (ret) return ret; @@ -100,22 +110,21 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; + /* Analog Output subdevice */ s = &dev->subdevices[0]; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 0xfff; - s->n_chan = 8; - s->insn_read = rti802_ao_insn_read; - s->insn_write = rti802_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->maxdata = 0xfff; + s->n_chan = 8; + s->insn_read = rti802_ao_insn_read; + s->insn_write = rti802_ao_insn_write; s->range_table_list = devpriv->range_type_list; for (i = 0; i < 8; i++) { devpriv->dac_coding[i] = (it->options[3 + 2 * i]) - ? (dac_straight) - : (dac_2comp); + ? (dac_straight) : (dac_2comp); devpriv->range_type_list[i] = (it->options[2 + 2 * i]) - ? &range_unipolar10 : &range_bipolar10; + ? &range_unipolar10 : &range_bipolar10; } return 0; @@ -130,5 +139,5 @@ static struct comedi_driver rti802_driver = { module_comedi_driver(rti802_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 9950f59b1192..85d2b7a3c125 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -420,15 +420,28 @@ static int s526_ai_insn_config(struct comedi_device *dev, return result; } +static int s526_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + REG_ISR); + if (status & ISR_ADC_DONE) + return 0; + return -EBUSY; +} + static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct s526_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - int n, i; + int n; unsigned short value; unsigned int d; - unsigned int status; + int ret; /* Set configured delay, enable channel for this channel only, * select "ADC read" channel, set "ADC start" bit. */ @@ -440,17 +453,12 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outw(value, dev->iobase + REG_ADC); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + REG_ISR); - if (status & ISR_ADC_DONE) { - outw(ISR_ADC_DONE, dev->iobase + REG_ISR); - break; - } - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0); + if (ret) + return ret; + + outw(ISR_ADC_DONE, dev->iobase + REG_ISR); /* read data */ d = inw(dev->iobase + REG_ADD); @@ -604,7 +612,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = s526_dio_insn_bits; s->insn_config = s526_dio_insn_config; - return 1; + return 0; } static struct comedi_driver s526_driver = { diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 19da1dbea494..95fadf343f27 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -106,16 +106,16 @@ struct s626_private { struct s626_enc_info { /* Pointers to functions that differ for A and B counters: */ /* Return clock enable. */ - uint16_t(*get_enable)(struct comedi_device *dev, + uint16_t (*get_enable)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return interrupt source. */ - uint16_t(*get_int_src)(struct comedi_device *dev, + uint16_t (*get_int_src)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return preload trigger source. */ - uint16_t(*get_load_trig)(struct comedi_device *dev, + uint16_t (*get_load_trig)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return standardized operating mode. */ - uint16_t(*get_mode)(struct comedi_device *dev, + uint16_t (*get_mode)(struct comedi_device *dev, const struct s626_enc_info *k); /* Generate soft index strobe. */ void (*pulse_index)(struct comedi_device *dev, @@ -209,6 +209,8 @@ static const struct comedi_lrange s626_range_table = { static void s626_debi_transfer(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; + static const int timeout = 10000; + int i; /* Initiate upload of shadow RAM to DEBI control register */ s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2); @@ -217,12 +219,23 @@ static void s626_debi_transfer(struct comedi_device *dev) * Wait for completion of upload from shadow RAM to * DEBI control register. */ - while (!s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) - ; + for (i = 0; i < timeout; i++) { + if (s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, + "Timeout while uploading to DEBI control register."); /* Wait until DEBI transfer is done */ - while (readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S) - ; + for (i = 0; i < timeout; i++) { + if (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, "DEBI transfer timeout."); } /* @@ -351,14 +364,57 @@ static const uint8_t s626_trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 }; +enum { + s626_send_dac_wait_not_mc1_a2out, + s626_send_dac_wait_ssr_af2_out, + s626_send_dac_wait_fb_buffer2_msb_00, + s626_send_dac_wait_fb_buffer2_msb_ff +}; + +static int s626_send_dac_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; + + switch (context) { + case s626_send_dac_wait_not_mc1_a2out: + status = readl(devpriv->mmio + S626_P_MC1); + if (!(status & S626_MC1_A2OUT)) + return 0; + break; + case s626_send_dac_wait_ssr_af2_out: + status = readl(devpriv->mmio + S626_P_SSR); + if (status & S626_SSR_AF2_OUT) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_00: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (!(status & 0xff000000)) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_ff: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (status & 0xff000000) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Private helper function: Transmit serial data to DAC via Audio * channel 2. Assumes: (1) TSL2 slot records initialized, and (2) * dacpol contains valid target image. */ -static void s626_send_dac(struct comedi_device *dev, uint32_t val) +static int s626_send_dac(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; + int ret; /* START THE SERIAL CLOCK RUNNING ------------- */ @@ -404,8 +460,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * Done by polling the DMAC enable flag; this flag is automatically * cleared when the transfer has finished. */ - while (readl(devpriv->mmio + S626_P_MC1) & S626_MC1_A2OUT) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_not_mc1_a2out); + if (ret) { + comedi_error(dev, "DMA transfer timeout."); + return ret; + } /* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */ @@ -425,8 +485,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * finished transferring the DAC's data DWORD from the output FIFO * to the output buffer register. */ - while (!(readl(devpriv->mmio + S626_P_SSR) & S626_SSR_AF2_OUT)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_ssr_af2_out); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 1 to execute."); + return ret; + } /* * Set up to trap execution at slot 0 when the TSL sequencer cycles @@ -466,8 +530,13 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * from 0xFF to 0x00, which slot 0 causes to happen by shifting * out/in on SD2 the 0x00 that is always referenced by slot 5. */ - while (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_00); + if (ret) { + comedi_error(dev, + "TSL timeout waiting for slot 0 to execute."); + return ret; + } } /* * Either (1) we were too late setting the slot 0 trap; the TSL @@ -486,14 +555,19 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * the next DAC write. This is detected when FB_BUFFER2 MSB changes * from 0x00 to 0xFF. */ - while (!(readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_ff); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 0 to execute."); + return ret; + } + return 0; } /* * Private helper function: Write setpoint to an application DAC channel. */ -static void s626_set_dac(struct comedi_device *dev, uint16_t chan, +static int s626_set_dac(struct comedi_device *dev, uint16_t chan, int16_t dacdata) { struct s626_private *devpriv = dev->private; @@ -556,10 +630,10 @@ static void s626_set_dac(struct comedi_device *dev, uint16_t chan, val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel * within the device. */ val |= (uint32_t)dacdata; /* Include DAC setpoint data. */ - s626_send_dac(dev, val); + return s626_send_dac(dev, val); } -static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, +static int s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, uint8_t dac_data) { struct s626_private *devpriv = dev->private; @@ -606,17 +680,22 @@ static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, * Address the DAC channel within the trimdac device. * Include DAC setpoint data. */ - s626_send_dac(dev, (chan << 8) | dac_data); + return s626_send_dac(dev, (chan << 8) | dac_data); } -static void s626_load_trim_dacs(struct comedi_device *dev) +static int s626_load_trim_dacs(struct comedi_device *dev) { uint8_t i; + int ret; /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ - for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) - s626_write_trim_dac(dev, i, + for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) { + ret = s626_write_trim_dac(dev, i, s626_i2c_read(dev, s626_trimadrs[i])); + if (ret) + return ret; + } + return 0; } /* ****** COUNTER FUNCTIONS ******* */ @@ -1846,6 +1925,20 @@ static int s626_ai_rinsn(struct comedi_device *dev, } #endif +static int s626_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + S626_P_PSR); + if (status & S626_PSR_GPIO2) + return 0; + return -EBUSY; +} + static int s626_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1856,6 +1949,7 @@ static int s626_ai_insn_read(struct comedi_device *dev, uint16_t adc_spec = 0; uint32_t gpio_image; uint32_t tmp; + int ret; int n; /* @@ -1897,8 +1991,9 @@ static int s626_ai_insn_read(struct comedi_device *dev, */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2)) - ; + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; /* Fetch ADC data */ if (n != 0) { @@ -2299,6 +2394,7 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, { struct s626_private *devpriv = dev->private; int i; + int ret; uint16_t chan = CR_CHAN(insn->chanspec); int16_t dacdata; @@ -2307,7 +2403,9 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i]; dacdata -= (0x1fff); - s626_set_dac(dev, chan, dacdata); + ret = s626_set_dac(dev, chan, dacdata); + if (ret) + return ret; } return i; @@ -2543,12 +2641,13 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev) return 0; } -static void s626_initialize(struct comedi_device *dev) +static int s626_initialize(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; dma_addr_t phys_buf; uint16_t chan; int i; + int ret; /* Enable DEBI and audio pins, enable I2C interface */ s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C, @@ -2749,7 +2848,9 @@ static void s626_initialize(struct comedi_device *dev) * sometimes causes the first few TrimDAC writes to malfunction. */ s626_load_trim_dacs(dev); - s626_load_trim_dacs(dev); + ret = s626_load_trim_dacs(dev); + if (ret) + return ret; /* * Manually init all gate array hardware in case this is a soft @@ -2763,8 +2864,11 @@ static void s626_initialize(struct comedi_device *dev) * Init all DAC outputs to 0V and init all DAC setpoint and * polarity images. */ - for (chan = 0; chan < S626_DAC_CHANNELS; chan++) - s626_set_dac(dev, chan, 0); + for (chan = 0; chan < S626_DAC_CHANNELS; chan++) { + ret = s626_set_dac(dev, chan, 0); + if (ret) + return ret; + } /* Init counters */ s626_counters_init(dev); @@ -2780,6 +2884,8 @@ static void s626_initialize(struct comedi_device *dev) /* Initialize the digital I/O subsystem */ s626_dio_init(dev); + + return 0; } static int s626_auto_attach(struct comedi_device *dev, @@ -2900,9 +3006,9 @@ static int s626_auto_attach(struct comedi_device *dev, s->insn_read = s626_enc_insn_read; s->insn_write = s626_enc_insn_write; - s626_initialize(dev); - - dev_info(dev->class_dev, "%s attached\n", dev->board_name); + ret = s626_initialize(dev); + if (ret) + return ret; return 0; } diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index 77e2059ff62e..39008cf30ecb 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -142,6 +142,29 @@ static int skel_ns_to_timer(unsigned int *ns, int round) } /* + * This function doesn't require a particular form, this is just + * what happens to be used in some of the drivers. The comedi_timeout() + * helper uses this callback to check for the end-of-conversion while + * waiting for up to 1 second. This function should return 0 when the + * conversion is finished and -EBUSY to keep waiting. Any other errno + * will terminate comedi_timeout() and return that errno to the caller. + * If the timeout occurs, comedi_timeout() will return -ETIMEDOUT. + */ +static int skel_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + /* status = inb(dev->iobase + SKEL_STATUS); */ + status = 1; + if (status) + return 0; + return -EBUSY; +} + +/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ @@ -149,9 +172,9 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct skel_board *thisboard = comedi_board(dev); - int n, i; + int n; unsigned int d; - unsigned int status; + int ret; /* a typical programming sequence */ @@ -165,18 +188,10 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ /* outw(0,dev->iobase + SKEL_CONVERT); */ -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = 1; - /* status = inb(dev->iobase + SKEL_STATUS); */ - if (status) - break; - } - if (i == TIMEOUT) { - dev_warn(dev->class_dev, "ai timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0); + if (ret) + return ret; /* read data */ /* d = inw(dev->iobase + SKEL_AI_DATA); */ @@ -456,8 +471,6 @@ static int skel_common_attach(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; } - dev_info(dev->class_dev, "skel: attached\n"); - return 0; } diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index df22a78d2b7e..848c30801580 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -161,8 +161,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(PCMR, CSCIR); outb((inb(CSCDR) & 0xAA), CSCDR); - dev_info(dev->class_dev, "%s: attached\n", dev->board_name); - return 1; + return 0; } static void dnp_detach(struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 5f85c55c1109..d6fae11ee4e0 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -372,7 +372,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT | TRIG_INT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + TRIG_FOLLOW | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -424,9 +424,6 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, tmp); } - if (cmd->scan_begin_src == TRIG_TIMER) - err |= -EINVAL; - /* stop source */ switch (cmd->stop_src) { case TRIG_COUNT: @@ -514,36 +511,28 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ devpriv->ignore = PACKETS_TO_IGNORE; - if (cmd->chanlist_len > 0) { - gain = CR_RANGE(cmd->chanlist[0]); - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - if (chan != i) { - dev_err(dev->class_dev, - "channels are not consecutive\n"); - up(&devpriv->sem); - return -EINVAL; - } - if ((gain != CR_RANGE(cmd->chanlist[i])) - && (cmd->chanlist_len > 3)) { - dev_err(dev->class_dev, - "gain must be the same for all channels\n"); - up(&devpriv->sem); - return -EINVAL; - } - if (i >= NUMCHANNELS) { - dev_err(dev->class_dev, "chanlist too long\n"); - break; - } + gain = CR_RANGE(cmd->chanlist[0]); + for (i = 0; i < cmd->chanlist_len; ++i) { + chan = CR_CHAN(cmd->chanlist[i]); + if (chan != i) { + dev_err(dev->class_dev, + "channels are not consecutive\n"); + up(&devpriv->sem); + return -EINVAL; + } + if ((gain != CR_RANGE(cmd->chanlist[i])) + && (cmd->chanlist_len > 3)) { + dev_err(dev->class_dev, + "gain must be the same for all channels\n"); + up(&devpriv->sem); + return -EINVAL; + } + if (i >= NUMCHANNELS) { + dev_err(dev->class_dev, "chanlist too long\n"); + break; } } steps = 0; - if (cmd->scan_begin_src == TRIG_TIMER) { - dev_err(dev->class_dev, - "scan_begin_src==TRIG_TIMER not valid\n"); - up(&devpriv->sem); - return -EINVAL; - } if (cmd->convert_src == TRIG_TIMER) steps = (cmd->convert_arg * 30) / 1000; diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 3beeb1254152..88c60b6020c4 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -48,6 +48,7 @@ #include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> +#include <asm/unaligned.h> #include "comedi_fc.h" #include "../comedidev.h" @@ -792,7 +793,8 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, } /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf) + 1))); + val = be32_to_cpu(get_unaligned((uint32_t + *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ @@ -1357,7 +1359,7 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) return ret; /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf)+1))); + val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ |