diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-15 11:30:39 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-15 11:30:39 -0800 |
commit | 46f7b635569731ff81a3b72d1bcd4415b293b637 (patch) | |
tree | e97e5e28d1768bb281116d92292851758ea20024 /drivers/staging/comedi/drivers | |
parent | 9682ec9692e5ac11c6caebd079324e727b19e7ce (diff) | |
parent | 533e80b1ea709577ec5cf73b8b566569bc711259 (diff) |
Merge tag 'staging-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging drivers patches from Greg KH:
"Here's the big staging driver tree update for 3.20-rc1.
Lots of little things in here, adding up to lots of overall cleanups.
The IIO driver updates are also in here as they cross the staging tree
boundry a lot. I2O has moved into staging as well, as a plan to drop
it from the tree eventually as that's a dead subsystem.
All of this has been in linux-next with no reported issues for a
while"
* tag 'staging-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (740 commits)
staging: lustre: lustre: libcfs: define symbols as static
staging: rtl8712: Do coding style cleanup
staging: lustre: make obd_updatemax_lock static
staging: rtl8188eu: core: switch with redundant cases
staging: rtl8188eu: odm: conditional setting with no effect
staging: rtl8188eu: odm: condition with no effect
staging: ft1000: fix braces warning
staging: sm7xxfb: fix remaining CamelCase
staging: sm7xxfb: fix CamelCase
staging: rtl8723au: multiple condition with no effect - if identical to else
staging: sm7xxfb: make smtc_scr_info static
staging/lustre/mdc: Initialize req in mdc_enqueue for !it case
staging/lustre/clio: Do not allow group locks with gid 0
staging/lustre/llite: don't add to page cache upon failure
staging/lustre/llite: Add exception entry check after radix_tree
staging/lustre/libcfs: protect kkuc_groups from write access
staging/lustre/fld: refer to MDT0 for fld lookup in some cases
staging/lustre/llite: Solve a race to access lli_has_smd in read case
staging/lustre/ptlrpc: hold rq_lock when modify rq_flags
staging/lustre/lnet: portal spreading rotor should be unsigned
...
Diffstat (limited to 'drivers/staging/comedi/drivers')
92 files changed, 3347 insertions, 4912 deletions
diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index 9f4c1411719d..51b9c8d279c0 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -1,20 +1,20 @@ /* - comedi/drivers/8253.h - Header file for 8253 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/8253.h + * Header file for 8253 + * + * 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. + */ #ifndef _8253_H #define _8253_H @@ -44,9 +44,11 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base, unsigned int start; unsigned int ns_low, ns_high; static const unsigned int max_count = 0x10000; - /* exit early if everything is already correct (this can save time + /* + * exit early if everything is already correct (this can save time * since this function may be called repeatedly during command tests - * and execution) */ + * and execution) + */ div1 = *d1 ? *d1 : max_count; div2 = *d2 ? *d2 : max_count; divider = div1 * div2; @@ -114,13 +116,14 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base, } *nanosec = div1 * div2 * i8253_osc_base; - /* masking is done since counter maps zero to 0x10000 */ + /* masking is done since counter maps zero to 0x10000 */ *d1 = div1 & 0xffff; *d2 = div2 & 0xffff; } #ifndef CMDTEST -/* i8254_load programs 8254 counter chip. It should also work for the 8253. +/* + * i8254_load programs 8254 counter chip. It should also work for the 8253. * base_address is the lowest io address * for the chip (the address of counter 0). * counter_number is the counter you want to load (0,1 or 2) @@ -158,12 +161,12 @@ static inline int i8254_load(unsigned long base_address, unsigned int regshift, return -1; byte = counter_number << 6; - byte |= 0x30; /* load low then high byte */ - byte |= (mode << 1); /* set counter mode */ + byte |= 0x30; /* load low then high byte */ + byte |= (mode << 1); /* set counter mode */ outb(byte, base_address + (i8254_control_reg << regshift)); - byte = count & 0xff; /* lsb of counter value */ + byte = count & 0xff; /* lsb of counter value */ outb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; /* msb of counter value */ + byte = (count >> 8) & 0xff; /* msb of counter value */ outb(byte, base_address + (counter_number << regshift)); return 0; @@ -187,18 +190,18 @@ static inline int i8254_mm_load(void __iomem *base_address, return -1; byte = counter_number << 6; - byte |= 0x30; /* load low then high byte */ - byte |= (mode << 1); /* set counter mode */ + byte |= 0x30; /* load low then high byte */ + byte |= (mode << 1); /* set counter mode */ writeb(byte, base_address + (i8254_control_reg << regshift)); - byte = count & 0xff; /* lsb of counter value */ + byte = count & 0xff; /* lsb of counter value */ writeb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; /* msb of counter value */ + byte = (count >> 8) & 0xff; /* msb of counter value */ writeb(byte, base_address + (counter_number << regshift)); return 0; } -/* Returns 16 bit counter value, should work for 8253 also.*/ +/* Returns 16 bit counter value, should work for 8253 also. */ static inline int i8254_read(unsigned long base_address, unsigned int regshift, unsigned int counter_number) { @@ -208,13 +211,13 @@ static inline int i8254_read(unsigned long base_address, unsigned int regshift, if (counter_number > 2) return -1; - /* latch counter */ + /* latch counter */ byte = counter_number << 6; outb(byte, base_address + (i8254_control_reg << regshift)); - /* read lsb */ + /* read lsb */ ret = inb(base_address + (counter_number << regshift)); - /* read msb */ + /* read msb */ ret += inb(base_address + (counter_number << regshift)) << 8; return ret; @@ -230,13 +233,13 @@ static inline int i8254_mm_read(void __iomem *base_address, if (counter_number > 2) return -1; - /* latch counter */ + /* latch counter */ byte = counter_number << 6; writeb(byte, base_address + (i8254_control_reg << regshift)); - /* read lsb */ + /* read lsb */ ret = readb(base_address + (counter_number << regshift)); - /* read msb */ + /* read msb */ ret += readb(base_address + (counter_number << regshift)) << 8; return ret; @@ -252,9 +255,9 @@ static inline void i8254_write(unsigned long base_address, if (counter_number > 2) return; - byte = count & 0xff; /* lsb of counter value */ + byte = count & 0xff; /* lsb of counter value */ outb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; /* msb of counter value */ + byte = (count >> 8) & 0xff; /* msb of counter value */ outb(byte, base_address + (counter_number << regshift)); } @@ -268,13 +271,14 @@ static inline void i8254_mm_write(void __iomem *base_address, if (counter_number > 2) return; - byte = count & 0xff; /* lsb of counter value */ + byte = count & 0xff; /* lsb of counter value */ writeb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; /* msb of counter value */ + byte = (count >> 8) & 0xff; /* msb of counter value */ writeb(byte, base_address + (counter_number << regshift)); } -/* Set counter mode, should work for 8253 also. +/* + * Set counter mode, should work for 8253 also. * Note: the 'mode' value is different to that for i8254_load() and comes * from the INSN_CONFIG_8254_SET_MODE command: * I8254_MODE0, I8254_MODE1, ..., I8254_MODE5 @@ -293,8 +297,8 @@ static inline int i8254_set_mode(unsigned long base_address, return -1; byte = counter_number << 6; - byte |= 0x30; /* load low then high byte */ - byte |= mode; /* set counter mode and BCD|binary */ + byte |= 0x30; /* load low then high byte */ + byte |= mode; /* set counter mode and BCD|binary */ outb(byte, base_address + (i8254_control_reg << regshift)); return 0; @@ -313,8 +317,8 @@ static inline int i8254_mm_set_mode(void __iomem *base_address, return -1; byte = counter_number << 6; - byte |= 0x30; /* load low then high byte */ - byte |= mode; /* set counter mode and BCD|binary */ + byte |= 0x30; /* load low then high byte */ + byte |= mode; /* set counter mode and BCD|binary */ writeb(byte, base_address + (i8254_control_reg << regshift)); return 0; diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 34d4d8b5f31e..c2f15de6a547 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -1,76 +1,51 @@ /* - comedi/drivers/8255.c - Driver for 8255 - - 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: 8255 -Description: generic 8255 support -Devices: [standard] 8255 (8255) -Author: ds -Status: works -Updated: Fri, 7 Jun 2002 12:56:45 -0700 - -The classic in digital I/O. The 8255 appears in Comedi as a single -digital I/O subdevice with 24 channels. The channel 0 corresponds -to the 8255's port A, bit 0; channel 23 corresponds to port C, bit -7. Direction configuration is done in blocks, with channels 0-7, -8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode -supported is mode 0. - -You should enable compilation this driver if you plan to use a board -that has an 8255 chip. For multifunction boards, the main driver will -configure the 8255 subdevice automatically. - -This driver also works independently with ISA and PCI cards that -directly map the 8255 registers to I/O ports, including cards with -multiple 8255 chips. To configure the driver for such a card, the -option list should be a list of the I/O port bases for each of the -8255 chips. For example, - - comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c - -Note that most PCI 8255 boards do NOT work with this driver, and -need a separate driver as a wrapper. For those that do work, the -I/O port base address can be found in the output of 'lspci -v'. - -*/ + * comedi/drivers/8255.c + * Driver for 8255 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* - This file contains an exported subdevice for driving an 8255. - - To use this subdevice as part of another driver, you need to - set up the subdevice in the attach function of the driver by - calling: - - subdev_8255_init(device, subdevice, io_function, iobase) - - device and subdevice are pointers to the device and subdevice - structures. io_function will be called to provide the - low-level input/output to the device, i.e., actual register - access. io_function will be called with the value of iobase - as the last parameter. If the 8255 device is mapped as 4 - consecutive I/O ports, you can use NULL for io_function - and the I/O port base for iobase, and an internal function will - handle the register access. - - In addition, if the main driver handles interrupts, you can - enable commands on the subdevice by calling subdev_8255_init_irq() - instead. Then, when you get an interrupt that is likely to be - from the 8255, you should call subdev_8255_interrupt(), which - will copy the latched value to a Comedi buffer. + * Driver: 8255 + * Description: generic 8255 support + * Devices: [standard] 8255 (8255) + * Author: ds + * Status: works + * Updated: Fri, 7 Jun 2002 12:56:45 -0700 + * + * The classic in digital I/O. The 8255 appears in Comedi as a single + * digital I/O subdevice with 24 channels. The channel 0 corresponds + * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit + * 7. Direction configuration is done in blocks, with channels 0-7, + * 8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode + * supported is mode 0. + * + * You should enable compilation this driver if you plan to use a board + * that has an 8255 chip. For multifunction boards, the main driver will + * configure the 8255 subdevice automatically. + * + * This driver also works independently with ISA and PCI cards that + * directly map the 8255 registers to I/O ports, including cards with + * multiple 8255 chips. To configure the driver for such a card, the + * option list should be a list of the I/O port bases for each of the + * 8255 chips. For example, + * + * comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c + * + * Note that most PCI 8255 boards do NOT work with this driver, and + * need a separate driver as a wrapper. For those that do work, the + * I/O port base address can be found in the output of 'lspci -v'. */ #include <linux/module.h> @@ -218,6 +193,33 @@ static int __subdev_8255_init(struct comedi_device *dev, return 0; } +/** + * subdev_8255_init - initialize DIO subdevice for driving I/O mapped 8255 + * @dev: comedi device owning subdevice + * @s: comedi subdevice to initialize + * @io: (optional) register I/O call-back function + * @regbase: offset of 8255 registers from dev->iobase, or call-back context + * + * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip. + * + * If the optional I/O call-back function is provided, its prototype is of + * the following form: + * + * int my_8255_callback(struct comedi_device *dev, + * struct comedi_subdevice *s, int dir, int port, + * int data, unsigned long regbase); + * + * where 'dev', 's', and 'regbase' match the values passed to this function, + * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir' + * is the direction (0 for read, 1 for write) and 'data' is the value to be + * written. It should return 0 if writing or the value read if reading. + * + * If the optional I/O call-back function is not provided, an internal + * call-back function is used which uses consecutive I/O port addresses + * starting at dev->iobase + regbase. + * + * Return: -ENOMEM if failed to allocate memory, zero on success. + */ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, int (*io)(struct comedi_device *, int, int, int, unsigned long), @@ -227,6 +229,33 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, } EXPORT_SYMBOL_GPL(subdev_8255_init); +/** + * subdev_8255_mm_init - initialize DIO subdevice for driving mmio-mapped 8255 + * @dev: comedi device owning subdevice + * @s: comedi subdevice to initialize + * @io: (optional) register I/O call-back function + * @regbase: offset of 8255 registers from dev->mmio, or call-back context + * + * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip. + * + * If the optional I/O call-back function is provided, its prototype is of + * the following form: + * + * int my_8255_callback(struct comedi_device *dev, + * struct comedi_subdevice *s, int dir, int port, + * int data, unsigned long regbase); + * + * where 'dev', 's', and 'regbase' match the values passed to this function, + * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir' + * is the direction (0 for read, 1 for write) and 'data' is the value to be + * written. It should return 0 if writing or the value read if reading. + * + * If the optional I/O call-back function is not provided, an internal + * call-back function is used which uses consecutive MMIO virtual addresses + * starting at dev->mmio + regbase. + * + * Return: -ENOMEM if failed to allocate memory, zero on success. + */ int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s, int (*io)(struct comedi_device *, int, int, int, unsigned long), @@ -235,10 +264,9 @@ int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s, return __subdev_8255_init(dev, s, io, regbase, true); } EXPORT_SYMBOL_GPL(subdev_8255_mm_init); -/* - - Start of the 8255 standalone device +/* + * Start of the 8255 standalone device */ static int dev_8255_attach(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index 5985c8e0330f..934b940ebd3c 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -1,20 +1,20 @@ /* - module/8255.h - Header file for 8255 - - 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. -*/ + * module/8255.h + * Header file for 8255 + * + * 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. + */ #ifndef _8255_H #define _8255_H diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index 8b9589828855..984764211a2d 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -22,33 +22,44 @@ */ /* -Driver: 8255_pci -Description: Generic PCI based 8255 Digital I/O boards -Devices: (ADLink) PCI-7224 [adl_pci-7224] - 24 channels - (ADLink) PCI-7248 [adl_pci-7248] - 48 channels - (ADLink) PCI-7296 [adl_pci-7296] - 96 channels - (Measurement Computing) PCI-DIO24 [cb_pci-dio24] - 24 channels - (Measurement Computing) PCI-DIO24H [cb_pci-dio24h] - 24 channels - (Measurement Computing) PCI-DIO48H [cb_pci-dio48h] - 48 channels - (Measurement Computing) PCI-DIO96H [cb_pci-dio96h] - 96 channels - (National Instruments) PCI-DIO-96 [ni_pci-dio-96] - 96 channels - (National Instruments) PCI-DIO-96B [ni_pci-dio-96b] - 96 channels - (National Instruments) PXI-6508 [ni_pxi-6508] - 96 channels - (National Instruments) PCI-6503 [ni_pci-6503] - 24 channels - (National Instruments) PCI-6503B [ni_pci-6503b] - 24 channels - (National Instruments) PCI-6503X [ni_pci-6503x] - 24 channels - (National Instruments) PXI-6503 [ni_pxi-6503] - 24 channels -Author: H Hartley Sweeten <hsweeten@visionengravers.com> -Updated: Wed, 12 Sep 2012 11:52:01 -0700 -Status: untested - -Some of these boards also have an 8254 programmable timer/counter -chip. This chip is not currently supported by this driver. - -Interrupt support for these boards is also not currently supported. - -Configuration Options: not applicable, uses PCI auto config -*/ + * Driver: 8255_pci + * Description: Generic PCI based 8255 Digital I/O boards + * Devices: [ADLink] PCI-7224 (adl_pci-7224), PCI-7248 (adl_pci-7248), + * PCI-7296 (adl_pci-7296), + * [Measurement Computing] PCI-DIO24 (cb_pci-dio24), + * PCI-DIO24H (cb_pci-dio24h), PCI-DIO48H (cb_pci-dio48h), + * PCI-DIO96H (cb_pci-dio96h), + * [National Instruments] PCI-DIO-96 (ni_pci-dio-96), + * PCI-DIO-96B (ni_pci-dio-96b), PXI-6508 (ni_pxi-6508), + * PCI-6503 (ni_pci-6503), PCI-6503B (ni_pci-6503b), + * PCI-6503X (ni_pci-6503x), PXI-6503 (ni_pxi-6503) + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Wed, 12 Sep 2012 11:52:01 -0700 + * Status: untested + * + * These boards have one or more 8255 digital I/O chips, each of which + * is supported as a separate 24-channel DIO subdevice. + * + * Boards with 24 DIO channels (1 DIO subdevice): + * + * PCI-7224, PCI-DIO24, PCI-DIO24H, PCI-6503, PCI-6503B, PCI-6503X, + * PXI-6503 + * + * Boards with 48 DIO channels (2 DIO subdevices): + * + * PCI-7248, PCI-DIO48H + * + * Boards with 96 DIO channels (4 DIO subdevices): + * + * PCI-7296, PCI-DIO96H, PCI-DIO-96, PCI-DIO-96B, PXI-6508 + * + * Some of these boards also have an 8254 programmable timer/counter + * chip. This chip is not currently supported by this driver. + * + * Interrupt support for these boards is also not currently supported. + * + * Configuration Options: not applicable, uses PCI auto config. + */ #include <linux/module.h> #include <linux/pci.h> diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 84fdf20ca986..7d1fbd53a8ab 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -3,6 +3,7 @@ ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG # Comedi "helper" modules +obj-$(CONFIG_COMEDI_ISADMA) += comedi_isadma.o # Comedi misc drivers obj-$(CONFIG_COMEDI_BOND) += comedi_bond.o diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c deleted file mode 100644 index bfa9228c833f..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ /dev/null @@ -1,2365 +0,0 @@ -/* - * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - * - * ADDI-DATA GmbH - * Dieselstrasse 3 - * D-77833 Ottersweier - * Tel: +19(0)7223/9493-0 - * Fax: +49(0)7223/9493-92 - * http://www.addi-data.com - * info@addi-data.com - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - */ - -/* Card Specific information */ -#define APCI1500_ADDRESS_RANGE 4 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI1500_DIGITAL_OP 2 -#define APCI1500_DIGITAL_IP 0 -#define APCI1500_AND 2 -#define APCI1500_OR 4 -#define APCI1500_OR_PRIORITY 6 -#define APCI1500_CLK_SELECT 0 -#define COUNTER1 0 -#define COUNTER2 1 -#define COUNTER3 2 -#define APCI1500_COUNTER 0x20 -#define APCI1500_TIMER 0 -#define APCI1500_WATCHDOG 0 -#define APCI1500_SINGLE 0 -#define APCI1500_CONTINUOUS 0x80 -#define APCI1500_DISABLE 0 -#define APCI1500_ENABLE 1 -#define APCI1500_SOFTWARE_TRIGGER 0x4 -#define APCI1500_HARDWARE_TRIGGER 0x10 -#define APCI1500_SOFTWARE_GATE 0 -#define APCI1500_HARDWARE_GATE 0x8 -#define START 0 -#define STOP 1 -#define TRIGGER 2 - -/* - * Zillog I/O enumeration - */ -enum { - APCI1500_Z8536_PORT_C, - APCI1500_Z8536_PORT_B, - APCI1500_Z8536_PORT_A, - APCI1500_Z8536_CONTROL_REGISTER -}; - -/* - * Z8536 CIO Internal Address - */ -enum { - APCI1500_RW_MASTER_INTERRUPT_CONTROL, - APCI1500_RW_MASTER_CONFIGURATION_CONTROL, - APCI1500_RW_PORT_A_INTERRUPT_CONTROL, - APCI1500_RW_PORT_B_INTERRUPT_CONTROL, - APCI1500_RW_TIMER_COUNTER_INTERRUPT_VECTOR, - APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, - APCI1500_RW_PORT_C_DATA_DIRECTION, - APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL, - - APCI1500_RW_PORT_A_COMMAND_AND_STATUS, - APCI1500_RW_PORT_B_COMMAND_AND_STATUS, - APCI1500_RW_CPT_TMR1_CMD_STATUS, - APCI1500_RW_CPT_TMR2_CMD_STATUS, - APCI1500_RW_CPT_TMR3_CMD_STATUS, - APCI1500_RW_PORT_A_DATA, - APCI1500_RW_PORT_B_DATA, - APCI1500_RW_PORT_C_DATA, - - APCI1500_R_CPT_TMR1_VALUE_HIGH, - APCI1500_R_CPT_TMR1_VALUE_LOW, - APCI1500_R_CPT_TMR2_VALUE_HIGH, - APCI1500_R_CPT_TMR2_VALUE_LOW, - APCI1500_R_CPT_TMR3_VALUE_HIGH, - APCI1500_R_CPT_TMR3_VALUE_LOW, - APCI1500_RW_CPT_TMR1_TIME_CST_HIGH, - APCI1500_RW_CPT_TMR1_TIME_CST_LOW, - APCI1500_RW_CPT_TMR2_TIME_CST_HIGH, - APCI1500_RW_CPT_TMR2_TIME_CST_LOW, - APCI1500_RW_CPT_TMR3_TIME_CST_HIGH, - APCI1500_RW_CPT_TMR3_TIME_CST_LOW, - APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION, - APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION, - APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION, - APCI1500_R_CURRENT_VECTOR, - - APCI1500_RW_PORT_A_SPECIFICATION, - APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION, - APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY, - APCI1500_RW_PORT_A_DATA_DIRECTION, - APCI1500_RW_PORT_A_SPECIAL_IO_CONTROL, - APCI1500_RW_PORT_A_PATTERN_POLARITY, - APCI1500_RW_PORT_A_PATTERN_TRANSITION, - APCI1500_RW_PORT_A_PATTERN_MASK, - - APCI1500_RW_PORT_B_SPECIFICATION, - APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION, - APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY, - APCI1500_RW_PORT_B_DATA_DIRECTION, - APCI1500_RW_PORT_B_SPECIAL_IO_CONTROL, - APCI1500_RW_PORT_B_PATTERN_POLARITY, - APCI1500_RW_PORT_B_PATTERN_TRANSITION, - APCI1500_RW_PORT_B_PATTERN_MASK -}; - -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; - -/* - * 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 apci1500_private *devpriv = dev->private; - int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0; - int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0; - int i_PatternTransitionCount = 0, i_RegValue; - int i; - - /* Selects the master interrupt control register */ - outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Disables the main interrupt on the board */ - outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - - if (data[0] == 1) { - i_MaxChannel = 8; - } else { - if (data[0] == 2) { - i_MaxChannel = 6; - } else { - dev_warn(dev->class_dev, - "The specified port event does not exist\n"); - return -EINVAL; - } - } - switch (data[1]) { - case 0: - data[1] = APCI1500_AND; - break; - case 1: - data[1] = APCI1500_OR; - break; - case 2: - data[1] = APCI1500_OR_PRIORITY; - break; - default: - dev_warn(dev->class_dev, - "The specified interrupt logic does not exist\n"); - return -EINVAL; - } - - i_Logic = data[1]; - for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) { - i_EventMask = data[2 + i]; - switch (i_EventMask) { - case 0: - i_PatternMask = - i_PatternMask | (1 << (i_MaxChannel - i_Count)); - break; - case 1: - i_PatternMask = - i_PatternMask | (1 << (i_MaxChannel - i_Count)); - i_PatternPolarity = - i_PatternPolarity | (1 << (i_MaxChannel - - i_Count)); - break; - case 2: - i_PatternMask = - i_PatternMask | (1 << (i_MaxChannel - i_Count)); - i_PatternTransition = - i_PatternTransition | (1 << (i_MaxChannel - - i_Count)); - break; - case 3: - i_PatternMask = - i_PatternMask | (1 << (i_MaxChannel - i_Count)); - i_PatternPolarity = - i_PatternPolarity | (1 << (i_MaxChannel - - i_Count)); - i_PatternTransition = - i_PatternTransition | (1 << (i_MaxChannel - - i_Count)); - break; - case 4: - i_PatternTransition = - i_PatternTransition | (1 << (i_MaxChannel - - i_Count)); - break; - case 5: - break; - default: - dev_warn(dev->class_dev, - "The option indicated in the event mask does not exist\n"); - return -EINVAL; - } - } - - 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) { - dev_warn(dev->class_dev, - "Transition error on an OR PRIORITY logic\n"); - return -EINVAL; - } - - /* 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++) { - i_PatternTransitionCount = - i_PatternTransitionCount + - ((i_PatternTransition >> - i_Count) & 0x1); - - } - - if (i_PatternTransitionCount > 1) { - dev_warn(dev->class_dev, - "Transition error on an AND logic\n"); - return -EINVAL; - } - } - - /* 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); - outb(i_PatternPolarity, - 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); - outb(i_PatternTransition, - 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); - i_RegValue = - 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, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - - 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); - - } else { - dev_warn(dev->class_dev, - "The choice for interrupt logic does not exist\n"); - return -EINVAL; - } - } - - /* 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); - i_RegValue = - 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); - i_RegValue = i_RegValue & 0xF9; - outb(i_RegValue, - 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 + - APCI1500_Z8536_CONTROL_REGISTER); - outb(i_PatternMask, - 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); - i_RegValue = (i_RegValue & 0xF9) | 4; - outb(i_RegValue, - devpriv->iobase + - 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); - } else { - dev_warn(dev->class_dev, - "The choice for interrupt logic does not exist\n"); - return -EINVAL; - } - } - - return insn->n; -} - -/* - * 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 apci1500_private *devpriv = dev->private; - int i_Event1InterruptStatus = 0, i_Event2InterruptStatus = - 0, i_RegValue; - - switch (data[0]) { - case START: - /* Tests the port number */ - - if (data[1] == 1 || data[1] == 2) { - /* Test if port 1 selected */ - - if (data[1] == 1) { - /* Test if event initialised */ - if (i_Event1Status == 1) { - /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Disable Port A */ - outb(0xF0, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the command and status register of */ - /* port 1 */ - outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Allows the pattern interrupt */ - outb(0xC0, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Enable Port A */ - outb(0xF4, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - i_Event1InterruptStatus = 1; - outb(APCI1500_RW_PORT_A_SPECIFICATION, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - i_RegValue = - inb(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); - - } else { - dev_warn(dev->class_dev, - "Event 1 not initialised\n"); - return -EINVAL; - } - } - 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; - } else { - dev_warn(dev->class_dev, - "Event 2 not initialised\n"); - return -EINVAL; - } - } - } else { - dev_warn(dev->class_dev, - "The port parameter is in error\n"); - return -EINVAL; - } - - 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; - } else { - dev_warn(dev->class_dev, - "Event 1 not initialised\n"); - return -EINVAL; - } - } - 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; - } else { - - dev_warn(dev->class_dev, - "Event 2 not initialised\n"); - return -EINVAL; - } - } - - } else { - dev_warn(dev->class_dev, - "The port parameter is in error\n"); - return -EINVAL; - } - break; - default: - dev_warn(dev->class_dev, - "The option of START/STOP logic does not exist\n"); - return -EINVAL; - } - - return insn->n; -} - -/* - * 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 apci1500_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); - outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - 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); - - /* Selects the data path polarity register of port A */ - outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* High level of port A means 1 */ - outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - - /* Selects the data direction register of port A */ - outb(APCI1500_RW_PORT_A_DATA_DIRECTION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* All bits used as inputs */ - outb(0xFF, 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); - /* Deletes IP and IUS */ - outb(0x20, 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 the interrupt management of port A: */ - outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the handshake specification register of port A */ - outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* 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); - /* Selects the data path polarity register of port B */ - outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* A high level of port B means 1 */ - outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the data direction register of port B */ - outb(APCI1500_RW_PORT_B_DATA_DIRECTION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* All bits used as inputs */ - outb(0xFF, 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); - /* Deletes IP and IUS */ - outb(0x20, 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 the interrupt management of port B: */ - outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the handshake specification register of port B */ - outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* 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 */ - outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the data direction register of port C */ - outb(APCI1500_RW_PORT_C_DATA_DIRECTION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* All bits used as inputs except channel 1 */ - outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the special IO register of port C */ - outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL, - 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 */ - outb(0x20, 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 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 */ - outb(0x20, 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 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 */ - outb(0x20, 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 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); - return insn->n; -} - -static int apci1500_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1500_private *devpriv = dev->private; - - data[1] = inw(devpriv->i_IobaseAddon + APCI1500_DIGITAL_IP); - - return insn->n; -} - -/* - * 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 apci1500_private *devpriv = dev->private; - - devpriv->b_OutputMemoryStatus = data[0]; - return insn->n; -} - -/* - * 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 apci1500_private *devpriv = dev->private; - static unsigned int ui_Temp; - unsigned int ui_Temp1; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - - if (!devpriv->b_OutputMemoryStatus) - ui_Temp = 0; - - if (data[3] == 0) { - if (data[1] == 0) { - data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; - outw(data[0], - devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = - (data[0] << (2 * - data[2])) | ui_Temp; - break; - - case 4: - data[0] = - (data[0] << (4 * - data[2])) | ui_Temp; - break; - - case 8: - data[0] = - (data[0] << (8 * - data[2])) | ui_Temp; - break; - - case 15: - data[0] = data[0] | ui_Temp; - break; - - default: - dev_err(dev->class_dev, - "chan spec wrong\n"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } - - outw(data[0], - devpriv->i_IobaseAddon + - APCI1500_DIGITAL_OP); - } else { - dev_warn(dev->class_dev, - "Specified channel not supported\n"); - return -EINVAL; - } - } - } else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - (data[0] << ui_NoOfChannel) ^ - 0xffffffff; - data[0] = data[0] & ui_Temp; - outw(data[0], - devpriv->i_IobaseAddon + - APCI1500_DIGITAL_OP); - } else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = - ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - - case 4: - data[0] = ~data[0] & 0xf; - ui_Temp1 = 15; - ui_Temp1 = - ui_Temp1 << 4 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (4 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - - case 8: - data[0] = ~data[0] & 0xff; - ui_Temp1 = 255; - ui_Temp1 = - ui_Temp1 << 8 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (8 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - - case 15: - break; - - default: - dev_err(dev->class_dev, - "chan spec wrong\n"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } - - outw(data[0], - devpriv->i_IobaseAddon + - APCI1500_DIGITAL_OP); - } else { - dev_warn(dev->class_dev, - "Specified channel not supported\n"); - return -EINVAL; - } - } - } else { - dev_warn(dev->class_dev, - "Specified functionality does not exist\n"); - return -EINVAL; - } - } - ui_Temp = data[0]; - return insn->n; -} - -/* - * 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 apci1500_private *devpriv = dev->private; - int i_TimerCounterMode, i_MasterConfiguration; - - devpriv->tsk_Current = current; - - /* Selection of the input clock */ - if (data[0] == 0 || data[0] == 1 || data[0] == 2) { - outw(data[0], devpriv->i_IobaseAddon + APCI1500_CLK_SELECT); - } else { - if (data[0] != 3) { - dev_warn(dev->class_dev, - "The option for input clock selection does not exist\n"); - return -EINVAL; - } - } - /* Select the counter/timer */ - switch (data[1]) { - case COUNTER1: - /* selecting counter or timer */ - switch (data[2]) { - case 0: - data[2] = APCI1500_COUNTER; - break; - case 1: - data[2] = APCI1500_TIMER; - break; - default: - dev_warn(dev->class_dev, - "This choice is not a timer nor a counter\n"); - return -EINVAL; - } - - /* Selecting single or continuous mode */ - switch (data[4]) { - case 0: - data[4] = APCI1500_CONTINUOUS; - break; - case 1: - data[4] = APCI1500_SINGLE; - break; - default: - dev_warn(dev->class_dev, - "This option for single/continuous mode does not exist\n"); - return -EINVAL; - } - - 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); - } else { - dev_warn(dev->class_dev, - "Error in selection of interrupt enable or disable\n"); - return -EINVAL; - } - } else { - dev_warn(dev->class_dev, - "Error in selection of reload value\n"); - return -EINVAL; - } - i_TimerCounterWatchdogInterrupt = data[7]; - i_TimerCounter1Init = 1; - break; - - case COUNTER2: /* selecting counter or timer */ - switch (data[2]) { - case 0: - data[2] = APCI1500_COUNTER; - break; - case 1: - data[2] = APCI1500_TIMER; - break; - default: - dev_warn(dev->class_dev, - "This choice is not a timer nor a counter\n"); - return -EINVAL; - } - - /* Selecting single or continuous mode */ - switch (data[4]) { - case 0: - data[4] = APCI1500_CONTINUOUS; - break; - case 1: - data[4] = APCI1500_SINGLE; - break; - default: - dev_warn(dev->class_dev, - "This option for single/continuous mode does not exist\n"); - return -EINVAL; - } - - /* Selecting software or hardware trigger */ - switch (data[5]) { - case 0: - data[5] = APCI1500_SOFTWARE_TRIGGER; - break; - case 1: - data[5] = APCI1500_HARDWARE_TRIGGER; - break; - default: - dev_warn(dev->class_dev, - "This choice for software or hardware trigger does not exist\n"); - return -EINVAL; - } - - /* Selecting software or hardware gate */ - switch (data[6]) { - case 0: - data[6] = APCI1500_SOFTWARE_GATE; - break; - case 1: - data[6] = APCI1500_HARDWARE_GATE; - break; - default: - dev_warn(dev->class_dev, - "This choice for software or hardware gate does not exist\n"); - return -EINVAL; - } - - 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); - } else { - dev_warn(dev->class_dev, - "Error in selection of interrupt enable or disable\n"); - return -EINVAL; - } - } else { - dev_warn(dev->class_dev, - "Error in selection of reload value\n"); - return -EINVAL; - } - i_TimerCounterWatchdogInterrupt = data[7]; - i_TimerCounter2Init = 1; - break; - - case COUNTER3: /* selecting counter or watchdog */ - switch (data[2]) { - case 0: - data[2] = APCI1500_COUNTER; - break; - case 1: - data[2] = APCI1500_WATCHDOG; - break; - default: - dev_warn(dev->class_dev, - "This choice is not a watchdog nor a counter\n"); - return -EINVAL; - } - - /* Selecting single or continuous mode */ - switch (data[4]) { - case 0: - data[4] = APCI1500_CONTINUOUS; - break; - case 1: - data[4] = APCI1500_SINGLE; - break; - default: - dev_warn(dev->class_dev, - "This option for single/continuous mode does not exist\n"); - return -EINVAL; - } - - /* Selecting software or hardware gate */ - switch (data[6]) { - case 0: - data[6] = APCI1500_SOFTWARE_GATE; - break; - case 1: - data[6] = APCI1500_HARDWARE_GATE; - break; - default: - dev_warn(dev->class_dev, - "This choice for software or hardware gate does not exist\n"); - return -EINVAL; - } - - /* 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; - } else { - i_TimerCounterMode = data[2] | data[4] | 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 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); - - } - - } else { - - dev_warn(dev->class_dev, - "Error in selection of interrupt enable or disable\n"); - return -EINVAL; - } - } else { - dev_warn(dev->class_dev, - "Error in selection of reload value\n"); - return -EINVAL; - } - i_TimerCounterWatchdogInterrupt = data[7]; - i_WatchdogCounter3Init = 1; - break; - - default: - dev_warn(dev->class_dev, - "The specified counter/timer option does not exist\n"); - return -EINVAL; - } - i_CounterLogic = data[2]; - return insn->n; -} - -/* - * 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 apci1500_private *devpriv = dev->private; - int i_CommandAndStatusValue; - - switch (data[0]) { - case COUNTER1: - switch (data[1]) { - case START: - if (i_TimerCounter1Init == 1) { - if (i_TimerCounterWatchdogInterrupt == 1) - i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ - else - i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ - - /* 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); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_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); - outb(0x00, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - i_TimerCounter1Enabled = 0; - break; - - case TRIGGER: - if (i_TimerCounter1Init == 1) { - if (i_TimerCounter1Enabled == 1) { - /* Set Trigger and gate */ - - i_CommandAndStatusValue = 0x6; - } else { - /* Set Trigger */ - - i_CommandAndStatusValue = 0x2; - } - - /* Selects the commands and status register */ - outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_dev, - "Counter/Timer1 not configured\n"); - return -EINVAL; - } - break; - - default: - dev_warn(dev->class_dev, - "The specified option for start/stop/trigger does not exist\n"); - return -EINVAL; - } - break; - - case COUNTER2: - switch (data[1]) { - case START: - if (i_TimerCounter2Init == 1) { - if (i_TimerCounterWatchdogInterrupt == 1) - i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ - else - i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ - - /* 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); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_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); - outb(0x00, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - i_TimerCounter2Enabled = 0; - break; - case TRIGGER: - if (i_TimerCounter2Init == 1) { - if (i_TimerCounter2Enabled == 1) { - /* Set Trigger and gate */ - - i_CommandAndStatusValue = 0x6; - } else { - /* Set Trigger */ - - i_CommandAndStatusValue = 0x2; - } - - /* Selects the commands and status register */ - outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_dev, - "Counter/Timer2 not configured\n"); - return -EINVAL; - } - break; - default: - dev_warn(dev->class_dev, - "The specified option for start/stop/trigger does not exist\n"); - return -EINVAL; - } - break; - case COUNTER3: - switch (data[1]) { - case START: - if (i_WatchdogCounter3Init == 1) { - - if (i_TimerCounterWatchdogInterrupt == 1) - i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ - else - i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ - - /* 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); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - - } else { - dev_warn(dev->class_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); - outb(0x00, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - i_WatchdogCounter3Enabled = 0; - break; - - case TRIGGER: - switch (data[2]) { - case 0: /* triggering counter 3 */ - if (i_WatchdogCounter3Init == 1) { - if (i_WatchdogCounter3Enabled == 1) { - /* Set Trigger and gate */ - - i_CommandAndStatusValue = 0x6; - } else { - /* Set Trigger */ - - i_CommandAndStatusValue = 0x2; - } - - /* Selects the commands and status register */ - outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_dev, - "Counter3 not configured\n"); - return -EINVAL; - } - break; - case 1: - /* 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); - outb(0x6, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_dev, - "Watchdog 3 not configured\n"); - return -EINVAL; - } - break; - default: - dev_warn(dev->class_dev, - "Wrong choice of watchdog/counter3\n"); - return -EINVAL; - } - break; - default: - dev_warn(dev->class_dev, - "The specified option for start/stop/trigger does not exist\n"); - return -EINVAL; - } - break; - default: - dev_warn(dev->class_dev, - "The specified choice for counter/watchdog/timer does not exist\n"); - return -EINVAL; - } - return insn->n; -} - -/* - * 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 apci1500_private *devpriv = dev->private; - int i_CommandAndStatusValue; - - switch (data[0]) { - case COUNTER1: - /* Read counter/timer1 */ - if (i_TimerCounter1Init == 1) { - if (i_TimerCounter1Enabled == 1) { - /* Set RCC and gate */ - - i_CommandAndStatusValue = 0xC; - } else { - /* Set RCC */ - - i_CommandAndStatusValue = 0x8; - } - - /* Selects the commands and status register */ - outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - - /* Selects the counter register (high) */ - outb(APCI1500_R_CPT_TMR1_VALUE_HIGH, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = - inb(devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = data[0] << 8; - data[0] = data[0] & 0xff00; - outb(APCI1500_R_CPT_TMR1_VALUE_LOW, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = - data[0] | inb(devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_dev, - "Timer/Counter1 not configured\n"); - return -EINVAL; - } - break; - case COUNTER2: - /* Read counter/timer2 */ - if (i_TimerCounter2Init == 1) { - if (i_TimerCounter2Enabled == 1) { - /* Set RCC and gate */ - - i_CommandAndStatusValue = 0xC; - } else { - /* Set RCC */ - - i_CommandAndStatusValue = 0x8; - } - - /* Selects the commands and status register */ - outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - - /* Selects the counter register (high) */ - outb(APCI1500_R_CPT_TMR2_VALUE_HIGH, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = - inb(devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = data[0] << 8; - data[0] = data[0] & 0xff00; - outb(APCI1500_R_CPT_TMR2_VALUE_LOW, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = - data[0] | inb(devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_dev, - "Timer/Counter2 not configured\n"); - return -EINVAL; - } - break; - case COUNTER3: - /* Read counter/watchdog2 */ - if (i_WatchdogCounter3Init == 1) { - if (i_WatchdogCounter3Enabled == 1) { - /* Set RCC and gate */ - - i_CommandAndStatusValue = 0xC; - } else { - /* Set RCC */ - - i_CommandAndStatusValue = 0x8; - } - - /* Selects the commands and status register */ - outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - outb(i_CommandAndStatusValue, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - - /* Selects the counter register (high) */ - outb(APCI1500_R_CPT_TMR3_VALUE_HIGH, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = - inb(devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = data[0] << 8; - data[0] = data[0] & 0xff00; - outb(APCI1500_R_CPT_TMR3_VALUE_LOW, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - data[0] = - data[0] | inb(devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - } else { - dev_warn(dev->class_dev, - "WatchdogCounter3 not configured\n"); - return -EINVAL; - } - break; - default: - dev_warn(dev->class_dev, - "The choice of timer/counter/watchdog does not exist\n"); - return -EINVAL; - } - - return insn->n; -} - -/* - * 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; - i_InterruptMask = 0; - return insn->n; -} - -/* - * 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 apci1500_private *devpriv = dev->private; - unsigned int ui_Status; - int i_RegValue; - int i_Constant; - - devpriv->tsk_Current = current; - outl(0x0, devpriv->i_IobaseAmcc + 0x38); - if (data[0] == 1) { - i_Constant = 0xC0; - } else { - if (data[0] == 0) { - i_Constant = 0x00; - } else { - dev_warn(dev->class_dev, - "The parameter passed to driver is in error for enabling the voltage interrupt\n"); - return -EINVAL; - } - } - - /* 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); - outl(0x23000, devpriv->i_IobaseAmcc + 0x38); - - return insn->n; -} - -static irqreturn_t apci1500_interrupt(int irq, void *d) -{ - - struct comedi_device *dev = d; - struct apci1500_private *devpriv = dev->private; - unsigned int ui_InterruptStatus = 0; - int i_RegValue = 0; - - /* Clear the interrupt mask */ - i_InterruptMask = 0; - - /* Read the board interrupt status */ - 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 */ - /* Disables the main interrupt on the board */ - /* 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 + - APCI1500_Z8536_CONTROL_REGISTER); - i_InterruptMask = i_InterruptMask | 1; - if (i_Logic == APCI1500_OR_PRIORITY) { - outb(APCI1500_RW_PORT_A_SPECIFICATION, - devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - i_RegValue = - 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); - i_RegValue = - inb(devpriv->iobase + - APCI1500_Z8536_CONTROL_REGISTER); - - i_InputChannel = 1 + (i_RegValue >> 1); - - } else { - i_InputChannel = 0; - } - } - - /* 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); - /* 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) { - i_InterruptMask = - i_InterruptMask | 0x40; - } - - if (i_RegValue & 0x40) { - i_InterruptMask = - i_InterruptMask | 0x80; - } - } else { - i_InterruptMask = i_InterruptMask | 2; - } - } - - /* 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; - } - /* 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 + - APCI1500_Z8536_CONTROL_REGISTER); - i_InterruptMask = i_InterruptMask | 8; - } - - /* 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 + - APCI1500_Z8536_CONTROL_REGISTER); - if (i_CounterLogic == APCI1500_COUNTER) - i_InterruptMask = i_InterruptMask | 0x10; - else - i_InterruptMask = i_InterruptMask | 0x20; - } - - 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); - } else { - dev_warn(dev->class_dev, - "Interrupt from unknown source\n"); - - } - - return IRQ_HANDLED; -} - -static int apci1500_reset(struct comedi_device *dev) -{ - struct apci1500_private *devpriv = dev->private; - int i_DummyRead = 0; - - i_TimerCounter1Init = 0; - i_TimerCounter2Init = 0; - i_WatchdogCounter3Init = 0; - i_Event1Status = 0; - i_Event2Status = 0; - i_TimerCounterWatchdogInterrupt = 0; - i_Logic = 0; - i_CounterLogic = 0; - i_InterruptMask = 0; - i_InputChannel = 0; - i_TimerCounter1Enabled = 0; - 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); - outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - 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); - - /* Selects the data path polarity register of port A */ - outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* High level of port A means 1 */ - outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - - /* Selects the data direction register of port A */ - outb(APCI1500_RW_PORT_A_DATA_DIRECTION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* All bits used as inputs */ - outb(0xFF, 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); - /* Deletes IP and IUS */ - outb(0x20, 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 the interrupt management of port A: */ - outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the handshake specification register of port A */ - outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* 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); - /* Selects the data path polarity register of port B */ - outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* A high level of port B means 1 */ - outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the data direction register of port B */ - outb(APCI1500_RW_PORT_B_DATA_DIRECTION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* All bits used as inputs */ - outb(0xFF, 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); - /* Deletes IP and IUS */ - outb(0x20, 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 the interrupt management of port B: */ - outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the handshake specification register of port B */ - outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* 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 */ - outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the data direction register of port C */ - outb(APCI1500_RW_PORT_C_DATA_DIRECTION, - devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* All bits used as inputs except channel 1 */ - outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /* Selects the special IO register of port C */ - outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL, - 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 */ - outb(0x20, 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 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 */ - outb(0x20, 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 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 */ - outb(0x20, 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 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_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index 339519a3d6b5..1f2f78186d58 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -93,7 +93,6 @@ static int apci3501_write_insn_timer(struct comedi_device *dev, { struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; - int i_Temp; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { @@ -135,7 +134,7 @@ static int apci3501_write_insn_timer(struct comedi_device *dev, } } - i_Temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + inl(dev->iobase + APCI3501_TIMER_STATUS_REG); return insn->n; } diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index bf14165297b7..4911b627203b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -22,6 +22,54 @@ * more details. */ +/* + * Driver: addi_apci_1032 + * Description: ADDI-DATA APCI-1032 Digital Input Board + * Author: ADDI-DATA GmbH <info@addi-data.com>, + * H Hartley Sweeten <hsweeten@visionengravers.com> + * Status: untested + * Devices: [ADDI-DATA] APCI-1032 (addi_apci_1032) + * + * Configuration options: + * None; devices are configured automatically. + * + * This driver models the APCI-1032 as a 32-channel, digital input subdevice + * plus an additional digital input subdevice to handle change-of-state (COS) + * interrupts (if an interrupt handler can be set up successfully). + * + * The COS subdevice supports comedi asynchronous read commands. + * + * Change-Of-State (COS) interrupt configuration: + * + * Channels 0 to 15 are interruptible. These channels can be configured + * to generate interrupts based on AND/OR logic for the desired channels. + * + * OR logic: + * - reacts to rising or falling edges + * - interrupt is generated when any enabled channel meets the desired + * interrupt condition + * + * AND logic: + * - reacts to changes in level of the selected inputs + * - interrupt is generated when all enabled channels meet the desired + * interrupt condition + * - after an interrupt, a change in level must occur on the selected + * inputs to release the IRQ logic + * + * The COS subdevice must be configured before setting up a comedi + * asynchronous command: + * + * data[0] : INSN_CONFIG_DIGITAL_TRIG + * data[1] : trigger number (= 0) + * data[2] : configuration operation: + * - COMEDI_DIGITAL_TRIG_DISABLE = no interrupts + * - COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts + * - COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts + * data[3] : left-shift for data[4] and data[5] + * data[4] : rising-edge/high level channels + * data[5] : falling-edge/low level channels + */ + #include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -62,36 +110,6 @@ static int apci1032_reset(struct comedi_device *dev) return 0; } -/* - * Change-Of-State (COS) interrupt configuration - * - * Channels 0 to 15 are interruptible. These channels can be configured - * to generate interrupts based on AND/OR logic for the desired channels. - * - * OR logic - * - reacts to rising or falling edges - * - interrupt is generated when any enabled channel - * meet the desired interrupt condition - * - * AND logic - * - reacts to changes in level of the selected inputs - * - interrupt is generated when all enabled channels - * meet the desired interrupt condition - * - after an interrupt, a change in level must occur on - * the selected inputs to release the IRQ logic - * - * The COS interrupt must be configured before it can be enabled. - * - * data[0] : INSN_CONFIG_DIGITAL_TRIG - * data[1] : trigger number (= 0) - * data[2] : configuration operation: - * COMEDI_DIGITAL_TRIG_DISABLE = no interrupts - * COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts - * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts - * data[3] : left-shift for data[4] and data[5] - * data[4] : rising-edge/high level channels - * data[5] : falling-edge/low level channels - */ static int apci1032_cos_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index 30b132c3d092..f15aa1f6b476 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -1,22 +1,755 @@ +/* + * addi_apci_1500.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + #include <linux/module.h> #include <linux/pci.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" +#include "z8536.h" + +/* + * PCI Bar 0 Register map (devpriv->amcc) + * see amcc_s5933.h for register and bit defines + */ + +/* + * PCI Bar 1 Register map (dev->iobase) + * see z8536.h for Z8536 internal registers and bit defines + */ +#define APCI1500_Z8536_PORTC_REG 0x00 +#define APCI1500_Z8536_PORTB_REG 0x01 +#define APCI1500_Z8536_PORTA_REG 0x02 +#define APCI1500_Z8536_CTRL_REG 0x03 + +/* + * PCI Bar 2 Register map (devpriv->addon) + */ +#define APCI1500_CLK_SEL_REG 0x00 +#define APCI1500_DI_REG 0x00 +#define APCI1500_DO_REG 0x02 struct apci1500_private { - int iobase; - int i_IobaseAmcc; - int i_IobaseAddon; - int i_IobaseReserved; - unsigned char b_OutputMemoryStatus; - struct task_struct *tsk_Current; + unsigned long amcc; + unsigned long addon; + + unsigned int clk_src; + + /* Digital trigger configuration [0]=AND [1]=OR */ + unsigned int pm[2]; /* Pattern Mask */ + unsigned int pt[2]; /* Pattern Transition */ + unsigned int pp[2]; /* Pattern Polarity */ }; -#include "addi-data/hwdrv_apci1500.c" +static unsigned int z8536_read(struct comedi_device *dev, unsigned int reg) +{ + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&dev->spinlock, flags); + outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG); + val = inb(dev->iobase + APCI1500_Z8536_CTRL_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + + return val; +} + +static void z8536_write(struct comedi_device *dev, + unsigned int val, unsigned int reg) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->spinlock, flags); + outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG); + outb(val, dev->iobase + APCI1500_Z8536_CTRL_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); +} + +static void z8536_reset(struct comedi_device *dev) +{ + unsigned long flags; + + /* + * Even if the state of the Z8536 is not known, the following + * sequence will reset it and put it in State 0. + */ + spin_lock_irqsave(&dev->spinlock, flags); + inb(dev->iobase + APCI1500_Z8536_CTRL_REG); + outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG); + inb(dev->iobase + APCI1500_Z8536_CTRL_REG); + outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG); + outb(1, dev->iobase + APCI1500_Z8536_CTRL_REG); + outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* Disable all Ports and Counter/Timers */ + z8536_write(dev, 0x00, Z8536_CFG_CTRL_REG); + + /* + * Port A is connected to Ditial Input channels 0-7. + * Configure the port to allow interrupt detection. + */ + z8536_write(dev, Z8536_PAB_MODE_PTS_BIT | + Z8536_PAB_MODE_SB | + Z8536_PAB_MODE_PMS_DISABLE, + Z8536_PA_MODE_REG); + z8536_write(dev, 0xff, Z8536_PB_DPP_REG); + z8536_write(dev, 0xff, Z8536_PA_DD_REG); + + /* + * Port B is connected to Ditial Input channels 8-13. + * Configure the port to allow interrupt detection. + * + * NOTE: Bits 7 and 6 of Port B are connected to internal + * diagnostic signals and bit 7 is inverted. + */ + z8536_write(dev, Z8536_PAB_MODE_PTS_BIT | + Z8536_PAB_MODE_SB | + Z8536_PAB_MODE_PMS_DISABLE, + Z8536_PB_MODE_REG); + z8536_write(dev, 0x7f, Z8536_PB_DPP_REG); + z8536_write(dev, 0xff, Z8536_PB_DD_REG); + + /* + * Not sure what Port C is connected to... + */ + z8536_write(dev, 0x09, Z8536_PC_DPP_REG); + z8536_write(dev, 0x0e, Z8536_PC_DD_REG); + + /* + * Clear and disable all interrupt sources. + * + * Just in case, the reset of the Z8536 should have already + * done this. + */ + z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PA_CMDSTAT_REG); + z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG); + + z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PB_CMDSTAT_REG); + z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG); + + z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(0)); + z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(0)); + + z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(1)); + z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(1)); + + z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(2)); + z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(2)); + + /* Disable all interrupts */ + z8536_write(dev, 0x00, Z8536_INT_CTRL_REG); +} + +static void apci1500_port_enable(struct comedi_device *dev, bool enable) +{ + unsigned int cfg; + + cfg = z8536_read(dev, Z8536_CFG_CTRL_REG); + if (enable) + cfg |= (Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE); + else + cfg &= ~(Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE); + z8536_write(dev, cfg, Z8536_CFG_CTRL_REG); +} + +static void apci1500_timer_enable(struct comedi_device *dev, + unsigned int chan, bool enable) +{ + unsigned int bit; + unsigned int cfg; + + if (chan == 0) + bit = Z8536_CFG_CTRL_CT1E; + else if (chan == 1) + bit = Z8536_CFG_CTRL_CT2E; + else + bit = Z8536_CFG_CTRL_PCE_CT3E; + + cfg = z8536_read(dev, Z8536_CFG_CTRL_REG); + if (enable) { + cfg |= bit; + } else { + cfg &= ~bit; + z8536_write(dev, 0x00, Z8536_CT_CMDSTAT_REG(chan)); + } + z8536_write(dev, cfg, Z8536_CFG_CTRL_REG); +} + +static bool apci1500_ack_irq(struct comedi_device *dev, + unsigned int reg) +{ + unsigned int val; + + val = z8536_read(dev, reg); + if ((val & Z8536_STAT_IE_IP) == Z8536_STAT_IE_IP) { + val &= 0x0f; /* preserve any write bits */ + val |= Z8536_CMD_CLR_IP_IUS; + z8536_write(dev, val, reg); + + return true; + } + return false; +} + +static irqreturn_t apci1500_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct apci1500_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int status = 0; + unsigned int val; + + val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR); + if (!(val & INTCSR_INTR_ASSERTED)) + return IRQ_NONE; + + if (apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG)) + status |= 0x01; /* port a event (inputs 0-7) */ + + if (apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG)) { + /* Tests if this is an external error */ + val = inb(dev->iobase + APCI1500_Z8536_PORTB_REG); + val &= 0xc0; + if (val) { + if (val & 0x80) /* voltage error */ + status |= 0x40; + if (val & 0x40) /* short circuit error */ + status |= 0x80; + } else { + status |= 0x02; /* port b event (inputs 8-13) */ + } + } + + /* + * NOTE: The 'status' returned by the sample matches the + * interrupt mask information from the APCI-1500 Users Manual. + * + * Mask Meaning + * ---------- ------------------------------------------ + * 0x00000001 Event 1 has occured + * 0x00000010 Event 2 has occured + * 0x00000100 Counter/timer 1 has run down (not implemented) + * 0x00001000 Counter/timer 2 has run down (not implemented) + * 0x00010000 Counter 3 has run down (not implemented) + * 0x00100000 Watchdog has run down (not implemented) + * 0x01000000 Voltage error + * 0x10000000 Short-circuit error + */ + comedi_buf_write_samples(s, &status, 1); + comedi_handle_events(dev, s); + + return IRQ_HANDLED; +} + +static int apci1500_di_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + /* Disables the main interrupt on the board */ + z8536_write(dev, 0x00, Z8536_INT_CTRL_REG); + + /* Disable Ports A & B */ + apci1500_port_enable(dev, false); + + /* Ack any pending interrupts */ + apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG); + apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG); + + /* Disable pattern interrupts */ + z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG); + z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG); + + /* Enable Ports A & B */ + apci1500_port_enable(dev, true); + + return 0; +} + +static int apci1500_di_inttrig_start(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) +{ + struct apci1500_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int pa_mode = Z8536_PAB_MODE_PMS_DISABLE; + unsigned int pb_mode = Z8536_PAB_MODE_PMS_DISABLE; + unsigned int pa_trig = trig_num & 0x01; + unsigned int pb_trig = (trig_num >> 1) & 0x01; + bool valid_trig = false; + unsigned int val; + + if (trig_num != cmd->start_arg) + return -EINVAL; + + /* Disable Ports A & B */ + apci1500_port_enable(dev, false); + + /* Set Port A for selected trigger pattern */ + z8536_write(dev, devpriv->pm[pa_trig] & 0xff, Z8536_PA_PM_REG); + z8536_write(dev, devpriv->pt[pa_trig] & 0xff, Z8536_PA_PT_REG); + z8536_write(dev, devpriv->pp[pa_trig] & 0xff, Z8536_PA_PP_REG); + + /* Set Port B for selected trigger pattern */ + z8536_write(dev, (devpriv->pm[pb_trig] >> 8) & 0xff, Z8536_PB_PM_REG); + z8536_write(dev, (devpriv->pt[pb_trig] >> 8) & 0xff, Z8536_PB_PT_REG); + z8536_write(dev, (devpriv->pp[pb_trig] >> 8) & 0xff, Z8536_PB_PP_REG); + + /* Set Port A trigger mode (if enabled) and enable interrupt */ + if (devpriv->pm[pa_trig] & 0xff) { + pa_mode = pa_trig ? Z8536_PAB_MODE_PMS_AND + : Z8536_PAB_MODE_PMS_OR; + + val = z8536_read(dev, Z8536_PA_MODE_REG); + val &= ~Z8536_PAB_MODE_PMS_MASK; + val |= (pa_mode | Z8536_PAB_MODE_IMO); + z8536_write(dev, val, Z8536_PA_MODE_REG); + + z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PA_CMDSTAT_REG); + + valid_trig = true; + + dev_dbg(dev->class_dev, + "Port A configured for %s mode pattern detection\n", + pa_trig ? "AND" : "OR"); + } + + /* Set Port B trigger mode (if enabled) and enable interrupt */ + if (devpriv->pm[pb_trig] & 0xff00) { + pb_mode = pb_trig ? Z8536_PAB_MODE_PMS_AND + : Z8536_PAB_MODE_PMS_OR; + + val = z8536_read(dev, Z8536_PB_MODE_REG); + val &= ~Z8536_PAB_MODE_PMS_MASK; + val |= (pb_mode | Z8536_PAB_MODE_IMO); + z8536_write(dev, val, Z8536_PB_MODE_REG); + + z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PB_CMDSTAT_REG); + + valid_trig = true; + + dev_dbg(dev->class_dev, + "Port B configured for %s mode pattern detection\n", + pb_trig ? "AND" : "OR"); + } + + /* Enable Ports A & B */ + apci1500_port_enable(dev, true); + + if (!valid_trig) { + dev_dbg(dev->class_dev, + "digital trigger %d is not configured\n", trig_num); + return -EINVAL; + } + + /* Authorizes the main interrupt on the board */ + z8536_write(dev, Z8536_INT_CTRL_MIE | Z8536_INT_CTRL_DLC, + Z8536_INT_CTRL_REG); + + return 0; +} + +static int apci1500_di_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + s->async->inttrig = apci1500_di_inttrig_start; + + return 0; +} + +static int apci1500_di_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ + + /* Step 3: check if arguments are trivially valid */ + + /* + * Internal start source triggers: + * + * 0 AND mode for Port A (digital inputs 0-7) + * AND mode for Port B (digital inputs 8-13 and internal signals) + * + * 1 OR mode for Port A (digital inputs 0-7) + * AND mode for Port B (digital inputs 8-13 and internal signals) + * + * 2 AND mode for Port A (digital inputs 0-7) + * OR mode for Port B (digital inputs 8-13 and internal signals) + * + * 3 OR mode for Port A (digital inputs 0-7) + * OR mode for Port B (digital inputs 8-13 and internal signals) + */ + err |= cfc_check_trigger_arg_max(&cmd->start_arg, 3); + + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* Step 4: fix up any arguments */ + + /* Step 5: check channel list if it exists */ + + return 0; +} + +/* + * The pattern-recognition logic must be configured before the digital + * input async command is started. + * + * Digital input channels 0 to 13 can generate interrupts. Channels 14 + * and 15 are connected to internal board status/diagnostic signals. + * + * Channel 14 - Voltage error (the external supply is < 5V) + * Channel 15 - Short-circuit/overtemperature error + * + * data[0] : INSN_CONFIG_DIGITAL_TRIG + * data[1] : trigger number + * 0 = AND mode + * 1 = OR mode + * data[2] : configuration operation: + * COMEDI_DIGITAL_TRIG_DISABLE = no interrupts + * COMEDI_DIGITAL_TRIG_ENABLE_EDGES = edge interrupts + * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = level interrupts + * data[3] : left-shift for data[4] and data[5] + * data[4] : rising-edge/high level channels + * data[5] : falling-edge/low level channels + */ +static int apci1500_di_cfg_trig(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1500_private *devpriv = dev->private; + unsigned int trig = data[1]; + unsigned int shift = data[3]; + unsigned int hi_mask = data[4] << shift; + unsigned int lo_mask = data[5] << shift; + unsigned int chan_mask = hi_mask | lo_mask; + unsigned int old_mask = (1 << shift) - 1; + unsigned int pm = devpriv->pm[trig] & old_mask; + unsigned int pt = devpriv->pt[trig] & old_mask; + unsigned int pp = devpriv->pp[trig] & old_mask; + + if (trig > 1) { + dev_dbg(dev->class_dev, + "invalid digital trigger number (0=AND, 1=OR)\n"); + return -EINVAL; + } + + if (chan_mask > 0xffff) { + dev_dbg(dev->class_dev, "invalid digital trigger channel\n"); + return -EINVAL; + } + + switch (data[2]) { + case COMEDI_DIGITAL_TRIG_DISABLE: + /* clear trigger configuration */ + pm = 0; + pt = 0; + pp = 0; + break; + case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: + pm |= chan_mask; /* enable channels */ + pt |= chan_mask; /* enable edge detection */ + pp |= hi_mask; /* rising-edge channels */ + pp &= ~lo_mask; /* falling-edge channels */ + break; + case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS: + pm |= chan_mask; /* enable channels */ + pt &= ~chan_mask; /* enable level detection */ + pp |= hi_mask; /* high level channels */ + pp &= ~lo_mask; /* low level channels */ + break; + default: + return -EINVAL; + } + + /* + * The AND mode trigger can only have one channel (max) enabled + * for edge detection. + */ + if (trig == 0) { + int ret = 0; + unsigned int src; + + src = pt & 0xff; + if (src) + ret |= cfc_check_trigger_is_unique(src); + + src = (pt >> 8) & 0xff; + if (src) + ret |= cfc_check_trigger_is_unique(src); + + if (ret) { + dev_dbg(dev->class_dev, + "invalid AND trigger configuration\n"); + return ret; + } + } + + /* save the trigger configuration */ + devpriv->pm[trig] = pm; + devpriv->pt[trig] = pt; + devpriv->pp[trig] = pp; + + return insn->n; +} + +static int apci1500_di_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + switch (data[0]) { + case INSN_CONFIG_DIGITAL_TRIG: + return apci1500_di_cfg_trig(dev, s, insn, data); + default: + return -EINVAL; + } +} + +static int apci1500_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1500_private *devpriv = dev->private; + + data[1] = inw(devpriv->addon + APCI1500_DI_REG); + + return insn->n; +} + +static int apci1500_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1500_private *devpriv = dev->private; + + if (comedi_dio_update_state(s, data)) + outw(s->state, devpriv->addon + APCI1500_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int apci1500_timer_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1500_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + + switch (data[0]) { + case INSN_CONFIG_ARM: + val = data[1] & s->maxdata; + z8536_write(dev, val & 0xff, Z8536_CT_RELOAD_LSB_REG(chan)); + z8536_write(dev, (val >> 8) & 0xff, + Z8536_CT_RELOAD_MSB_REG(chan)); + + apci1500_timer_enable(dev, chan, true); + z8536_write(dev, Z8536_CT_CMDSTAT_GCB, + Z8536_CT_CMDSTAT_REG(chan)); + break; + case INSN_CONFIG_DISARM: + apci1500_timer_enable(dev, chan, false); + break; + + case INSN_CONFIG_GET_COUNTER_STATUS: + data[1] = 0; + val = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan)); + if (val & Z8536_CT_STAT_CIP) + data[1] |= COMEDI_COUNTER_COUNTING; + if (val & Z8536_CT_CMDSTAT_GCB) + data[1] |= COMEDI_COUNTER_ARMED; + if (val & Z8536_STAT_IP) { + data[1] |= COMEDI_COUNTER_TERMINAL_COUNT; + apci1500_ack_irq(dev, Z8536_CT_CMDSTAT_REG(chan)); + } + data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING | + COMEDI_COUNTER_TERMINAL_COUNT; + break; + + case INSN_CONFIG_SET_COUNTER_MODE: + /* Simulate the 8254 timer modes */ + switch (data[1]) { + case I8254_MODE0: + /* Interrupt on Terminal Count */ + val = Z8536_CT_MODE_ECE | + Z8536_CT_MODE_DCS_ONESHOT; + break; + case I8254_MODE1: + /* Hardware Retriggerable One-Shot */ + val = Z8536_CT_MODE_ETE | + Z8536_CT_MODE_DCS_ONESHOT; + break; + case I8254_MODE2: + /* Rate Generator */ + val = Z8536_CT_MODE_CSC | + Z8536_CT_MODE_DCS_PULSE; + break; + case I8254_MODE3: + /* Square Wave Mode */ + val = Z8536_CT_MODE_CSC | + Z8536_CT_MODE_DCS_SQRWAVE; + break; + case I8254_MODE4: + /* Software Triggered Strobe */ + val = Z8536_CT_MODE_REB | + Z8536_CT_MODE_DCS_PULSE; + break; + case I8254_MODE5: + /* Hardware Triggered Strobe (watchdog) */ + val = Z8536_CT_MODE_EOE | + Z8536_CT_MODE_ETE | + Z8536_CT_MODE_REB | + Z8536_CT_MODE_DCS_PULSE; + break; + default: + return -EINVAL; + } + apci1500_timer_enable(dev, chan, false); + z8536_write(dev, val, Z8536_CT_MODE_REG(chan)); + break; + + case INSN_CONFIG_SET_CLOCK_SRC: + if (data[1] > 2) + return -EINVAL; + devpriv->clk_src = data[1]; + if (devpriv->clk_src == 2) + devpriv->clk_src = 3; + outw(devpriv->clk_src, devpriv->addon + APCI1500_CLK_SEL_REG); + break; + case INSN_CONFIG_GET_CLOCK_SRC: + switch (devpriv->clk_src) { + case 0: + data[1] = 0; /* 111.86 kHz / 2 */ + data[2] = 17879; /* 17879 ns (approx) */ + break; + case 1: + data[1] = 1; /* 3.49 kHz / 2 */ + data[2] = 573066; /* 573066 ns (approx) */ + break; + case 3: + data[1] = 2; /* 1.747 kHz / 2 */ + data[2] = 1164822; /* 1164822 ns (approx) */ + break; + default: + return -EINVAL; + } + break; + + case INSN_CONFIG_SET_GATE_SRC: + if (chan == 0) + return -EINVAL; + + val = z8536_read(dev, Z8536_CT_MODE_REG(chan)); + val &= Z8536_CT_MODE_EGE; + if (data[1] == 1) + val |= Z8536_CT_MODE_EGE; + else if (data[1] > 1) + return -EINVAL; + z8536_write(dev, val, Z8536_CT_MODE_REG(chan)); + break; + case INSN_CONFIG_GET_GATE_SRC: + if (chan == 0) + return -EINVAL; + break; + + default: + return -EINVAL; + } + return insn->n; +} + +static int apci1500_timer_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 cmd; + + cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan)); + cmd &= Z8536_CT_CMDSTAT_GCB; /* preserve gate */ + cmd |= Z8536_CT_CMD_TCB; /* set trigger */ + + /* software trigger a timer, it only makes sense to do one write */ + if (insn->n) + z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan)); + + return insn->n; +} + +static int apci1500_timer_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 cmd; + unsigned int val; + int i; + + cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan)); + cmd &= Z8536_CT_CMDSTAT_GCB; /* preserve gate */ + cmd |= Z8536_CT_CMD_RCC; /* set RCC */ + + for (i = 0; i < insn->n; i++) { + z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan)); + + val = z8536_read(dev, Z8536_CT_VAL_MSB_REG(chan)) << 8; + val |= z8536_read(dev, Z8536_CT_VAL_LSB_REG(chan)); + + data[i] = val; + } + + return insn->n; +} static int apci1500_auto_attach(struct comedi_device *dev, unsigned long context) @@ -35,10 +768,10 @@ static int apci1500_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 1); - devpriv->iobase = dev->iobase; - devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); - devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); - devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); + devpriv->amcc = pci_resource_start(pcidev, 0); + devpriv->addon = pci_resource_start(pcidev, 2); + + z8536_reset(dev); if (pcidev->irq > 0) { ret = request_irq(pcidev->irq, apci1500_interrupt, IRQF_SHARED, @@ -51,51 +784,66 @@ static int apci1500_auto_attach(struct comedi_device *dev, if (ret) return ret; - /* Allocate and Initialise DI Subdevice Structures */ + /* Digital Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = apci1500_di_config; - s->insn_read = apci1500_di_read; - s->insn_write = apci1500_di_write; - s->insn_bits = apci1500_di_insn_bits; - - /* Allocate and Initialise DO Subdevice Structures */ + 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 = apci1500_di_insn_bits; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->insn_config = apci1500_di_insn_config; + s->do_cmdtest = apci1500_di_cmdtest; + s->do_cmd = apci1500_di_cmd; + s->cancel = apci1500_di_cancel; + } + + /* Digital Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = apci1500_do_config; - s->insn_write = apci1500_do_write; - s->insn_bits = apci1500_do_bits; - - /* Allocate and Initialise Timer Subdevice Structures */ + 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 = apci1500_do_insn_bits; + + /* reset all the digital outputs */ + outw(0x0, devpriv->addon + APCI1500_DO_REG); + + /* Counter/Timer(Watchdog) subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; - s->range_table = &range_digital; - s->insn_write = apci1500_timer_write; - s->insn_read = apci1500_timer_read; - s->insn_config = apci1500_timer_config; - s->insn_bits = apci1500_timer_bits; - - apci1500_reset(dev); + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0xffff; + s->range_table = &range_unknown; + s->insn_config = apci1500_timer_insn_config; + s->insn_write = apci1500_timer_insn_write; + s->insn_read = apci1500_timer_insn_read; + + /* Enable the PCI interrupt */ + if (dev->irq) { + outl(0x2000 | INTCSR_INBOX_FULL_INT, + devpriv->amcc + AMCC_OP_REG_INTCSR); + inl(devpriv->amcc + AMCC_OP_REG_IMB1); + inl(devpriv->amcc + AMCC_OP_REG_INTCSR); + outl(INTCSR_INBOX_INTR_STATUS | 0x2000 | INTCSR_INBOX_FULL_INT, + devpriv->amcc + AMCC_OP_REG_INTCSR); + } return 0; } static void apci1500_detach(struct comedi_device *dev) { - if (dev->iobase) - apci1500_reset(dev); + struct apci1500_private *devpriv = dev->private; + + if (devpriv->amcc) + outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR); comedi_pci_detach(dev); } diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index a726efcea6a5..5961f195ba0b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -267,7 +267,6 @@ static irqreturn_t apci3501_interrupt(int irq, void *d) struct apci3501_private *devpriv = dev->private; unsigned int ui_Timer_AOWatchdog; unsigned long ul_Command1; - int i_temp; /* Disable Interrupt */ ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); @@ -285,7 +284,7 @@ static irqreturn_t apci3501_interrupt(int irq, void *d) ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1); outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); - i_temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + inl(dev->iobase + APCI3501_TIMER_STATUS_REG); return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 528f15c25dae..a3ea4b7c18dd 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -19,8 +19,7 @@ /* * Driver: adl_pci6208 * Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards - * Devices: (ADLink) PCI-6208 [adl_pci6208] - * (ADLink) PCI-6216 [adl_pci6216] + * Devices: [ADLink] PCI-6208 (adl_pci6208), PCI-6216 (adl_pci6216) * Author: nsyeow <nsyeow@pd.jaring.my> * Updated: Fri, 30 Jan 2004 14:44:27 +0800 * Status: untested diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index fb8e5f582496..618e641ffaac 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -22,27 +22,35 @@ */ /* -Driver: adl_pci7x3x -Description: 32/64-Channel Isolated Digital I/O Boards -Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output - (ADLink) PCI-7233 [adl_pci7233] - 32 input - (ADLink) PCI-7234 [adl_pci7234] - 32 output - (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output - (ADLink) PCI-7433 [adl_pci7433] - 64 input - (ADLink) PCI-7434 [adl_pci7434] - 64 output -Author: H Hartley Sweeten <hsweeten@visionengravers.com> -Updated: Thu, 02 Aug 2012 14:27:46 -0700 -Status: untested - -The PCI-7230, PCI-7432 and PCI-7433 boards also support external -interrupt signals on digital input channels 0 and 1. The PCI-7233 -has dual-interrupt sources for change-of-state (COS) on any 16 -digital input channels of LSB and for COS on any 16 digital input -lines of MSB. Interrupts are not currently supported by this -driver. - -Configuration Options: not applicable, uses comedi PCI auto config -*/ + * Driver: adl_pci7x3x + * Description: 32/64-Channel Isolated Digital I/O Boards + * Devices: [ADLink] PCI-7230 (adl_pci7230), PCI-7233 (adl_pci7233), + * PCI-7234 (adl_pci7234), PCI-7432 (adl_pci7432), PCI-7433 (adl_pci7433), + * PCI-7434 (adl_pci7434) + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Thu, 02 Aug 2012 14:27:46 -0700 + * Status: untested + * + * One or two subdevices are setup by this driver depending on + * the number of digital inputs and/or outputs provided by the + * board. Each subdevice has a maximum of 32 channels. + * + * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output + * PCI-7233 - 1 subdevice: 0 - 32 input + * PCI-7234 - 1 subdevice: 0 - 32 output + * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output + * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input + * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output + * + * The PCI-7230, PCI-7432 and PCI-7433 boards also support external + * interrupt signals on digital input channels 0 and 1. The PCI-7233 + * has dual-interrupt sources for change-of-state (COS) on any 16 + * digital input channels of LSB and for COS on any 16 digital input + * lines of MSB. Interrupts are not currently supported by this + * driver. + * + * Configuration Options: not applicable, uses comedi PCI auto config + */ #include <linux/module.h> #include <linux/pci.h> @@ -155,18 +163,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 2); - /* - * One or two subdevices are setup by this driver depending on - * the number of digital inputs and/or outputs provided by the - * board. Each subdevice has a maximum of 32 channels. - * - * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output - * PCI-7233 - 1 subdevice: 0 - 32 input - * PCI-7234 - 1 subdevice: 0 - 32 output - * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output - * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input - * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output - */ ret = comedi_alloc_subdevices(dev, board->nsubdevs); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index 72bccb447a74..cc6c53b800a7 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -18,7 +18,7 @@ /* * Driver: adl_pci8164 * Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board - * Devices: (ADLink) PCI-8164 [adl_pci8164] + * Devices: [ADLink] PCI-8164 (adl_pci8164) * Author: Michel Lachaine <mike@mikelachaine.ca> * Status: experimental * Updated: Mon, 14 Apr 2008 15:10:32 +0100 diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index 47f6c0e9f014..f68dc99f8e27 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -539,7 +539,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) spin_unlock_irqrestore(&dev->spinlock, irq_flags); dev_dbg(dev->class_dev, "fifo overflow\n"); outb(0, dev->iobase + PCI9111_INT_CLR_REG); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); return IRQ_HANDLED; diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 26603582e71a..f61e392c2d3e 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -749,13 +749,13 @@ static irqreturn_t pci9118_interrupt(int irq, void *d) if (intcsr & MASTER_ABORT_INT) { dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n"); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_ERROR; goto interrupt_exit; } if (intcsr & TARGET_ABORT_INT) { dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n"); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_ERROR; goto interrupt_exit; } diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index d02df7d0c629..9800c01e6fb9 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -51,11 +51,6 @@ Configuration options: #include "8253.h" #include "amcc_s5933.h" -/* hardware types of the cards */ -#define TYPE_PCI171X 0 -#define TYPE_PCI1713 2 -#define TYPE_PCI1720 3 - #define PCI171x_AD_DATA 0 /* R: A/D data */ #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */ #define PCI171x_RANGE 2 /* W: A/D gain/range register */ @@ -164,7 +159,7 @@ static const struct comedi_lrange range_pci17x1 = { static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 }; -static const struct comedi_lrange range_pci1720 = { +static const struct comedi_lrange pci1720_ao_range = { 4, { UNI_RANGE(5), UNI_RANGE(10), @@ -173,7 +168,7 @@ static const struct comedi_lrange range_pci1720 = { } }; -static const struct comedi_lrange range_pci171x_da = { +static const struct comedi_lrange pci171x_ao_range = { 2, { UNI_RANGE(5), UNI_RANGE(10) @@ -191,112 +186,81 @@ enum pci1710_boardid { struct boardtype { const char *name; /* board name */ - char have_irq; /* 1=card support IRQ */ - char cardtype; /* 0=1710& co. 2=1713, ... */ int n_aichan; /* num of A/D chans */ - int n_aichand; /* num of A/D chans in diff mode */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - int n_counter; /* num of counters */ - int ai_maxdata; /* resolution of A/D */ - int ao_maxdata; /* resolution of D/A */ const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ const char *rangecode_ai; /* range codes for programming */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ - unsigned int ai_ns_min; /* max sample speed of card v ns */ - unsigned int fifo_half_size; /* size of FIFO/2 */ + unsigned int is_pci1713:1; + unsigned int is_pci1720:1; + unsigned int has_irq:1; + unsigned int has_large_fifo:1; /* 4K or 1K FIFO */ + unsigned int has_diff_ai:1; + unsigned int has_ao:1; + unsigned int has_di_do:1; + unsigned int has_counter:1; }; static const struct boardtype boardtypes[] = { [BOARD_PCI1710] = { .name = "pci1710", - .have_irq = 1, - .cardtype = TYPE_PCI171X, .n_aichan = 16, - .n_aichand = 8, - .n_aochan = 2, - .n_dichan = 16, - .n_dochan = 16, - .n_counter = 1, - .ai_maxdata = 0x0fff, - .ao_maxdata = 0x0fff, .rangelist_ai = &range_pci1710_3, .rangecode_ai = range_codes_pci1710_3, - .rangelist_ao = &range_pci171x_da, - .ai_ns_min = 10000, - .fifo_half_size = 2048, + .has_irq = 1, + .has_large_fifo = 1, + .has_diff_ai = 1, + .has_ao = 1, + .has_di_do = 1, + .has_counter = 1, }, [BOARD_PCI1710HG] = { .name = "pci1710hg", - .have_irq = 1, - .cardtype = TYPE_PCI171X, .n_aichan = 16, - .n_aichand = 8, - .n_aochan = 2, - .n_dichan = 16, - .n_dochan = 16, - .n_counter = 1, - .ai_maxdata = 0x0fff, - .ao_maxdata = 0x0fff, .rangelist_ai = &range_pci1710hg, .rangecode_ai = range_codes_pci1710hg, - .rangelist_ao = &range_pci171x_da, - .ai_ns_min = 10000, - .fifo_half_size = 2048, + .has_irq = 1, + .has_large_fifo = 1, + .has_diff_ai = 1, + .has_ao = 1, + .has_di_do = 1, + .has_counter = 1, }, [BOARD_PCI1711] = { .name = "pci1711", - .have_irq = 1, - .cardtype = TYPE_PCI171X, .n_aichan = 16, - .n_aochan = 2, - .n_dichan = 16, - .n_dochan = 16, - .n_counter = 1, - .ai_maxdata = 0x0fff, - .ao_maxdata = 0x0fff, .rangelist_ai = &range_pci17x1, .rangecode_ai = range_codes_pci17x1, - .rangelist_ao = &range_pci171x_da, - .ai_ns_min = 10000, - .fifo_half_size = 512, + .has_irq = 1, + .has_ao = 1, + .has_di_do = 1, + .has_counter = 1, }, [BOARD_PCI1713] = { .name = "pci1713", - .have_irq = 1, - .cardtype = TYPE_PCI1713, .n_aichan = 32, - .n_aichand = 16, - .ai_maxdata = 0x0fff, .rangelist_ai = &range_pci1710_3, .rangecode_ai = range_codes_pci1710_3, - .ai_ns_min = 10000, - .fifo_half_size = 2048, + .is_pci1713 = 1, + .has_irq = 1, + .has_large_fifo = 1, + .has_diff_ai = 1, }, [BOARD_PCI1720] = { .name = "pci1720", - .cardtype = TYPE_PCI1720, - .n_aochan = 4, - .ao_maxdata = 0x0fff, - .rangelist_ao = &range_pci1720, + .is_pci1720 = 1, + .has_ao = 1, }, [BOARD_PCI1731] = { .name = "pci1731", - .have_irq = 1, - .cardtype = TYPE_PCI171X, .n_aichan = 16, - .n_dichan = 16, - .n_dochan = 16, - .ai_maxdata = 0x0fff, .rangelist_ai = &range_pci17x1, .rangecode_ai = range_codes_pci17x1, - .ai_ns_min = 10000, - .fifo_half_size = 512, + .has_irq = 1, + .has_di_do = 1, }, }; struct pci1710_private { + unsigned int max_samples; unsigned int CntrlReg; /* Control register */ unsigned char ai_et; unsigned int ai_et_CntrlReg; @@ -308,39 +272,10 @@ struct pci1710_private { unsigned int act_chanlist[32]; /* list of scanned channel */ unsigned char saved_seglen; /* len of the non-repeating chanlist */ unsigned char da_ranges; /* copy of D/A outpit range register */ - unsigned short ao_data[4]; /* data output buffer */ unsigned int cnt0_write_wait; /* after a write, wait for update of the * internal state */ }; -/* used for gain list programming */ -static const unsigned int muxonechan[] = { - 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, - 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, - 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, - 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f -}; - -static int pci171x_ai_dropout(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int chan, - unsigned int val) -{ - const struct boardtype *board = dev->board_ptr; - struct pci1710_private *devpriv = dev->private; - - if (board->cardtype != TYPE_PCI1713) { - if ((val & 0xf000) != devpriv->act_chanlist[chan]) { - dev_err(dev->class_dev, - "A/D data droput: received from channel %d, expected %d\n", - (val >> 12) & 0xf, - (devpriv->act_chanlist[chan] >> 12) & 0xf); - return -ENODATA; - } - } - return 0; -} - static int pci171x_ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -407,33 +342,39 @@ static int pci171x_ai_check_chanlist(struct comedi_device *dev, return 0; } -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) +static void pci171x_ai_setup_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chanlist, + unsigned int n_chan, + unsigned int seglen) { - const struct boardtype *this_board = dev->board_ptr; + const struct boardtype *board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; - unsigned int i, range, chanprog; + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]); + unsigned int i; for (i = 0; i < seglen; i++) { /* store range list to card */ - chanprog = muxonechan[CR_CHAN(chanlist[i])]; - outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ - range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; - if (CR_AREF(chanlist[i]) == AREF_DIFF) - range |= 0x0020; - outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ - devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; - } - for ( ; i < n_chan; i++) { /* store remainder of channel list */ - devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; + unsigned int chan = CR_CHAN(chanlist[i]); + unsigned int range = CR_RANGE(chanlist[i]); + unsigned int aref = CR_AREF(chanlist[i]); + unsigned int rangeval; + + rangeval = board->rangecode_ai[range]; + if (aref == AREF_DIFF) + rangeval |= 0x0020; + + /* select channel and set range */ + outw(chan | (chan << 8), dev->iobase + PCI171x_MUX); + outw(rangeval, dev->iobase + PCI171x_RANGE); + + devpriv->act_chanlist[i] = chan; } + for ( ; i < n_chan; i++) /* store remainder of channel list */ + devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); - devpriv->ai_et_MuxVal = - CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); /* select channel interval to scan */ + devpriv->ai_et_MuxVal = first_chan | (last_chan << 8); outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); } @@ -450,9 +391,39 @@ static int pci171x_ai_eoc(struct comedi_device *dev, return -EBUSY; } -static int pci171x_insn_read_ai(struct comedi_device *dev, +static int pci171x_ai_read_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int cur_chan, + unsigned int *val) +{ + const struct boardtype *board = dev->board_ptr; + struct pci1710_private *devpriv = dev->private; + unsigned int sample; + unsigned int chan; + + sample = inw(dev->iobase + PCI171x_AD_DATA); + if (!board->is_pci1713) { + /* + * The upper 4 bits of the 16-bit sample are the channel number + * that the sample was acquired from. Verify that this channel + * number matches the expected channel number. + */ + chan = sample >> 12; + if (chan != devpriv->act_chanlist[cur_chan]) { + dev_err(dev->class_dev, + "A/D data droput: received from channel %d, expected %d\n", + chan, devpriv->act_chanlist[cur_chan]); + return -ENODATA; + } + } + *val = sample & s->maxdata; + return 0; +} + +static int pci171x_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct pci1710_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); @@ -465,7 +436,7 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - setup_channel_list(dev, s, &insn->chanspec, 1, 1); + pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1); for (i = 0; i < insn->n; i++) { unsigned int val; @@ -476,12 +447,11 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, if (ret) break; - val = inw(dev->iobase + PCI171x_AD_DATA); - ret = pci171x_ai_dropout(dev, s, chan, val); + ret = pci171x_ai_read_sample(dev, s, chan, &val); if (ret) break; - data[i] = val & s->maxdata; + data[i] = val; } outb(0, dev->iobase + PCI171x_CLRFIFO); @@ -490,73 +460,43 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, return ret ? ret : insn->n; } -/* -============================================================================== -*/ -static int pci171x_insn_write_ao(struct comedi_device *dev, +static int pci171x_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 pci1710_private *devpriv = dev->private; - unsigned int val; - int n, chan, range, ofs; - - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - if (chan) { - devpriv->da_ranges &= 0xfb; - devpriv->da_ranges |= (range << 2); - outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); - ofs = PCI171x_DA2; - } else { - devpriv->da_ranges &= 0xfe; - devpriv->da_ranges |= range; - outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); - ofs = PCI171x_DA1; - } - val = devpriv->ao_data[chan]; - - for (n = 0; n < insn->n; n++) { - val = data[n]; - outw(val, dev->iobase + ofs); - } - - devpriv->ao_data[chan] = val; - - return n; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1; + unsigned int val = s->readback[chan]; + int i; -} + devpriv->da_ranges &= ~(1 << (chan << 1)); + devpriv->da_ranges |= (range << (chan << 1)); + outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); -/* -============================================================================== -*/ -static int pci171x_insn_read_ao(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pci1710_private *devpriv = dev->private; - int n, chan; + for (i = 0; i < insn->n; i++) { + val = data[i]; + outw(val, dev->iobase + reg); + } - chan = CR_CHAN(insn->chanspec); - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_data[chan]; + s->readback[chan] = val; - return n; + return insn->n; } -/* -============================================================================== -*/ -static int pci171x_insn_bits_di(struct comedi_device *dev, +static int pci171x_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { data[1] = inw(dev->iobase + PCI171x_DI); return insn->n; } -static int pci171x_insn_bits_do(struct comedi_device *dev, +static int pci171x_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -584,10 +524,7 @@ static void pci171x_start_pacer(struct comedi_device *dev, } } -/* -============================================================================== -*/ -static int pci171x_insn_counter_read(struct comedi_device *dev, +static int pci171x_counter_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -608,10 +545,7 @@ static int pci171x_insn_counter_read(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ -static int pci171x_insn_counter_write(struct comedi_device *dev, +static int pci171x_counter_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -638,10 +572,7 @@ static int pci171x_insn_counter_write(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ -static int pci171x_insn_counter_config(struct comedi_device *dev, +static int pci171x_counter_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -677,57 +608,48 @@ static int pci171x_insn_counter_config(struct comedi_device *dev, return 1; } -/* -============================================================================== -*/ -static int pci1720_insn_write_ao(struct comedi_device *dev, +static int pci1720_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 pci1710_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned int val; - int n, rangereg, chan; - - chan = CR_CHAN(insn->chanspec); - rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1))); - rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1)); - if (rangereg != devpriv->da_ranges) { - outb(rangereg, dev->iobase + PCI1720_RANGE); - devpriv->da_ranges = rangereg; + int i; + + val = devpriv->da_ranges & (~(0x03 << (chan << 1))); + val |= (range << (chan << 1)); + if (val != devpriv->da_ranges) { + outb(val, dev->iobase + PCI1720_RANGE); + devpriv->da_ranges = val; } - val = devpriv->ao_data[chan]; - for (n = 0; n < insn->n; n++) { - val = data[n]; + val = s->readback[chan]; + for (i = 0; i < insn->n; i++) { + val = data[i]; outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); - outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ + outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ } - devpriv->ao_data[chan] = val; + s->readback[chan] = val; - return n; + return insn->n; } -/* -============================================================================== -*/ static int pci171x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct boardtype *this_board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; - switch (this_board->cardtype) { - default: - devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; - /* reset any operations */ - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - pci171x_start_pacer(dev, false); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - break; - } + devpriv->CntrlReg &= Control_CNT0; + devpriv->CntrlReg |= Control_SW; + /* reset any operations */ + outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); + pci171x_start_pacer(dev, false); + outb(0, dev->iobase + PCI171x_CLRFIFO); + outb(0, dev->iobase + PCI171x_CLRINT); return 0; } @@ -743,29 +665,25 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, status = inw(dev->iobase + PCI171x_STATUS); if (status & Status_FE) { dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_handle_events(dev, s); + s->async->events |= COMEDI_CB_ERROR; return; } if (status & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_handle_events(dev, s); + s->async->events |= COMEDI_CB_ERROR; return; } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { - val = inw(dev->iobase + PCI171x_AD_DATA); - ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); + ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val); if (ret) { - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + s->async->events |= COMEDI_CB_ERROR; break; } - val &= s->maxdata; comedi_buf_write_samples(s, &val, 1); if (cmd->stop_src == TRIG_COUNT && @@ -776,85 +694,53 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - - comedi_handle_events(dev, s); -} - -/* -============================================================================== -*/ -static int move_block_from_fifo(struct comedi_device *dev, - struct comedi_subdevice *s, int n, int turn) -{ - unsigned int val; - int ret; - int i; - - for (i = 0; i < n; i++) { - val = inw(dev->iobase + PCI171x_AD_DATA); - - ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); - if (ret) { - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - return ret; - } - - val &= s->maxdata; - comedi_buf_write_samples(s, &val, 1); - } - return 0; } static void pci1710_handle_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct boardtype *this_board = dev->board_ptr; - struct comedi_cmd *cmd = &s->async->cmd; - unsigned int nsamples; - unsigned int m; - - m = inw(dev->iobase + PCI171x_STATUS); - if (!(m & Status_FH)) { - dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_handle_events(dev, s); + struct pci1710_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int status; + int i; + + status = inw(dev->iobase + PCI171x_STATUS); + if (!(status & Status_FH)) { + dev_dbg(dev->class_dev, "A/D FIFO not half full!\n"); + async->events |= COMEDI_CB_ERROR; return; } - if (m & Status_FF) { + if (status & Status_FF) { dev_dbg(dev->class_dev, - "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_handle_events(dev, s); + "A/D FIFO Full status (Fatal Error!)\n"); + async->events |= COMEDI_CB_ERROR; return; } - nsamples = this_board->fifo_half_size; - if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) { - m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz); - if (move_block_from_fifo(dev, s, m, 0)) - return; - nsamples -= m; - } + for (i = 0; i < devpriv->max_samples; i++) { + unsigned int val; + int ret; - if (nsamples) { - if (move_block_from_fifo(dev, s, nsamples, 1)) - return; - } + ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val); + if (ret) { + s->async->events |= COMEDI_CB_ERROR; + break; + } - if (cmd->stop_src == TRIG_COUNT && - s->async->scans_done >= cmd->stop_arg) { - s->async->events |= COMEDI_CB_EOA; - comedi_handle_events(dev, s); - return; + if (!comedi_buf_write_samples(s, &val, 1)) + break; + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { + async->events |= COMEDI_CB_EOA; + break; + } } - outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - comedi_handle_events(dev, s); + outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ } -/* -============================================================================== -*/ static irqreturn_t interrupt_service_pci1710(int irq, void *d) { struct comedi_device *dev = d; @@ -891,6 +777,8 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) else pci1710_handle_fifo(dev, s); + comedi_handle_events(dev, s); + return IRQ_HANDLED; } @@ -901,8 +789,8 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) pci171x_start_pacer(dev, false); - setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len, - devpriv->saved_seglen); + pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, + devpriv->saved_seglen); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); @@ -937,14 +825,10 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* -============================================================================== -*/ static int pci171x_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct boardtype *this_board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -977,8 +861,7 @@ static int pci171x_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, - this_board->ai_ns_min); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); else /* TRIG_FOLLOW */ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); @@ -1016,12 +899,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ static int pci171x_reset(struct comedi_device *dev) { - const struct boardtype *this_board = dev->board_ptr; + const struct boardtype *board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; outw(0x30, dev->iobase + PCI171x_CNTCTRL); @@ -1033,15 +913,11 @@ static int pci171x_reset(struct comedi_device *dev) outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ pci171x_start_pacer(dev, false); devpriv->da_ranges = 0; - if (this_board->n_aochan) { + if (board->has_ao) { /* set DACs to 0..5V */ outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */ - devpriv->ao_data[0] = 0x0000; - if (this_board->n_aochan > 1) { - outw(0, dev->iobase + PCI171x_DA2); - devpriv->ao_data[1] = 0x0000; - } + outw(0, dev->iobase + PCI171x_DA2); } outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */ outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ @@ -1050,9 +926,6 @@ static int pci171x_reset(struct comedi_device *dev) return 0; } -/* -============================================================================== -*/ static int pci1720_reset(struct comedi_device *dev) { struct pci1710_private *devpriv = dev->private; @@ -1066,43 +939,35 @@ static int pci1720_reset(struct comedi_device *dev) outw(0x0800, dev->iobase + PCI1720_DA2); outw(0x0800, dev->iobase + PCI1720_DA3); outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ - devpriv->ao_data[0] = 0x0800; - devpriv->ao_data[1] = 0x0800; - devpriv->ao_data[2] = 0x0800; - devpriv->ao_data[3] = 0x0800; + return 0; } -/* -============================================================================== -*/ static int pci1710_reset(struct comedi_device *dev) { - const struct boardtype *this_board = dev->board_ptr; + const struct boardtype *board = dev->board_ptr; - switch (this_board->cardtype) { - case TYPE_PCI1720: + if (board->is_pci1720) return pci1720_reset(dev); - default: - return pci171x_reset(dev); - } + + return pci171x_reset(dev); } static int pci1710_auto_attach(struct comedi_device *dev, unsigned long context) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct boardtype *this_board = NULL; + const struct boardtype *board = NULL; struct pci1710_private *devpriv; struct comedi_subdevice *s; int ret, subdev, n_subdevices; if (context < ARRAY_SIZE(boardtypes)) - this_board = &boardtypes[context]; - if (!this_board) + board = &boardtypes[context]; + if (!board) return -ENODEV; - dev->board_ptr = this_board; - dev->board_name = this_board->name; + dev->board_ptr = board; + dev->board_name = board->name; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -1114,15 +979,13 @@ static int pci1710_auto_attach(struct comedi_device *dev, dev->iobase = pci_resource_start(pcidev, 2); n_subdevices = 0; - if (this_board->n_aichan) - n_subdevices++; - if (this_board->n_aochan) - n_subdevices++; - if (this_board->n_dichan) + if (board->n_aichan) n_subdevices++; - if (this_board->n_dochan) + if (board->has_ao) n_subdevices++; - if (this_board->n_counter) + if (board->has_di_do) + n_subdevices += 2; + if (board->has_counter) n_subdevices++; ret = comedi_alloc_subdevices(dev, n_subdevices); @@ -1131,7 +994,7 @@ static int pci1710_auto_attach(struct comedi_device *dev, pci1710_reset(dev); - if (this_board->have_irq && pcidev->irq) { + if (board->has_irq && pcidev->irq) { ret = request_irq(pcidev->irq, interrupt_service_pci1710, IRQF_SHARED, dev->board_name, dev); if (ret == 0) @@ -1140,85 +1003,93 @@ static int pci1710_auto_attach(struct comedi_device *dev, subdev = 0; - if (this_board->n_aichan) { + if (board->n_aichan) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; - if (this_board->n_aichand) - s->subdev_flags |= SDF_DIFF; - s->n_chan = this_board->n_aichan; - s->maxdata = this_board->ai_maxdata; - s->range_table = this_board->rangelist_ai; - s->insn_read = pci171x_insn_read_ai; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; + if (board->has_diff_ai) + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan; + s->maxdata = 0x0fff; + s->range_table = board->rangelist_ai; + s->insn_read = pci171x_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 = pci171x_ai_cmdtest; - s->do_cmd = pci171x_ai_cmd; - s->cancel = pci171x_ai_cancel; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = pci171x_ai_cmdtest; + s->do_cmd = pci171x_ai_cmd; + s->cancel = pci171x_ai_cancel; } subdev++; } - if (this_board->n_aochan) { + if (board->has_ao) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_aochan; - s->maxdata = this_board->ao_maxdata; - s->len_chanlist = this_board->n_aochan; - s->range_table = this_board->rangelist_ao; - switch (this_board->cardtype) { - case TYPE_PCI1720: - s->insn_write = pci1720_insn_write_ao; - break; - default: - s->insn_write = pci171x_insn_write_ao; - break; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->maxdata = 0x0fff; + if (board->is_pci1720) { + s->n_chan = 4; + s->range_table = &pci1720_ao_range; + s->insn_write = pci1720_ao_insn_write; + } else { + s->n_chan = 2; + s->range_table = &pci171x_ao_range; + s->insn_write = pci171x_ao_insn_write; } - s->insn_read = pci171x_insn_read_ao; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + /* initialize the readback values to match the board reset */ + if (board->is_pci1720) { + int i; + + for (i = 0; i < s->n_chan; i++) + s->readback[i] = 0x0800; + } + subdev++; } - if (this_board->n_dichan) { + if (board->has_di_do) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = this_board->n_dichan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dichan; - s->range_table = &range_digital; - s->insn_bits = pci171x_insn_bits_di; + 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 = pci171x_di_insn_bits; subdev++; - } - if (this_board->n_dochan) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = this_board->n_dochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dochan; - s->range_table = &range_digital; - s->insn_bits = pci171x_insn_bits_do; + 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 = pci171x_do_insn_bits; subdev++; } - if (this_board->n_counter) { + if (board->has_counter) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = this_board->n_counter; - s->len_chanlist = this_board->n_counter; - s->maxdata = 0xffff; - s->range_table = &range_unknown; - s->insn_read = pci171x_insn_counter_read; - s->insn_write = pci171x_insn_counter_write; - s->insn_config = pci171x_insn_counter_config; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 1; + s->maxdata = 0xffff; + s->range_table = &range_unknown; + s->insn_read = pci171x_counter_insn_read; + s->insn_write = pci171x_counter_insn_write; + s->insn_config = pci171x_counter_insn_config; subdev++; } + /* max_samples is half the FIFO size (2 bytes/sample) */ + devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512; + return 0; } @@ -1312,5 +1183,5 @@ static struct pci_driver adv_pci1710_pci_driver = { module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 65f854e1eb66..f1945be89eff 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -20,7 +20,7 @@ * Driver: adv_pci1723 * Description: Advantech PCI-1723 * Author: yonggang <rsmgnu@gmail.com>, Ian Abbott <abbotti@mev.co.uk> - * Devices: (Advantech) PCI-1723 [adv_pci1723] + * Devices: [Advantech] PCI-1723 (adv_pci1723) * Updated: Mon, 14 Apr 2008 15:12:56 +0100 * Status: works * diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c index a8d28403262e..a3573ea6f9c0 100644 --- a/drivers/staging/comedi/drivers/adv_pci1724.c +++ b/drivers/staging/comedi/drivers/adv_pci1724.c @@ -22,7 +22,7 @@ /* * Driver: adv_pci1724 * Description: Advantech PCI-1724U - * Devices: (Advantech) PCI-1724U [adv_pci1724] + * Devices: [Advantech] PCI-1724U (adv_pci1724) * Author: Frank Mori Hess <fmh6jj@gmail.com> * Updated: 2013-02-09 * Status: works diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 7b5ed439c164..1c7b325a373c 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -1,48 +1,155 @@ /* + * aio_iiro_16.c + * Comedi driver for Access I/O Products 104-IIRO-16 board + * Copyright (C) 2006 C&C Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ - comedi/drivers/aio_iiro_16.c +/* + * Driver: aio_iiro_16 + * Description: Access I/O Products PC/104 Isolated Input/Relay Output Board + * Author: Zachary Ware <zach.ware@cctechnol.com> + * Devices: [Access I/O] 104-IIRO-16 (aio_iiro_16) + * Status: experimental + * + * Configuration Options: + * [0] - I/O port base address + * [1] - IRQ (optional) + * + * The board supports interrupts on change of state of the digital inputs. + * The sample data returned by the async command indicates which inputs + * changed state and the current state of the inputs: + * + * Bit 23 - IRQ Enable (1) / Disable (0) + * Bit 17 - Input 8-15 Changed State (1 = Changed, 0 = No Change) + * Bit 16 - Input 0-7 Changed State (1 = Changed, 0 = No Change) + * Bit 15 - Digital input 15 + * ... + * Bit 0 - Digital input 0 + */ - Driver for Access I/O Products PC-104 AIO-IIRO-16 Digital I/O board - Copyright (C) 2006 C&C Technologies, Inc. +#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" - 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 "comedi_fc.h" -/* +#define AIO_IIRO_16_RELAY_0_7 0x00 +#define AIO_IIRO_16_INPUT_0_7 0x01 +#define AIO_IIRO_16_IRQ 0x02 +#define AIO_IIRO_16_RELAY_8_15 0x04 +#define AIO_IIRO_16_INPUT_8_15 0x05 +#define AIO_IIRO_16_STATUS 0x07 +#define AIO_IIRO_16_STATUS_IRQE BIT(7) +#define AIO_IIRO_16_STATUS_INPUT_8_15 BIT(1) +#define AIO_IIRO_16_STATUS_INPUT_0_7 BIT(0) -Driver: aio_iiro_16 -Description: Access I/O Products PC-104 IIRO16 Relay And Isolated Input Board -Author: Zachary Ware <zach.ware@cctechnol.com> -Devices: - [Access I/O] PC-104 AIO12-8 -Status: experimental +static unsigned int aio_iiro_16_read_inputs(struct comedi_device *dev) +{ + unsigned int val; -Configuration Options: - [0] - I/O port base address + val = inb(dev->iobase + AIO_IIRO_16_INPUT_0_7); + val |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8; -*/ + return val; +} -#include <linux/module.h> -#include "../comedidev.h" +static irqreturn_t aio_iiro_16_cos(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int status; + unsigned int val; + + status = inb(dev->iobase + AIO_IIRO_16_STATUS); + if (!(status & AIO_IIRO_16_STATUS_IRQE)) + return IRQ_NONE; + + val = aio_iiro_16_read_inputs(dev); + val |= (status << 16); + + comedi_buf_write_samples(s, &val, 1); + comedi_handle_events(dev, s); + + return IRQ_HANDLED; +} + +static void aio_iiro_enable_irq(struct comedi_device *dev, bool enable) +{ + if (enable) + inb(dev->iobase + AIO_IIRO_16_IRQ); + else + outb(0, dev->iobase + AIO_IIRO_16_IRQ); +} + +static int aio_iiro_16_cos_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + aio_iiro_enable_irq(dev, false); + + return 0; +} -#define AIO_IIRO_16_RELAY_0_7 0x00 -#define AIO_IIRO_16_INPUT_0_7 0x01 -#define AIO_IIRO_16_IRQ 0x02 -#define AIO_IIRO_16_RELAY_8_15 0x04 -#define AIO_IIRO_16_INPUT_8_15 0x05 +static int aio_iiro_16_cos_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + aio_iiro_enable_irq(dev, true); + + return 0; +} + +static int aio_iiro_16_cos_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ + + /* Step 3: check if arguments are trivially valid */ -static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* Step 4: fix up any arguments */ + + /* Step 5: check channel list if it exists */ + + return 0; +} + +static int aio_iiro_16_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 + AIO_IIRO_16_RELAY_0_7); @@ -55,14 +162,12 @@ static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, return insn->n; } -static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int aio_iiro_16_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - data[1] = 0; - data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7); - data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8; + data[1] = aio_iiro_16_read_inputs(dev); return insn->n; } @@ -77,25 +182,52 @@ static int aio_iiro_16_attach(struct comedi_device *dev, if (ret) return ret; + aio_iiro_enable_irq(dev, false); + + /* + * Digital input change of state interrupts are optionally supported + * using IRQ 2-7, 10-12, 14, or 15. + */ + if ((1 << it->options[1]) & 0xdcfc) { + ret = request_irq(it->options[1], aio_iiro_16_cos, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; + } + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; + /* Digital Output subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = aio_iiro_16_dio_insn_bits_write; - + 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 = aio_iiro_16_do_insn_bits; + + /* get the initial state of the relays */ + s->state = inb(dev->iobase + AIO_IIRO_16_RELAY_0_7) | + (inb(dev->iobase + AIO_IIRO_16_RELAY_8_15) << 8); + + /* Digital Input subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = aio_iiro_16_dio_insn_bits_read; + 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 = aio_iiro_16_di_insn_bits; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL; + s->len_chanlist = 1; + s->do_cmdtest = aio_iiro_16_cos_cmdtest; + s->do_cmd = aio_iiro_16_cos_cmd; + s->cancel = aio_iiro_16_cos_cancel; + } return 0; } @@ -109,5 +241,5 @@ static struct comedi_driver aio_iiro_16_driver = { module_comedi_driver(aio_iiro_16_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Access I/O Products 104-IIRO-16 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index e7cb7032a910..1a109e30d8ff 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -22,7 +22,7 @@ * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card * Author: Dan Block * Status: unknown - * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio] + * Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio) * Updated: Sun Nov 20 20:18:34 EST 2005 * * Configuration Options: diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 0a48d2a961d5..1079b6c72b15 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -38,10 +38,7 @@ Status: experimental #include <linux/interrupt.h> #include <linux/delay.h> -#include "../comedidev.h" - -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> +#include "../comedi_pcmcia.h" #include "comedi_fc.h" #include "8253.h" diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 669b1703eb99..dd0c65a5b5a0 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -1355,7 +1355,7 @@ 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); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + async->events |= COMEDI_CB_ERROR; } comedi_handle_events(dev, s); diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index eddb7ace43df..5b43e4e6d037 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -439,6 +439,29 @@ static const struct comedi_lrange ai_ranges_64xx = { } }; +static const uint8_t ai_range_code_64xx[8] = { + 0x0, 0x1, 0x2, 0x3, /* bipolar 10, 5, 2,5, 1.25 */ + 0x8, 0x9, 0xa, 0xb /* unipolar 10, 5, 2.5, 1.25 */ +}; + +/* analog input ranges for 64-Mx boards */ +static const struct comedi_lrange ai_ranges_64_mx = { + 7, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } +}; + +static const uint8_t ai_range_code_64_mx[7] = { + 0x0, 0x1, 0x2, 0x3, /* bipolar 5, 2.5, 1.25, 0.625 */ + 0x9, 0xa, 0xb /* unipolar 5, 2.5, 1.25 */ +}; + /* analog input ranges for 60xx boards */ static const struct comedi_lrange ai_ranges_60xx = { 4, { @@ -449,6 +472,10 @@ static const struct comedi_lrange ai_ranges_60xx = { } }; +static const uint8_t ai_range_code_60xx[4] = { + 0x0, 0x1, 0x4, 0x7 /* bipolar 10, 5, 0.5, 0.05 */ +}; + /* analog input ranges for 6030, etc boards */ static const struct comedi_lrange ai_ranges_6030 = { 14, { @@ -469,6 +496,11 @@ static const struct comedi_lrange ai_ranges_6030 = { } }; +static const uint8_t ai_range_code_6030[14] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, /* bip 10, 5, 2, 1, 0.5, 0.2, 0.1 */ + 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* uni 10, 5, 2, 1, 0.5, 0.2, 0.1 */ +}; + /* analog input ranges for 6052, etc boards */ static const struct comedi_lrange ai_ranges_6052 = { 15, { @@ -490,6 +522,11 @@ static const struct comedi_lrange ai_ranges_6052 = { } }; +static const uint8_t ai_range_code_6052[15] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, /* bipolar 10 ... 0.05 */ + 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* unipolar 10 ... 0.1 */ +}; + /* analog input ranges for 4020 board */ static const struct comedi_lrange ai_ranges_4020 = { 2, { @@ -593,6 +630,7 @@ struct pcidas64_board { int ai_bits; /* analog input resolution */ int ai_speed; /* fastest conversion period in ns */ const struct comedi_lrange *ai_range_table; + const uint8_t *ai_range_code; int ao_nchan; /* number of analog out channels */ int ao_bits; /* analog output resolution */ int ao_scan_speed; /* analog output scan speed */ @@ -651,6 +689,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_64XX, .ai_range_table = &ai_ranges_64xx, + .ai_range_code = ai_range_code_64xx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -666,6 +705,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_64XX, .ai_range_table = &ai_ranges_64xx, + .ai_range_code = ai_range_code_64xx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -680,7 +720,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -695,7 +736,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -710,7 +752,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -725,6 +768,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -740,6 +784,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -754,6 +799,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -769,6 +815,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -784,6 +831,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -799,6 +847,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -812,6 +861,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ai_fifo = &ai_fifo_60xx, .has_8255 = 0, }, @@ -823,6 +873,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ai_fifo = &ai_fifo_60xx, .has_8255 = 0, }, @@ -835,6 +886,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 0, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ai_fifo = &ai_fifo_60xx, .has_8255 = 0, }, @@ -848,6 +900,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -863,6 +916,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -878,6 +932,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 1000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -893,6 +948,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 3333, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -908,6 +964,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 1000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -923,6 +980,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 1000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -957,6 +1015,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_64XX, .ai_range_table = &ai_ranges_64xx, + .ai_range_code = ai_range_code_64xx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -968,7 +1027,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -980,7 +1040,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -992,7 +1053,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1004,7 +1066,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 2, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1016,7 +1079,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 2, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1028,7 +1092,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 2, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1115,45 +1180,8 @@ static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, unsigned int range_index) { const struct pcidas64_board *thisboard = dev->board_ptr; - const struct comedi_krange *range = - &thisboard->ai_range_table->range[range_index]; - unsigned int bits = 0; - switch (range->max) { - case 10000000: - bits = 0x000; - break; - case 5000000: - bits = 0x100; - break; - case 2000000: - case 2500000: - bits = 0x200; - break; - case 1000000: - case 1250000: - bits = 0x300; - break; - case 500000: - bits = 0x400; - break; - case 200000: - case 250000: - bits = 0x500; - break; - case 100000: - bits = 0x600; - break; - case 50000: - bits = 0x700; - break; - default: - dev_err(dev->class_dev, "bug! in %s\n", __func__); - break; - } - if (range->min == 0) - bits += 0x900; - return bits; + return thisboard->ai_range_code[range_index] << 8; } static unsigned int hw_revision(const struct comedi_device *dev, @@ -2776,7 +2804,7 @@ static void handle_ai_interrupt(struct comedi_device *dev, /* check for fifo overrun */ if (status & ADC_OVERRUN_BIT) { dev_err(dev->class_dev, "fifo overrun\n"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + async->events |= COMEDI_CB_ERROR; } /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 01875d7c376f..2b2cfcdda5bd 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -22,12 +22,10 @@ /* * Driver: cb_pcidda * Description: MeasurementComputing PCI-DDA series - * Devices: (Measurement Computing) PCI-DDA08/12 [pci-dda08/12] - * (Measurement Computing) PCI-DDA04/12 [pci-dda04/12] - * (Measurement Computing) PCI-DDA02/12 [pci-dda02/12] - * (Measurement Computing) PCI-DDA08/16 [pci-dda08/16] - * (Measurement Computing) PCI-DDA04/16 [pci-dda04/16] - * (Measurement Computing) PCI-DDA02/16 [pci-dda02/16] + * Devices: [Measurement Computing] PCI-DDA08/12 (pci-dda08/12), + * PCI-DDA04/12 (pci-dda04/12), PCI-DDA02/12 (pci-dda02/12), + * PCI-DDA08/16 (pci-dda08/16), PCI-DDA04/16 (pci-dda04/16), + * PCI-DDA02/16 (pci-dda02/16) * Author: Ivan Martinez <ivanmr@altavista.com> * Frank Mori Hess <fmhess@users.sourceforge.net> * Status: works diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 85b2f4ab1ba4..221d3819c967 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -261,6 +261,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) { /* Append dev:subdev to devpriv->name */ char buf[20]; + snprintf(buf, sizeof(buf), "%u:%u ", bdev->minor, bdev->subdev); strlcat(devpriv->name, buf, diff --git a/drivers/staging/comedi/drivers/comedi_isadma.c b/drivers/staging/comedi/drivers/comedi_isadma.c new file mode 100644 index 000000000000..dbdea71d6b95 --- /dev/null +++ b/drivers/staging/comedi/drivers/comedi_isadma.c @@ -0,0 +1,262 @@ +/* + * COMEDI ISA DMA support functions + * Copyright (c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <asm/dma.h> + +#include "../comedidev.h" + +#include "comedi_isadma.h" + +/** + * comedi_isadma_program - program and enable an ISA DMA transfer + * @desc: the ISA DMA cookie to program and enable + */ +void comedi_isadma_program(struct comedi_isadma_desc *desc) +{ + unsigned long flags; + + flags = claim_dma_lock(); + clear_dma_ff(desc->chan); + set_dma_mode(desc->chan, desc->mode); + set_dma_addr(desc->chan, desc->hw_addr); + set_dma_count(desc->chan, desc->size); + enable_dma(desc->chan); + release_dma_lock(flags); +} +EXPORT_SYMBOL_GPL(comedi_isadma_program); + +/** + * comedi_isadma_disable - disable the ISA DMA channel + * @dma_chan: the DMA channel to disable + * + * Returns the residue (remaining bytes) left in the DMA transfer. + */ +unsigned int comedi_isadma_disable(unsigned int dma_chan) +{ + unsigned long flags; + unsigned int residue; + + flags = claim_dma_lock(); + disable_dma(dma_chan); + residue = get_dma_residue(dma_chan); + release_dma_lock(flags); + + return residue; +} +EXPORT_SYMBOL_GPL(comedi_isadma_disable); + +/** + * comedi_isadma_disable_on_sample - disable the ISA DMA channel + * @dma_chan: the DMA channel to disable + * @size: the sample size (in bytes) + * + * Returns the residue (remaining bytes) left in the DMA transfer. + */ +unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan, + unsigned int size) +{ + int stalled = 0; + unsigned long flags; + unsigned int residue; + unsigned int new_residue; + + residue = comedi_isadma_disable(dma_chan); + while (residue % size) { + /* residue is a partial sample, enable DMA to allow more data */ + flags = claim_dma_lock(); + enable_dma(dma_chan); + release_dma_lock(flags); + + udelay(2); + new_residue = comedi_isadma_disable(dma_chan); + + /* is DMA stalled? */ + if (new_residue == residue) { + stalled++; + if (stalled > 10) + break; + } + residue = new_residue; + stalled = 0; + } + return residue; +} +EXPORT_SYMBOL_GPL(comedi_isadma_disable_on_sample); + +/** + * comedi_isadma_poll - poll the current DMA transfer + * @dma: the ISA DMA to poll + * + * Returns the position (in bytes) of the current DMA transfer. + */ +unsigned int comedi_isadma_poll(struct comedi_isadma *dma) +{ + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned long flags; + unsigned int result; + unsigned int result1; + + flags = claim_dma_lock(); + clear_dma_ff(desc->chan); + if (!isa_dma_bridge_buggy) + disable_dma(desc->chan); + result = get_dma_residue(desc->chan); + /* + * Read the counter again and choose higher value in order to + * avoid reading during counter lower byte roll over if the + * isa_dma_bridge_buggy is set. + */ + result1 = get_dma_residue(desc->chan); + if (!isa_dma_bridge_buggy) + enable_dma(desc->chan); + release_dma_lock(flags); + + if (result < result1) + result = result1; + if (result >= desc->size || result == 0) + return 0; + else + return desc->size - result; +} +EXPORT_SYMBOL_GPL(comedi_isadma_poll); + +/** + * comedi_isadma_set_mode - set the ISA DMA transfer direction + * @desc: the ISA DMA cookie to set + * @dma_dir: the DMA direction + */ +void comedi_isadma_set_mode(struct comedi_isadma_desc *desc, char dma_dir) +{ + desc->mode = (dma_dir == COMEDI_ISADMA_READ) ? DMA_MODE_READ + : DMA_MODE_WRITE; +} +EXPORT_SYMBOL_GPL(comedi_isadma_set_mode); + +/** + * comedi_isadma_alloc - allocate and initialize the ISA DMA + * @dev: comedi_device struct + * @n_desc: the number of cookies to allocate + * @dma_chan: DMA channel for the first cookie + * @dma_chan2: DMA channel for the second cookie + * @maxsize: the size of the buffer to allocate for each cookie + * @dma_dir: the DMA direction + * + * Returns the allocated and initialized ISA DMA or NULL if anything fails. + */ +struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev, + int n_desc, unsigned int dma_chan1, + unsigned int dma_chan2, + unsigned int maxsize, char dma_dir) +{ + struct comedi_isadma *dma = NULL; + struct comedi_isadma_desc *desc; + unsigned int dma_chans[2]; + int i; + + if (n_desc < 1 || n_desc > 2) + goto no_dma; + + dma = kzalloc(sizeof(*dma), GFP_KERNEL); + if (!dma) + goto no_dma; + + desc = kcalloc(n_desc, sizeof(*desc), GFP_KERNEL); + if (!desc) + goto no_dma; + dma->desc = desc; + dma->n_desc = n_desc; + + dma_chans[0] = dma_chan1; + if (dma_chan2 == 0 || dma_chan2 == dma_chan1) + dma_chans[1] = dma_chan1; + else + dma_chans[1] = dma_chan2; + + if (request_dma(dma_chans[0], dev->board_name)) + goto no_dma; + dma->chan = dma_chans[0]; + if (dma_chans[1] != dma_chans[0]) { + if (request_dma(dma_chans[1], dev->board_name)) + goto no_dma; + } + dma->chan2 = dma_chans[1]; + + for (i = 0; i < n_desc; i++) { + desc = &dma->desc[i]; + desc->chan = dma_chans[i]; + desc->maxsize = maxsize; + desc->virt_addr = dma_alloc_coherent(NULL, desc->maxsize, + &desc->hw_addr, + GFP_KERNEL); + if (!desc->virt_addr) + goto no_dma; + comedi_isadma_set_mode(desc, dma_dir); + } + + return dma; + +no_dma: + comedi_isadma_free(dma); + return NULL; +} +EXPORT_SYMBOL_GPL(comedi_isadma_alloc); + +/** + * comedi_isadma_free - free the ISA DMA + * @dma: the ISA DMA to free + */ +void comedi_isadma_free(struct comedi_isadma *dma) +{ + struct comedi_isadma_desc *desc; + int i; + + if (!dma) + return; + + if (dma->desc) { + for (i = 0; i < dma->n_desc; i++) { + desc = &dma->desc[i]; + if (desc->virt_addr) + dma_free_coherent(NULL, desc->maxsize, + desc->virt_addr, desc->hw_addr); + } + kfree(dma->desc); + } + if (dma->chan2 && dma->chan2 != dma->chan) + free_dma(dma->chan2); + if (dma->chan) + free_dma(dma->chan); + kfree(dma); +} +EXPORT_SYMBOL_GPL(comedi_isadma_free); + +static int __init comedi_isadma_init(void) +{ + return 0; +} +module_init(comedi_isadma_init); + +static void __exit comedi_isadma_exit(void) +{ +} +module_exit(comedi_isadma_exit); + +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("Comedi ISA DMA support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_isadma.h b/drivers/staging/comedi/drivers/comedi_isadma.h new file mode 100644 index 000000000000..c7c524faf595 --- /dev/null +++ b/drivers/staging/comedi/drivers/comedi_isadma.h @@ -0,0 +1,116 @@ +/* + * COMEDI ISA DMA support functions + * Copyright (c) 2014 H Hartley Sweeten <hsweeten@visionengravers.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. + */ + +#ifndef _COMEDI_ISADMA_H +#define _COMEDI_ISADMA_H + +/* + * These are used to avoid issues when <asm/dma.h> and the DMA_MODE_ + * defines are not available. + */ +#define COMEDI_ISADMA_READ 0 +#define COMEDI_ISADMA_WRITE 1 + +/** + * struct comedi_isadma_desc - cookie for ISA DMA + * @virt_addr: virtual address of buffer + * @hw_addr: hardware (bus) address of buffer + * @chan: DMA channel + * @maxsize: allocated size of buffer (in bytes) + * @size: transfer size (in bytes) + * @mode: DMA_MODE_READ or DMA_MODE_WRITE + */ +struct comedi_isadma_desc { + void *virt_addr; + dma_addr_t hw_addr; + unsigned int chan; + unsigned int maxsize; + unsigned int size; + char mode; +}; + +/** + * struct comedi_isadma - ISA DMA data + * @desc: cookie for each DMA buffer + * @n_desc: the number of cookies + * @cur_dma: the current cookie in use + * @chan: the first DMA channel requested + * @chan2: the second DMA channel requested + */ +struct comedi_isadma { + struct comedi_isadma_desc *desc; + int n_desc; + int cur_dma; + unsigned int chan; + unsigned int chan2; +}; + +#if IS_ENABLED(CONFIG_ISA_DMA_API) + +void comedi_isadma_program(struct comedi_isadma_desc *); +unsigned int comedi_isadma_disable(unsigned int dma_chan); +unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan, + unsigned int size); +unsigned int comedi_isadma_poll(struct comedi_isadma *); +void comedi_isadma_set_mode(struct comedi_isadma_desc *, char dma_dir); + +struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *, + int n_desc, unsigned int dma_chan1, + unsigned int dma_chan2, + unsigned int maxsize, char dma_dir); +void comedi_isadma_free(struct comedi_isadma *); + +#else /* !IS_ENABLED(CONFIG_ISA_DMA_API) */ + +static inline void comedi_isadma_program(struct comedi_isadma_desc *desc) +{ +} + +static inline unsigned int comedi_isadma_disable(unsigned int dma_chan) +{ + return 0; +} + +static inline unsigned int +comedi_isadma_disable_on_sample(unsigned int dma_chan, unsigned int size) +{ + return 0; +} + +static inline unsigned int comedi_isadma_poll(struct comedi_isadma *dma) +{ + return 0; +} + +static inline void comedi_isadma_set_mode(struct comedi_isadma_desc *desc, + char dma_dir) +{ +} + +static inline struct comedi_isadma * +comedi_isadma_alloc(struct comedi_device *dev, int n_desc, + unsigned int dma_chan1, unsigned int dma_chan2, + unsigned int maxsize, char dma_dir) +{ + return NULL; +} + +static inline void comedi_isadma_free(struct comedi_isadma *dma) +{ +} + +#endif /* !IS_ENABLED(CONFIG_ISA_DMA_API) */ + +#endif /* #ifndef _COMEDI_ISADMA_H */ diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index 3bac903c8627..ceef6931edbe 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -24,7 +24,7 @@ * Description: Standard PC parallel port * Author: ds * Status: works in immediate mode - * Devices: (standard) parallel port [comedi_parport] + * Devices: [standard] parallel port (comedi_parport) * Updated: Tue, 30 Apr 2002 21:11:45 -0700 * * A cheap and easy way to get a few more digital I/O lines. Steal diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c index beb36c8dd00a..a6798ad8fa7f 100644 --- a/drivers/staging/comedi/drivers/dac02.c +++ b/drivers/staging/comedi/drivers/dac02.c @@ -24,7 +24,7 @@ /* * Driver: dac02 * Description: Comedi driver for DAC02 compatible boards - * Devices: (Keithley Metrabyte) DAC-02 [dac02] + * Devices: [Keithley Metrabyte] DAC-02 (dac02) * Author: H Hartley Sweeten <hsweeten@visionengravers.com> * Updated: Tue, 11 Mar 2014 11:27:19 -0700 * Status: unknown diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 20a9f0eb72b5..c78c0df9bbe3 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -1,6 +1,6 @@ /* * comedi/drivers/das08.c - * comedi driver for common DAS08 support (used by ISA/PCI/PCMCIA drivers) + * comedi module for common DAS08 support (used by ISA/PCI/PCMCIA drivers) * * COMEDI - Linux Control and Measurement Device Interface * Copyright (C) 2000 David A. Schleef <ds@schleef.org> @@ -18,21 +18,6 @@ * GNU General Public License for more details. */ -/* - * Driver: das08 - * Description: DAS-08 compatible boards - * Devices: various, see das08_isa, das08_cs, and das08_pci drivers - * Author: Warren Jasper, ds, Frank Hess - * Updated: Fri, 31 Aug 2012 19:19:06 +0100 - * Status: works - * - * This driver is used by the das08_isa, das08_cs, and das08_pci - * drivers to provide the common support for the DAS-08 hardware. - * - * The driver doesn't support asynchronous commands, since the - * cheap das08 hardware doesn't really support them. - */ - #include <linux/module.h> #include "../comedidev.h" diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index f3ccc2ce6d49..93fab6890161 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -41,10 +41,7 @@ Command support does not exist, but could be added for this board. #include <linux/module.h> -#include "../comedidev.h" - -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> +#include "../comedi_pcmcia.h" #include "das08.h" diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c index e4ba268e78ab..2d9a31dab552 100644 --- a/drivers/staging/comedi/drivers/das08_isa.c +++ b/drivers/staging/comedi/drivers/das08_isa.c @@ -21,18 +21,12 @@ /* * Driver: das08_isa * Description: DAS-08 ISA/PC-104 compatible boards - * Devices: (Keithley Metrabyte) DAS08 [isa-das08], - * (ComputerBoards) DAS08 [isa-das08] - * (ComputerBoards) DAS08-PGM [das08-pgm] - * (ComputerBoards) DAS08-PGH [das08-pgh] - * (ComputerBoards) DAS08-PGL [das08-pgl] - * (ComputerBoards) DAS08-AOH [das08-aoh] - * (ComputerBoards) DAS08-AOL [das08-aol] - * (ComputerBoards) DAS08-AOM [das08-aom] - * (ComputerBoards) DAS08/JR-AO [das08/jr-ao] - * (ComputerBoards) DAS08/JR-16-AO [das08jr-16-ao] - * (ComputerBoards) PC104-DAS08 [pc104-das08] - * (ComputerBoards) DAS08/JR/16 [das08jr/16] + * Devices: [Keithley Metrabyte] DAS08 (isa-das08), + * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm), + * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh), + * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao), + * DAS08/JR-16-AO (das08jr-16-ao), PC104-DAS08 (pc104-das08), + * DAS08/JR/16 (das08jr/16) * Author: Warren Jasper, ds, Frank Hess * Updated: Fri, 31 Aug 2012 19:19:06 +0100 * Status: works diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c index 0987ce554945..b2ea10b848c3 100644 --- a/drivers/staging/comedi/drivers/das08_pci.c +++ b/drivers/staging/comedi/drivers/das08_pci.c @@ -21,7 +21,7 @@ /* * Driver: das08_pci * Description: DAS-08 PCI compatible boards - * Devices: (ComputerBoards) PCI-DAS08 [pci-das08] + * Devices: [ComputerBoards] PCI-DAS08 (pci-das08) * Author: Warren Jasper, ds, Frank Hess * Updated: Fri, 31 Aug 2012 19:19:06 +0100 * Status: works diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 2436057304a3..2c20311120f1 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -22,28 +22,17 @@ * Driver: das16 * Description: DAS16 compatible boards * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze - * Devices: (Keithley Metrabyte) DAS-16 [das-16] - * (Keithley Metrabyte) DAS-16G [das-16g] - * (Keithley Metrabyte) DAS-16F [das-16f] - * (Keithley Metrabyte) DAS-1201 [das-1201] - * (Keithley Metrabyte) DAS-1202 [das-1202] - * (Keithley Metrabyte) DAS-1401 [das-1401] - * (Keithley Metrabyte) DAS-1402 [das-1402] - * (Keithley Metrabyte) DAS-1601 [das-1601] - * (Keithley Metrabyte) DAS-1602 [das-1602] - * (ComputerBoards) PC104-DAS16/JR [pc104-das16jr] - * (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16] - * (ComputerBoards) CIO-DAS16 [cio-das16] - * (ComputerBoards) CIO-DAS16F [cio-das16/f] - * (ComputerBoards) CIO-DAS16/JR [cio-das16/jr] - * (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16] - * (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12] - * (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12] - * (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16] - * (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12] - * (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12] - * (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16] - * (ComputerBoards) CIO-DAS16/330 [cio-das16/330] + * Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g), + * DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202), + * DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601), + * DAS-1602 (das-1602), + * [ComputerBoards] PC104-DAS16/JR (pc104-das16jr), + * PC104-DAS16JR/16 (pc104-das16jr/16), CIO-DAS16 (cio-das16), + * CIO-DAS16F (cio-das16/f), CIO-DAS16/JR (cio-das16/jr), + * CIO-DAS16JR/16 (cio-das16jr/16), CIO-DAS1401/12 (cio-das1401/12), + * CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16), + * CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12), + * CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330) * Status: works * Updated: 2003-10-12 * @@ -82,17 +71,14 @@ #include <linux/module.h> #include <linux/slab.h> -#include <linux/delay.h> -#include <linux/pci.h> #include <linux/interrupt.h> -#include <asm/dma.h> - #include "../comedidev.h" +#include "comedi_isadma.h" +#include "comedi_fc.h" #include "8253.h" #include "8255.h" -#include "comedi_fc.h" #define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */ @@ -451,86 +437,37 @@ static inline int timer_period(void) } struct das16_private_struct { + struct comedi_isadma *dma; unsigned int clockbase; unsigned int ctrl_reg; - unsigned long adc_byte_count; unsigned int divisor1; unsigned int divisor2; - unsigned int dma_chan; - uint16_t *dma_buffer[2]; - dma_addr_t dma_buffer_addr[2]; - unsigned int current_buffer; - unsigned int dma_transfer_size; - struct comedi_lrange *user_ai_range_table; - struct comedi_lrange *user_ao_range_table; struct timer_list timer; - short timer_running; unsigned long extra_iobase; unsigned int can_burst:1; + unsigned int timer_running:1; }; -static void das16_ai_enable(struct comedi_device *dev, - unsigned int mode, unsigned int src) -{ - struct das16_private_struct *devpriv = dev->private; - - devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | - DAS16_CTRL_DMAE | - DAS16_CTRL_PACING_MASK); - devpriv->ctrl_reg |= mode; - - if (src == TRIG_EXT) - devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER; - else - devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER; - outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); -} - -static void das16_ai_disable(struct comedi_device *dev) +static void das16_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int unread_samples) { struct das16_private_struct *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize); + unsigned int nsamples; - /* disable interrupts, dma and pacer clocked conversions */ - devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | - DAS16_CTRL_DMAE | - DAS16_CTRL_PACING_MASK); - outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); -} - -/* the pc104-das16jr (at least) has problems if the dma - transfer is interrupted in the middle of transferring - a 16 bit sample, so this function takes care to get - an even transfer count after disabling dma - channel. -*/ -static int disable_dma_on_even(struct comedi_device *dev) -{ - struct das16_private_struct *devpriv = dev->private; - static const int disable_limit = 100; - static const int enable_timeout = 100; - int residue; - int new_residue; - int i; - int j; - - disable_dma(devpriv->dma_chan); - residue = get_dma_residue(devpriv->dma_chan); - for (i = 0; i < disable_limit && (residue % 2); ++i) { - enable_dma(devpriv->dma_chan); - for (j = 0; j < enable_timeout; ++j) { - udelay(2); - new_residue = get_dma_residue(devpriv->dma_chan); - if (new_residue != residue) - break; - } - disable_dma(devpriv->dma_chan); - residue = get_dma_residue(devpriv->dma_chan); - } - if (i == disable_limit) { - dev_err(dev->class_dev, - "failed to get an even dma transfer, could be trouble\n"); + /* + * Determine dma size based on the buffer size plus the number of + * unread samples and the number of samples remaining in the command. + */ + nsamples = comedi_nsamples_left(s, max_samples + unread_samples); + if (nsamples > unread_samples) { + nsamples -= unread_samples; + desc->size = comedi_samples_to_bytes(s, nsamples); + comedi_isadma_program(desc); } - return residue; } static void das16_interrupt(struct comedi_device *dev) @@ -539,11 +476,12 @@ static void das16_interrupt(struct comedi_device *dev) struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; unsigned long spin_flags; - unsigned long dma_flags; + unsigned int residue; + unsigned int nbytes; unsigned int nsamples; - int num_bytes, residue; - int buffer_index; spin_lock_irqsave(&dev->spinlock, spin_flags); if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) { @@ -551,42 +489,36 @@ static void das16_interrupt(struct comedi_device *dev) return; } - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma_chan); - residue = disable_dma_on_even(dev); + /* + * The pc104-das16jr (at least) has problems if the dma + * transfer is interrupted in the middle of transferring + * a 16 bit sample. + */ + residue = comedi_isadma_disable_on_sample(desc->chan, + comedi_bytes_per_sample(s)); - /* figure out how many points to read */ - if (residue > devpriv->dma_transfer_size) { + /* figure out how many samples to read */ + if (residue > desc->size) { dev_err(dev->class_dev, "residue > transfer size!\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - num_bytes = 0; - } else - num_bytes = devpriv->dma_transfer_size - residue; - - if (cmd->stop_src == TRIG_COUNT && - num_bytes >= devpriv->adc_byte_count) { - num_bytes = devpriv->adc_byte_count; - async->events |= COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; + nbytes = 0; + } else { + nbytes = desc->size - residue; } + nsamples = comedi_bytes_to_samples(s, nbytes); - buffer_index = devpriv->current_buffer; - devpriv->current_buffer = (devpriv->current_buffer + 1) % 2; - devpriv->adc_byte_count -= num_bytes; - - /* re-enable dma */ - if ((async->events & COMEDI_CB_EOA) == 0) { - set_dma_addr(devpriv->dma_chan, - devpriv->dma_buffer_addr[devpriv->current_buffer]); - set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_chan); + /* restart DMA if more samples are needed */ + if (nsamples) { + dma->cur_dma = 1 - dma->cur_dma; + das16_ai_setup_dma(dev, s, nsamples); } - release_dma_lock(dma_flags); spin_unlock_irqrestore(&dev->spinlock, spin_flags); - nsamples = comedi_bytes_to_samples(s, num_bytes); - comedi_buf_write_samples(s, devpriv->dma_buffer[buffer_index], - nsamples); + comedi_buf_write_samples(s, desc->virt_addr, nsamples); + + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; comedi_handle_events(dev, s); } @@ -605,6 +537,29 @@ static void das16_timer_interrupt(unsigned long arg) spin_unlock_irqrestore(&dev->spinlock, flags); } +static void das16_ai_set_mux_range(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan, + unsigned int range) +{ + const struct das16_board *board = dev->board_ptr; + + /* set multiplexer */ + outb(first_chan | (last_chan << 4), dev->iobase + DAS16_MUX_REG); + + /* some boards do not have programmable gain */ + if (board->ai_pg == das16_pg_none) + return; + + /* + * Set gain (this is also burst rate register but according to + * computer boards manual, burst rate does nothing, even on + * keithley cards). + */ + outb((das16_gainlists[board->ai_pg])[range], + dev->iobase + DAS16_GAIN_REG); +} + static int das16_ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -755,13 +710,15 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct das16_board *board = dev->board_ptr; struct das16_private_struct *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned int first_chan = CR_CHAN(cmd->chanlist[0]); + unsigned int last_chan = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); + unsigned int range = CR_RANGE(cmd->chanlist[0]); unsigned int byte; unsigned long flags; - int range; if (cmd->flags & CMDF_PRIORITY) { dev_err(dev->class_dev, @@ -769,24 +726,11 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) return -1; } - devpriv->adc_byte_count = cmd->stop_arg * comedi_bytes_per_scan(s); - if (devpriv->can_burst) outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG); - /* set scan limits */ - byte = CR_CHAN(cmd->chanlist[0]); - byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4; - outb(byte, dev->iobase + DAS16_MUX_REG); - - /* set gain (this is also burst rate register but according to - * computer boards manual, burst rate does nothing, even on - * keithley cards) */ - if (board->ai_pg != das16_pg_none) { - range = CR_RANGE(cmd->chanlist[0]); - outb((das16_gainlists[board->ai_pg])[range], - dev->iobase + DAS16_GAIN_REG); - } + /* set mux and range for chanlist scan */ + das16_ai_set_mux_range(dev, first_chan, last_chan, range); /* set counter mode and counts */ cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags); @@ -805,19 +749,9 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) } outb(byte, dev->iobase + DAS16_PACER_REG); - /* set up dma transfer */ - flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma_chan); - devpriv->current_buffer = 0; - set_dma_addr(devpriv->dma_chan, - devpriv->dma_buffer_addr[devpriv->current_buffer]); - devpriv->dma_transfer_size = DAS16_DMA_SIZE; - set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_chan); - release_dma_lock(flags); + /* set up dma transfer */ + dma->cur_dma = 0; + das16_ai_setup_dma(dev, s, 0); /* set up timer */ spin_lock_irqsave(&dev->spinlock, flags); @@ -825,7 +759,14 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->timer.expires = jiffies + timer_period(); add_timer(&devpriv->timer); - das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src); + /* enable DMA interrupt with external or internal pacing */ + devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_PACING_MASK); + devpriv->ctrl_reg |= DAS16_CTRL_DMAE; + if (cmd->convert_src == TRIG_EXT) + devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER; + else + devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER; + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); if (devpriv->can_burst) outb(0, dev->iobase + DAS1600_CONV_REG); @@ -837,12 +778,17 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct das16_private_struct *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); - das16_ai_disable(dev); - disable_dma(devpriv->dma_chan); + /* disable interrupts, dma and pacer clocked conversions */ + devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_DMAE | + DAS16_CTRL_PACING_MASK); + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); + + comedi_isadma_disable(dma->chan); /* disable SW timer */ if (devpriv->timer_running) { @@ -893,23 +839,14 @@ static int das16_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - const struct das16_board *board = dev->board_ptr; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); unsigned int val; int ret; int i; - das16_ai_disable(dev); - - /* set multiplexer */ - outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG); - - /* set gain */ - if (board->ai_pg != das16_pg_none) { - outb((das16_gainlists[board->ai_pg])[range], - dev->iobase + DAS16_GAIN_REG); - } + /* set mux and range for single channel */ + das16_ai_set_mux_range(dev, chan, chan, range); for (i = 0; i < insn->n; i++) { /* trigger conversion */ @@ -1001,14 +938,107 @@ static void das16_reset(struct comedi_device *dev) outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg); } +static void das16_alloc_dma(struct comedi_device *dev, unsigned int dma_chan) +{ + struct das16_private_struct *devpriv = dev->private; + + /* only DMA channels 3 and 1 are valid */ + if (!(dma_chan == 1 || dma_chan == 3)) + return; + + /* DMA uses two buffers */ + devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan, + DAS16_DMA_SIZE, COMEDI_ISADMA_READ); + if (devpriv->dma) { + init_timer(&devpriv->timer); + devpriv->timer.function = das16_timer_interrupt; + devpriv->timer.data = (unsigned long)dev; + } +} + +static void das16_free_dma(struct comedi_device *dev) +{ + struct das16_private_struct *devpriv = dev->private; + + if (devpriv) { + if (devpriv->timer.data) + del_timer_sync(&devpriv->timer); + comedi_isadma_free(devpriv->dma); + } +} + +static const struct comedi_lrange *das16_ai_range(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it, + unsigned int pg_type, + unsigned int status) +{ + unsigned int min = it->options[4]; + unsigned int max = it->options[5]; + + /* get any user-defined input range */ + if (pg_type == das16_pg_none && (min || max)) { + struct comedi_lrange *lrange; + struct comedi_krange *krange; + + /* allocate single-range range table */ + lrange = comedi_alloc_spriv(s, + sizeof(*lrange) + sizeof(*krange)); + if (!lrange) + return &range_unknown; + + /* initialize ai range */ + lrange->length = 1; + krange = lrange->range; + krange->min = min; + krange->max = max; + krange->flags = UNIT_volt; + + return lrange; + } + + /* use software programmable range */ + if (status & DAS16_STATUS_UNIPOLAR) + return das16_ai_uni_lranges[pg_type]; + return das16_ai_bip_lranges[pg_type]; +} + +static const struct comedi_lrange *das16_ao_range(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + unsigned int min = it->options[6]; + unsigned int max = it->options[7]; + + /* get any user-defined output range */ + if (min || max) { + struct comedi_lrange *lrange; + struct comedi_krange *krange; + + /* allocate single-range range table */ + lrange = comedi_alloc_spriv(s, + sizeof(*lrange) + sizeof(*krange)); + if (!lrange) + return &range_unknown; + + /* initialize ao range */ + lrange->length = 1; + krange = lrange->range; + krange->min = min; + krange->max = max; + krange->flags = UNIT_volt; + + return lrange; + } + + return &range_unknown; +} + static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct das16_board *board = dev->board_ptr; struct das16_private_struct *devpriv; struct comedi_subdevice *s; - struct comedi_lrange *lrange; - struct comedi_krange *krange; - unsigned int dma_chan = it->options[2]; unsigned int status; int ret; @@ -1063,72 +1093,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->clockbase = I8254_OSC_BASE_1MHZ; } - /* initialize dma */ - if (dma_chan == 1 || dma_chan == 3) { - unsigned long flags; - int i; - - if (request_dma(dma_chan, dev->board_name)) { - dev_err(dev->class_dev, - "failed to request dma channel %i\n", - dma_chan); - return -EINVAL; - } - devpriv->dma_chan = dma_chan; - - /* allocate dma buffers */ - for (i = 0; i < 2; i++) { - void *p; - - p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE, - &devpriv->dma_buffer_addr[i]); - if (!p) - return -ENOMEM; - devpriv->dma_buffer[i] = p; - } - - flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); - release_dma_lock(flags); - - init_timer(&devpriv->timer); - devpriv->timer.function = das16_timer_interrupt; - devpriv->timer.data = (unsigned long)dev; - } - - /* get any user-defined input range */ - if (board->ai_pg == das16_pg_none && - (it->options[4] || it->options[5])) { - /* allocate single-range range table */ - lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL); - if (!lrange) - return -ENOMEM; - - /* initialize ai range */ - devpriv->user_ai_range_table = lrange; - lrange->length = 1; - krange = devpriv->user_ai_range_table->range; - krange->min = it->options[4]; - krange->max = it->options[5]; - krange->flags = UNIT_volt; - } - - /* get any user-defined output range */ - if (it->options[6] || it->options[7]) { - /* allocate single-range range table */ - lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL); - if (!lrange) - return -ENOMEM; - - /* initialize ao range */ - devpriv->user_ao_range_table = lrange; - lrange->length = 1; - krange = devpriv->user_ao_range_table->range; - krange->min = it->options[6]; - krange->max = it->options[7]; - krange->flags = UNIT_volt; - } + das16_alloc_dma(dev, it->options[2]); ret = comedi_alloc_subdevices(dev, 4 + board->has_8255); if (ret) @@ -1149,15 +1114,9 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) } s->len_chanlist = s->n_chan; s->maxdata = board->ai_maxdata; - if (devpriv->user_ai_range_table) { /* user defined ai range */ - s->range_table = devpriv->user_ai_range_table; - } else if (status & DAS16_STATUS_UNIPOLAR) { - s->range_table = das16_ai_uni_lranges[board->ai_pg]; - } else { - s->range_table = das16_ai_bip_lranges[board->ai_pg]; - } + s->range_table = das16_ai_range(dev, s, it, board->ai_pg, status); s->insn_read = das16_ai_insn_read; - if (devpriv->dma_chan) { + if (devpriv->dma) { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; s->do_cmdtest = das16_cmd_test; @@ -1173,7 +1132,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = 0x0fff; - s->range_table = devpriv->user_ao_range_table; + s->range_table = das16_ao_range(dev, s, it); s->insn_write = das16_ao_insn_write; ret = comedi_alloc_subdev_readback(s); @@ -1230,25 +1189,11 @@ static void das16_detach(struct comedi_device *dev) { const struct das16_board *board = dev->board_ptr; struct das16_private_struct *devpriv = dev->private; - int i; if (devpriv) { - if (devpriv->timer.data) - del_timer_sync(&devpriv->timer); if (dev->iobase) das16_reset(dev); - - for (i = 0; i < 2; i++) { - if (devpriv->dma_buffer[i]) - pci_free_consistent(NULL, DAS16_DMA_SIZE, - devpriv->dma_buffer[i], - devpriv-> - dma_buffer_addr[i]); - } - if (devpriv->dma_chan) - free_dma(devpriv->dma_chan); - kfree(devpriv->user_ai_range_table); - kfree(devpriv->user_ao_range_table); + das16_free_dma(dev); if (devpriv->extra_iobase) release_region(devpriv->extra_iobase, diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 80f41b7e8273..3666a68979fb 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -455,7 +455,7 @@ 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) { - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + async->events |= COMEDI_CB_ERROR; dev_err(dev->class_dev, "fifo overflow\n"); } diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index be825d21a185..0790a28828de 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -98,12 +98,12 @@ TODO: #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/io.h> -#include "../comedidev.h" -#include <asm/dma.h> +#include "../comedidev.h" -#include "8253.h" +#include "comedi_isadma.h" #include "comedi_fc.h" +#include "8253.h" /* misc. defines */ #define DAS1800_SIZE 16 /* uses 16 io addresses */ @@ -421,19 +421,14 @@ static const struct das1800_board das1800_boards[] = { }; struct das1800_private { + struct comedi_isadma *dma; unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ int irq_dma_bits; /* bits for control register b */ /* dma bits for control register b, stored so that dma can be * turned on and off */ int dma_bits; - unsigned int dma0; /* dma channels used */ - unsigned int dma1; - unsigned int dma_current; /* dma channel currently in use */ - uint16_t *ai_buf0; /* pointers to dma buffers */ - uint16_t *ai_buf1; - uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */ - unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */ + uint16_t *fifo_buf; /* bounce buffer for analog input FIFO */ unsigned long iobase2; /* secondary io address used for analog out on 'ao' boards */ unsigned short ao_update_bits; /* remembers the last write to the * 'update' dac */ @@ -480,9 +475,9 @@ static void das1800_handle_fifo_half_full(struct comedi_device *dev, struct das1800_private *devpriv = dev->private; unsigned int nsamples = comedi_nsamples_left(s, FIFO_SIZE / 2); - insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, nsamples); - munge_data(dev, devpriv->ai_buf0, nsamples); - comedi_buf_write_samples(s, devpriv->ai_buf0, nsamples); + insw(dev->iobase + DAS1800_FIFO, devpriv->fifo_buf, nsamples); + munge_data(dev, devpriv->fifo_buf, nsamples); + comedi_buf_write_samples(s, devpriv->fifo_buf, nsamples); } static void das1800_handle_fifo_not_empty(struct comedi_device *dev, @@ -508,29 +503,21 @@ static void das1800_handle_fifo_not_empty(struct comedi_device *dev, } } -/* Utility function used by das1800_flush_dma() and das1800_handle_dma(). - * Assumes dma lock is held */ +/* Utility function used by das1800_flush_dma() and das1800_handle_dma() */ static void das1800_flush_dma_channel(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int channel, uint16_t *buffer) + struct comedi_isadma_desc *desc) { - struct das1800_private *devpriv = dev->private; - unsigned int nbytes; + unsigned int residue = comedi_isadma_disable(desc->chan); + unsigned int nbytes = desc->size - residue; unsigned int nsamples; - disable_dma(channel); - - /* clear flip-flop to make sure 2-byte registers - * get set correctly */ - clear_dma_ff(channel); - /* figure out how many points to read */ - nbytes = devpriv->dma_transfer_size - get_dma_residue(channel); nsamples = comedi_bytes_to_samples(s, nbytes); nsamples = comedi_nsamples_left(s, nsamples); - munge_data(dev, buffer, nsamples); - comedi_buf_write_samples(s, buffer, nsamples); + munge_data(dev, desc->virt_addr, nsamples); + comedi_buf_write_samples(s, desc->virt_addr, nsamples); } /* flushes remaining data from board when external trigger has stopped acquisition @@ -539,28 +526,19 @@ static void das1800_flush_dma(struct comedi_device *dev, struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; - unsigned long flags; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; - flags = claim_dma_lock(); - das1800_flush_dma_channel(dev, s, devpriv->dma_current, - devpriv->dma_current_buf); + das1800_flush_dma_channel(dev, s, desc); if (dual_dma) { /* switch to other channel and flush it */ - if (devpriv->dma_current == devpriv->dma0) { - devpriv->dma_current = devpriv->dma1; - devpriv->dma_current_buf = devpriv->ai_buf1; - } else { - devpriv->dma_current = devpriv->dma0; - devpriv->dma_current_buf = devpriv->ai_buf0; - } - das1800_flush_dma_channel(dev, s, devpriv->dma_current, - devpriv->dma_current_buf); + dma->cur_dma = 1 - dma->cur_dma; + desc = &dma->desc[dma->cur_dma]; + das1800_flush_dma_channel(dev, s, desc); } - release_dma_lock(flags); - /* get any remaining samples in fifo */ das1800_handle_fifo_not_empty(dev, s); } @@ -569,47 +547,41 @@ static void das1800_handle_dma(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int status) { struct das1800_private *devpriv = dev->private; - unsigned long flags; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; - flags = claim_dma_lock(); - das1800_flush_dma_channel(dev, s, devpriv->dma_current, - devpriv->dma_current_buf); - /* re-enable dma channel */ - set_dma_addr(devpriv->dma_current, - virt_to_bus(devpriv->dma_current_buf)); - set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_current); - release_dma_lock(flags); + das1800_flush_dma_channel(dev, s, desc); + + /* re-enable dma channel */ + comedi_isadma_program(desc); if (status & DMATC) { /* clear DMATC interrupt bit */ outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS); /* switch dma channels for next time, if appropriate */ - if (dual_dma) { - /* read data from the other channel next time */ - if (devpriv->dma_current == devpriv->dma0) { - devpriv->dma_current = devpriv->dma1; - devpriv->dma_current_buf = devpriv->ai_buf1; - } else { - devpriv->dma_current = devpriv->dma0; - devpriv->dma_current_buf = devpriv->ai_buf0; - } - } + if (dual_dma) + dma->cur_dma = 1 - dma->cur_dma; } } static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc; + int i; outb(0x0, dev->iobase + DAS1800_STATUS); /* disable conversions */ outb(0x0, dev->iobase + DAS1800_CONTROL_B); /* disable interrupts and dma */ outb(0x0, dev->iobase + DAS1800_CONTROL_A); /* disable and clear fifo and stop triggering */ - if (devpriv->dma0) - disable_dma(devpriv->dma0); - if (devpriv->dma1) - disable_dma(devpriv->dma1); + + for (i = 0; i < 2; i++) { + desc = &dma->desc[i]; + if (desc->chan) + comedi_isadma_disable(desc->chan); + } + return 0; } @@ -639,7 +611,7 @@ static void das1800_ai_handler(struct comedi_device *dev) /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); dev_err(dev->class_dev, "FIFO overflow\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); return; } @@ -963,79 +935,64 @@ static void das1800_setup_counters(struct comedi_device *dev, } } -/* utility function that suggests a dma transfer size based on the conversion period 'ns' */ -static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd) +static unsigned int das1800_ai_transfer_size(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int maxbytes, + unsigned int ns) { - unsigned int size = DMA_BUF_SIZE; - static const int sample_size = 2; /* size in bytes of one sample from board */ - unsigned int fill_time = 300000000; /* target time in nanoseconds for filling dma buffer */ - unsigned int max_size; /* maximum size we will allow for a transfer */ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int max_samples = comedi_bytes_to_samples(s, maxbytes); + unsigned int samples; + + samples = max_samples; - /* make dma buffer fill in 0.3 seconds for timed modes */ + /* for timed modes, make dma buffer fill in 'ns' time */ switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: /* not in burst mode */ + case TRIG_FOLLOW: /* not in burst mode */ if (cmd->convert_src == TRIG_TIMER) - size = (fill_time / cmd->convert_arg) * sample_size; + samples = ns / cmd->convert_arg; break; case TRIG_TIMER: - size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) * - sample_size; - break; - default: - size = DMA_BUF_SIZE; + samples = ns / (cmd->scan_begin_arg * cmd->chanlist_len); break; } - /* set a minimum and maximum size allowed */ - max_size = DMA_BUF_SIZE; - /* if we are taking limited number of conversions, limit transfer size to that */ - if (cmd->stop_src == TRIG_COUNT && - cmd->stop_arg * cmd->chanlist_len * sample_size < max_size) - max_size = cmd->stop_arg * cmd->chanlist_len * sample_size; + /* limit samples to what is remaining in the command */ + samples = comedi_nsamples_left(s, samples); - if (size > max_size) - size = max_size; - if (size < sample_size) - size = sample_size; + if (samples > max_samples) + samples = max_samples; + if (samples < 1) + samples = 1; - return size; + return comedi_samples_to_bytes(s, samples); } -/* sets up dma */ -static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) +static void das1800_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; - unsigned long lock_flags; - const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[0]; + unsigned int bytes; if ((devpriv->irq_dma_bits & DMA_ENABLED) == 0) return; - /* determine a reasonable dma transfer size */ - devpriv->dma_transfer_size = suggest_transfer_size(cmd); - lock_flags = claim_dma_lock(); - disable_dma(devpriv->dma0); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma0); - set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->ai_buf0)); - /* set appropriate size of transfer */ - set_dma_count(devpriv->dma0, devpriv->dma_transfer_size); - devpriv->dma_current = devpriv->dma0; - devpriv->dma_current_buf = devpriv->ai_buf0; - enable_dma(devpriv->dma0); - /* set up dual dma if appropriate */ - if (dual_dma) { - disable_dma(devpriv->dma1); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma1); - set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->ai_buf1)); - /* set appropriate size of transfer */ - set_dma_count(devpriv->dma1, devpriv->dma_transfer_size); - enable_dma(devpriv->dma1); + dma->cur_dma = 0; + + /* determine a dma transfer size to fill buffer in 0.3 sec */ + bytes = das1800_ai_transfer_size(dev, s, desc->maxsize, 300000000); + + desc->size = bytes; + comedi_isadma_program(desc); + + /* set up dual dma if appropriate */ + if (devpriv->irq_dma_bits & DMA_DUAL) { + desc = &dma->desc[1]; + desc->size = bytes; + comedi_isadma_program(desc); } - release_dma_lock(lock_flags); } /* programs channel/gain list into card */ @@ -1097,7 +1054,7 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, /* setup card and start */ program_chanlist(dev, cmd); das1800_setup_counters(dev, cmd); - setup_dma(dev, cmd); + das1800_ai_setup_dma(dev, s); outb(control_c, dev->iobase + DAS1800_CONTROL_C); /* set conversion rate and length for burst mode */ if (control_c & BMDE) { @@ -1234,79 +1191,57 @@ static int das1800_do_wbits(struct comedi_device *dev, return insn->n; } -static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, - unsigned int dma1) +static void das1800_init_dma(struct comedi_device *dev, + struct comedi_devconfig *it) { struct das1800_private *devpriv = dev->private; - unsigned long flags; + unsigned int *dma_chan; - /* need an irq to do dma */ - if (dev->irq && dma0) { - /* encode dma0 and dma1 into 2 digit hexadecimal for switch */ - switch ((dma0 & 0x7) | (dma1 << 4)) { - case 0x5: /* dma0 == 5 */ - devpriv->dma_bits |= DMA_CH5; - break; - case 0x6: /* dma0 == 6 */ - devpriv->dma_bits |= DMA_CH6; - break; - case 0x7: /* dma0 == 7 */ - devpriv->dma_bits |= DMA_CH7; - break; - case 0x65: /* dma0 == 5, dma1 == 6 */ - devpriv->dma_bits |= DMA_CH5_CH6; - break; - case 0x76: /* dma0 == 6, dma1 == 7 */ - devpriv->dma_bits |= DMA_CH6_CH7; - break; - case 0x57: /* dma0 == 7, dma1 == 5 */ - devpriv->dma_bits |= DMA_CH7_CH5; - break; - default: - dev_err(dev->class_dev, - "only supports dma channels 5 through 7\n"); - dev_err(dev->class_dev, - "Dual dma only allows the following combinations:\n"); - dev_err(dev->class_dev, - "dma 5,6 / 6,7 / or 7,5\n"); - return -EINVAL; - } - if (request_dma(dma0, dev->driver->driver_name)) { - dev_err(dev->class_dev, - "failed to allocate dma channel %i\n", dma0); - return -EINVAL; - } - devpriv->dma0 = dma0; - devpriv->dma_current = dma0; - if (dma1) { - if (request_dma(dma1, dev->driver->driver_name)) { - dev_err(dev->class_dev, - "failed to allocate dma channel %i\n", - dma1); - return -EINVAL; - } - devpriv->dma1 = dma1; - } - devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); - if (devpriv->ai_buf0 == NULL) - return -ENOMEM; - devpriv->dma_current_buf = devpriv->ai_buf0; - if (dma1) { - devpriv->ai_buf1 = - kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); - if (devpriv->ai_buf1 == NULL) - return -ENOMEM; - } - flags = claim_dma_lock(); - disable_dma(devpriv->dma0); - set_dma_mode(devpriv->dma0, DMA_MODE_READ); - if (dma1) { - disable_dma(devpriv->dma1); - set_dma_mode(devpriv->dma1, DMA_MODE_READ); - } - release_dma_lock(flags); + /* + * it->options[2] is DMA channel 0 + * it->options[3] is DMA channel 1 + * + * Encode the DMA channels into 2 digit hexadecimal for switch. + */ + dma_chan = &it->options[2]; + + switch ((dma_chan[0] & 0x7) | (dma_chan[1] << 4)) { + case 0x5: /* dma0 == 5 */ + devpriv->dma_bits = DMA_CH5; + break; + case 0x6: /* dma0 == 6 */ + devpriv->dma_bits = DMA_CH6; + break; + case 0x7: /* dma0 == 7 */ + devpriv->dma_bits = DMA_CH7; + break; + case 0x65: /* dma0 == 5, dma1 == 6 */ + devpriv->dma_bits = DMA_CH5_CH6; + break; + case 0x76: /* dma0 == 6, dma1 == 7 */ + devpriv->dma_bits = DMA_CH6_CH7; + break; + case 0x57: /* dma0 == 7, dma1 == 5 */ + devpriv->dma_bits = DMA_CH7_CH5; + break; + default: + return; } - return 0; + + /* DMA can use 1 or 2 buffers, each with a separate channel */ + devpriv->dma = comedi_isadma_alloc(dev, dma_chan[1] ? 2 : 1, + dma_chan[0], dma_chan[1], + DMA_BUF_SIZE, COMEDI_ISADMA_READ); + if (!devpriv->dma) + devpriv->dma_bits = 0; +} + +static void das1800_free_dma(struct comedi_device *dev) +{ + struct das1800_private *devpriv = dev->private; + + if (devpriv) + comedi_isadma_free(devpriv->dma); } static int das1800_probe(struct comedi_device *dev) @@ -1374,8 +1309,6 @@ static int das1800_attach(struct comedi_device *dev, struct das1800_private *devpriv; struct comedi_subdevice *s; unsigned int irq = it->options[1]; - unsigned int dma0 = it->options[2]; - unsigned int dma1 = it->options[3]; int board; int ret; @@ -1437,16 +1370,13 @@ static int das1800_attach(struct comedi_device *dev, } } - ret = das1800_init_dma(dev, dma0, dma1); - if (ret < 0) - return ret; + /* an irq and one dma channel is required to use dma */ + if (dev->irq & it->options[2]) + das1800_init_dma(dev, it); - if (devpriv->ai_buf0 == NULL) { - devpriv->ai_buf0 = - kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL); - if (devpriv->ai_buf0 == NULL) - return -ENOMEM; - } + devpriv->fifo_buf = kmalloc_array(FIFO_SIZE, sizeof(uint16_t), GFP_KERNEL); + if (!devpriv->fifo_buf) + return -ENOMEM; ret = comedi_alloc_subdevices(dev, 4); if (ret) @@ -1523,13 +1453,9 @@ static void das1800_detach(struct comedi_device *dev) { struct das1800_private *devpriv = dev->private; + das1800_free_dma(dev); if (devpriv) { - if (devpriv->dma0) - free_dma(devpriv->dma0); - if (devpriv->dma1) - free_dma(devpriv->dma1); - kfree(devpriv->ai_buf0); - kfree(devpriv->ai_buf1); + kfree(devpriv->fifo_buf); if (devpriv->iobase2) release_region(devpriv->iobase2, DAS1800_SIZE); } diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 780f4f646ea0..b8755b50a11e 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -20,8 +20,8 @@ /* * Driver: das6402 * Description: Keithley Metrabyte DAS6402 (& compatibles) - * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12) - * (Keithley Metrabyte) DAS6402-16 (das6402-16) + * Devices: [Keithley Metrabyte] DAS6402-12 (das6402-12), + * DAS6402-16 (das6402-16) * Author: H Hartley Sweeten <hsweeten@visionengravers.com> * Updated: Fri, 14 Mar 2014 10:18:43 -0700 * Status: unknown diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index e5bdc2423445..ff7f4be3f314 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -511,7 +511,7 @@ static irqreturn_t das800_interrupt(int irq, void *d) if (fifo_overflow) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 6df298a99cc6..1af006609fc1 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -19,7 +19,7 @@ /* * Driver: dmm32at * Description: Diamond Systems Diamond-MM-32-AT - * Devices: (Diamond Systems) Diamond-MM-32-AT [dmm32at] + * Devices: [Diamond Systems] Diamond-MM-32-AT (dmm32at) * Author: Perry J. Piplani <perry.j.piplani@nasa.gov> * Updated: Fri Jun 4 09:13:24 CDT 2004 * Status: experimental @@ -365,7 +365,7 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec) /* enable the ai conversion interrupt and the clock to start scans */ outb(DMM32AT_INTCLK_ADINT | DMM32AT_INTCLK_CLKEN | DMM32AT_INTCLK_CLKSEL, - dev->iobase + DMM32AT_INTCLK_REG); + dev->iobase + DMM32AT_INTCLK_REG); } static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 2be98bb9a809..db21d2135856 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -20,22 +20,12 @@ * Driver: dt282x * Description: Data Translation DT2821 series (including DT-EZ) * Author: ds - * Devices: (Data Translation) DT2821 [dt2821] - * (Data Translation) DT2821-F-16SE [dt2821-f] - * (Data Translation) DT2821-F-8DI [dt2821-f] - * (Data Translation) DT2821-G-16SE [dt2821-g] - * (Data Translation) DT2821-G-8DI [dt2821-g] - * (Data Translation) DT2823 [dt2823] - * (Data Translation) DT2824-PGH [dt2824-pgh] - * (Data Translation) DT2824-PGL [dt2824-pgl] - * (Data Translation) DT2825 [dt2825] - * (Data Translation) DT2827 [dt2827] - * (Data Translation) DT2828 [dt2828] - * (Data Translation) DT2928 [dt2829] - * (Data Translation) DT21-EZ [dt21-ez] - * (Data Translation) DT23-EZ [dt23-ez] - * (Data Translation) DT24-EZ [dt24-ez] - * (Data Translation) DT24-EZ-PGL [dt24-ez-pgl] + * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f), + * DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g), + * DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh), + * DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827), + * DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez), + * DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl) * Status: complete * Updated: Wed, 22 Aug 2001 17:11:34 -0700 * @@ -66,15 +56,14 @@ */ #include <linux/module.h> -#include "../comedidev.h" - #include <linux/delay.h> #include <linux/gfp.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <asm/dma.h> +#include "../comedidev.h" +#include "comedi_isadma.h" #include "comedi_fc.h" /* @@ -311,55 +300,36 @@ static const struct dt282x_board boardtypes[] = { }; struct dt282x_private { + struct comedi_isadma *dma; unsigned int ad_2scomp:1; - unsigned int divisor; - int dacsr; /* software copies of registers */ int adcsr; int supcsr; - int ntrig; int nread; - - struct { - int chan; - unsigned short *buf; /* DMA buffer */ - int size; /* size of current transfer */ - } dma[2]; - int dma_maxsize; /* max size of DMA transfer (in bytes) */ - int current_dma_index; int dma_dir; }; static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n) { struct dt282x_private *devpriv = dev->private; - int dma_chan; - unsigned long dma_ptr; - unsigned long flags; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma_index]; if (!devpriv->ntrig) return 0; if (n == 0) - n = devpriv->dma_maxsize; + n = desc->maxsize; if (n > devpriv->ntrig * 2) n = devpriv->ntrig * 2; devpriv->ntrig -= n / 2; - devpriv->dma[dma_index].size = n; - dma_chan = devpriv->dma[dma_index].chan; - dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf); - - set_dma_mode(dma_chan, DMA_MODE_READ); - flags = claim_dma_lock(); - clear_dma_ff(dma_chan); - set_dma_addr(dma_chan, dma_ptr); - set_dma_count(dma_chan, n); - release_dma_lock(flags); + desc->size = n; + comedi_isadma_set_mode(desc, devpriv->dma_dir); - enable_dma(dma_chan); + comedi_isadma_program(desc); return n; } @@ -367,22 +337,13 @@ static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n) static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n) { struct dt282x_private *devpriv = dev->private; - int dma_chan; - unsigned long dma_ptr; - unsigned long flags; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma_index]; - devpriv->dma[dma_index].size = n; - dma_chan = devpriv->dma[dma_index].chan; - dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf); + desc->size = n; + comedi_isadma_set_mode(desc, devpriv->dma_dir); - set_dma_mode(dma_chan, DMA_MODE_WRITE); - flags = claim_dma_lock(); - clear_dma_ff(dma_chan); - set_dma_addr(dma_chan, dma_ptr); - set_dma_count(dma_chan, n); - release_dma_lock(flags); - - enable_dma(dma_chan); + comedi_isadma_program(desc); return n; } @@ -390,9 +351,14 @@ static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n) static void dt282x_disable_dma(struct comedi_device *dev) { struct dt282x_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc; + int i; - disable_dma(devpriv->dma[0].chan); - disable_dma(devpriv->dma[1].chan); + for (i = 0; i < 2; i++) { + desc = &dma->desc[i]; + comedi_isadma_disable(desc->chan); + } } static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags) @@ -454,11 +420,12 @@ static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev, int cur_dma) { struct dt282x_private *devpriv = dev->private; - void *ptr = devpriv->dma[cur_dma].buf; - unsigned int nsamples = comedi_bytes_to_samples(s, devpriv->dma_maxsize); + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[cur_dma]; + unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize); unsigned int nbytes; - nbytes = comedi_buf_read_samples(s, ptr, nsamples); + nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples); if (nbytes) dt282x_prep_ao_dma(dev, cur_dma, nbytes); else @@ -471,39 +438,37 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { struct dt282x_private *devpriv = dev->private; - int cur_dma = devpriv->current_dma_index; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE, dev->iobase + DT2821_SUPCSR_REG); - disable_dma(devpriv->dma[cur_dma].chan); - - devpriv->current_dma_index = 1 - cur_dma; + comedi_isadma_disable(desc->chan); - if (!dt282x_ao_setup_dma(dev, s, cur_dma)) + if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma)) s->async->events |= COMEDI_CB_OVERFLOW; + + dma->cur_dma = 1 - dma->cur_dma; } static void dt282x_ai_dma_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { struct dt282x_private *devpriv = dev->private; - int cur_dma = devpriv->current_dma_index; - void *ptr = devpriv->dma[cur_dma].buf; - int size = devpriv->dma[cur_dma].size; - unsigned int nsamples = comedi_bytes_to_samples(s, size); + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned int nsamples = comedi_bytes_to_samples(s, desc->size); int ret; outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE, dev->iobase + DT2821_SUPCSR_REG); - disable_dma(devpriv->dma[cur_dma].chan); - - devpriv->current_dma_index = 1 - cur_dma; + comedi_isadma_disable(desc->chan); - dt282x_munge(dev, s, ptr, size); - ret = comedi_buf_write_samples(s, ptr, nsamples); - if (ret != size) + dt282x_munge(dev, s, desc->virt_addr, desc->size); + ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples); + if (ret != desc->size) return; devpriv->nread -= nsamples; @@ -524,7 +489,9 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev, } #endif /* restart the channel */ - dt282x_prep_ai_dma(dev, cur_dma, 0); + dt282x_prep_ai_dma(dev, dma->cur_dma, 0); + + dma->cur_dma = 1 - dma->cur_dma; } static irqreturn_t dt282x_interrupt(int irq, void *d) @@ -545,7 +512,7 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) dacsr = inw(dev->iobase + DT2821_DACSR_REG); supcsr = inw(dev->iobase + DT2821_SUPCSR_REG); if (supcsr & DT2821_SUPCSR_DMAD) { - if (devpriv->dma_dir == DMA_MODE_READ) + if (devpriv->dma_dir == COMEDI_ISADMA_READ) dt282x_ai_dma_interrupt(dev, s); else dt282x_ao_dma_interrupt(dev, s_ao); @@ -718,14 +685,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* internal trigger */ - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000); @@ -757,6 +717,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct dt282x_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_cmd *cmd = &s->async->cmd; int ret; @@ -778,8 +739,8 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg; devpriv->nread = devpriv->ntrig; - devpriv->dma_dir = DMA_MODE_READ; - devpriv->current_dma_index = 0; + devpriv->dma_dir = COMEDI_ISADMA_READ; + dma->cur_dma = 0; dt282x_prep_ai_dma(dev, 0, 0); if (devpriv->ntrig) { dt282x_prep_ai_dma(dev, 1, 0); @@ -942,6 +903,7 @@ static int dt282x_ao_inttrig(struct comedi_device *dev, static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct dt282x_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_cmd *cmd = &s->async->cmd; dt282x_disable_dma(dev); @@ -958,8 +920,8 @@ static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len; devpriv->nread = devpriv->ntrig; - devpriv->dma_dir = DMA_MODE_WRITE; - devpriv->current_dma_index = 0; + devpriv->dma_dir = COMEDI_ISADMA_WRITE; + dma->cur_dma = 0; outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG); @@ -1063,46 +1025,42 @@ static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x) return ai_range_table[x]; } -static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) +static void dt282x_alloc_dma(struct comedi_device *dev, + struct comedi_devconfig *it) { struct dt282x_private *devpriv = dev->private; - int ret; + unsigned int irq_num = it->options[1]; + unsigned int dma_chan[2]; - ret = request_dma(dma1, "dt282x A"); - if (ret) - return -EBUSY; - devpriv->dma[0].chan = dma1; + if (it->options[2] < it->options[3]) { + dma_chan[0] = it->options[2]; + dma_chan[1] = it->options[3]; + } else { + dma_chan[0] = it->options[3]; + dma_chan[1] = it->options[2]; + } - ret = request_dma(dma2, "dt282x B"); - if (ret) - return -EBUSY; - devpriv->dma[1].chan = dma2; + if (!irq_num || dma_chan[0] == dma_chan[1] || + dma_chan[0] < 5 || dma_chan[0] > 7 || + dma_chan[1] < 5 || dma_chan[1] > 7) + return; - devpriv->dma_maxsize = PAGE_SIZE; - devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) - return -ENOMEM; + if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev)) + return; - return 0; + /* DMA uses two 4K buffers with separate DMA channels */ + devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1], + PAGE_SIZE, 0); + if (!devpriv->dma) + free_irq(irq_num, dev); } static void dt282x_free_dma(struct comedi_device *dev) { struct dt282x_private *devpriv = dev->private; - int i; - - if (!devpriv) - return; - for (i = 0; i < 2; i++) { - if (devpriv->dma[i].chan) - free_dma(devpriv->dma[i].chan); - if (devpriv->dma[i].buf) - free_page((unsigned long)devpriv->dma[i].buf); - devpriv->dma[i].chan = 0; - devpriv->dma[i].buf = NULL; - } + if (devpriv) + comedi_isadma_free(devpriv->dma); } static int dt282x_initialize(struct comedi_device *dev) @@ -1160,36 +1118,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) return -ENOMEM; /* an IRQ and 2 DMA channels are required for async command support */ - if (it->options[1] && it->options[2] && it->options[3]) { - unsigned int irq = it->options[1]; - unsigned int dma1 = it->options[2]; - unsigned int dma2 = it->options[3]; - - if (dma2 < dma1) { - unsigned int swap; - - swap = dma1; - dma1 = dma2; - dma2 = swap; - } - - if (dma1 != dma2 && - dma1 >= 5 && dma1 <= 7 && - dma2 >= 5 && dma2 <= 7) { - ret = request_irq(irq, dt282x_interrupt, 0, - dev->board_name, dev); - if (ret == 0) { - dev->irq = irq; - - ret = dt282x_grab_dma(dev, dma1, dma2); - if (ret < 0) { - dt282x_free_dma(dev); - free_irq(dev->irq, dev); - dev->irq = 0; - } - } - } - } + dt282x_alloc_dma(dev, it); ret = comedi_alloc_subdevices(dev, 3); if (ret) diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 1d9a7a63e06f..0aa51980e327 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -355,7 +355,7 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) dt3k_ai_empty_fifo(dev, s); if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_ERROR; debug_n_ints++; if (debug_n_ints >= 10) diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 06c601d8fdff..e11c216a4c85 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -42,9 +42,8 @@ for my needs. #include <linux/module.h> #include <linux/errno.h> #include <linux/uaccess.h> -#include <linux/usb.h> -#include "../comedidev.h" +#include "../comedi_usb.h" #define DT9812_DIAGS_BOARD_INFO_ADDR 0xFBFF #define DT9812_MAX_WRITE_CMD_PIPE_SIZE 32 diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index 1b6324c6eb29..6c1e442f6c81 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -14,24 +14,23 @@ */ /* - Driver: dyna_pci10xx - Devices: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/ - Author: Prashant Shah <pshah.mumbai@gmail.com> - Developed at Automation Labs, Chemical Dept., IIT Bombay, India. - Prof. Kannan Moudgalya <kannan@iitb.ac.in> - http://www.iitb.ac.in - Status: Stable - Version: 1.0 - Device Supported : - - Dynalog PCI 1050 - - Notes : - - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and - they are using the PLX Technlogies Vendor ID since that is the PCI Chip used - in the card. - - Dynalog India Pvt. Ltd. has provided the internal register specification for - their cards in their manuals. -*/ + * Driver: dyna_pci10xx + * Description: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/ + * Devices: [Dynalog] PCI-1050 (dyna_pci1050) + * Author: Prashant Shah <pshah.mumbai@gmail.com> + * Status: Stable + * + * Developed at Automation Labs, Chemical Dept., IIT Bombay, India. + * Prof. Kannan Moudgalya <kannan@iitb.ac.in> + * http://www.iitb.ac.in + * + * Notes : + * - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and + * they are using the PLX Technlogies Vendor ID since that is the PCI Chip + * used in the card. + * - Dynalog India Pvt. Ltd. has provided the internal register specification + * for their cards in their manuals. + */ #include <linux/module.h> #include <linux/delay.h> diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 0979f536ed39..deada9784b69 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -261,12 +261,12 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) if (hpdi_board_status & RX_OVERRUN_BIT) { dev_err(dev->class_dev, "rx fifo overrun\n"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + async->events |= 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; + async->events |= COMEDI_CB_ERROR; } if (devpriv->dio_count == 0) diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 1085d66935fe..0768bc42a5db 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -9,7 +9,7 @@ /* * Driver: ii_pci20kc * Description: Intelligent Instruments PCI-20001C carrier board - * Devices: (Intelligent Instrumentation) PCI-20001C [ii_pci20kc] + * Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc) * Author: Markus Kempf <kempf@matsci.uni-sb.de> * Status: works * diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index 20478ae8fad6..356811defaf4 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.h +++ b/drivers/staging/comedi/drivers/jr3_pci.h @@ -261,8 +261,9 @@ struct intern_transform { } link[8]; }; -/* JR3 force/torque sensor data definition. For more information see sensor and */ -/* hardware manuals. */ +/* JR3 force/torque sensor data definition. For more information see sensor + * and hardware manuals. + */ struct jr3_channel { /* Raw_channels is the area used to store the raw data coming from */ diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 77e94a34b51e..3c19e0f178ca 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -19,7 +19,7 @@ /* * Driver: ke_counter * Description: Driver for Kolter Electronic Counter Card - * Devices: (Kolter Electronic) PCI Counter Card [ke_counter] + * Devices: [Kolter Electronic] PCI Counter Card (ke_counter) * Author: Michael Hillmann * Updated: Mon, 14 Apr 2008 15:42:42 +0100 * Status: tested diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 915685c1c85c..d120aa244cf9 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1068,7 +1068,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) ME4000_AI_CTRL_BIT_SC_IRQ); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_ERROR; dev_err(dev->class_dev, "FIFO overflow\n"); } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) @@ -1089,7 +1089,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) ME4000_AI_CTRL_BIT_SC_IRQ); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_ERROR; dev_err(dev->class_dev, "Undefined FIFO state\n"); } diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index b5278c11e622..92e23527f2cb 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -19,8 +19,7 @@ /* * Driver: me_daq * Description: Meilhaus PCI data acquisition cards - * Devices: (Meilhaus) ME-2600i [me-2600i] - * (Meilhaus) ME-2000i [me-2000i] + * Devices: [Meilhaus] ME-2600i (me-2600i), ME-2000i (me-2000i) * Author: Michael Hillmann <hillmann@syscongroup.de> * Status: experimental * @@ -175,7 +174,7 @@ struct me_private_data { static inline void sleep(unsigned sec) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(sec * HZ); } diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c index af21bc180c46..db972bce2b5b 100644 --- a/drivers/staging/comedi/drivers/mf6x4.c +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -18,7 +18,7 @@ /* * Driver: mf6x4 * Description: Humusoft MF634 and MF624 Data acquisition card driver - * Devices: Humusoft MF634, Humusoft MF624 + * Devices: [Humusoft] MF634 (mf634), MF624 (mf624) * Author: Rostislav Lisovy <lisovy@gmail.com> * Status: works * Updated: diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index ffc9e61d6cdd..1e537a5cf862 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -494,9 +494,7 @@ EXPORT_SYMBOL_GPL(mite_bytes_read_from_memory_ub); unsigned mite_dma_tcr(struct mite_channel *mite_chan) { struct mite_struct *mite = mite_chan->mite; - int lkar; - lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); return readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel)); } EXPORT_SYMBOL_GPL(mite_dma_tcr); diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index f99847f3999f..530f716f6586 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -19,8 +19,7 @@ /* * Driver: ni_6527 * Description: National Instruments 6527 - * Devices: (National Instruments) PCI-6527 [pci-6527] - * (National Instruments) PXI-6527 [pxi-6527] + * Devices: [National Instruments] PCI-6527 (pci-6527), PXI-6527 (pxi-6527) * Author: David A. Schleef <ds@schleef.org> * Updated: Sat, 25 Jan 2003 13:24:40 -0800 * Status: works diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index bcb326e31562..67cb758eb0cd 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -25,28 +25,14 @@ * Author: Jon Grierson <jd@renko.co.uk>, * Frank Mori Hess <fmhess@users.sourceforge.net> * Status: testing - * Devices: (National Instruments) PCI-6509 [ni_65xx] - * (National Instruments) PXI-6509 [ni_65xx] - * (National Instruments) PCI-6510 [ni_65xx] - * (National Instruments) PCI-6511 [ni_65xx] - * (National Instruments) PXI-6511 [ni_65xx] - * (National Instruments) PCI-6512 [ni_65xx] - * (National Instruments) PXI-6512 [ni_65xx] - * (National Instruments) PCI-6513 [ni_65xx] - * (National Instruments) PXI-6513 [ni_65xx] - * (National Instruments) PCI-6514 [ni_65xx] - * (National Instruments) PXI-6514 [ni_65xx] - * (National Instruments) PCI-6515 [ni_65xx] - * (National Instruments) PXI-6515 [ni_65xx] - * (National Instruments) PCI-6516 [ni_65xx] - * (National Instruments) PCI-6517 [ni_65xx] - * (National Instruments) PCI-6518 [ni_65xx] - * (National Instruments) PCI-6519 [ni_65xx] - * (National Instruments) PCI-6520 [ni_65xx] - * (National Instruments) PCI-6521 [ni_65xx] - * (National Instruments) PXI-6521 [ni_65xx] - * (National Instruments) PCI-6528 [ni_65xx] - * (National Instruments) PXI-6528 [ni_65xx] + * Devices: [National Instruments] PCI-6509 (pci-6509), PXI-6509 (pxi-6509), + * PCI-6510 (pci-6510), PCI-6511 (pci-6511), PXI-6511 (pxi-6511), + * PCI-6512 (pci-6512), PXI-6512 (pxi-6512), PCI-6513 (pci-6513), + * PXI-6513 (pxi-6513), PCI-6514 (pci-6514), PXI-6514 (pxi-6514), + * PCI-6515 (pxi-6515), PXI-6515 (pxi-6515), PCI-6516 (pci-6516), + * PCI-6517 (pci-6517), PCI-6518 (pci-6518), PCI-6519 (pci-6519), + * PCI-6520 (pci-6520), PCI-6521 (pci-6521), PXI-6521 (pxi-6521), + * PCI-6528 (pci-6528), PXI-6528 (pxi-6528) * Updated: Mon, 21 Jul 2014 12:49:58 +0000 * * Configuration Options: not applicable, uses PCI auto config diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 69e543a0bf22..a1ce0b0b8c41 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -62,14 +62,13 @@ TRIG_WAKE_EOS #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/slab.h> -#include "../comedidev.h" - #include <linux/io.h> -#include <asm/dma.h> +#include "../comedidev.h" -#include "8253.h" +#include "comedi_isadma.h" #include "comedi_fc.h" +#include "8253.h" #define A2150_DMA_BUFFER_SIZE 0xff00 /* size in bytes of dma buffer */ @@ -146,11 +145,8 @@ static const struct a2150_board a2150_boards[] = { }; struct a2150_private { - - volatile unsigned int count; /* number of data points left to be taken */ - unsigned int dma; /* dma channel */ - uint16_t *dma_buffer; /* dma buffer */ - unsigned int dma_transfer_size; /* size in bytes of dma transfers */ + struct comedi_isadma *dma; + unsigned int count; /* number of data points left to be taken */ int irq_dma_bits; /* irq/dma register bits */ int config_bits; /* config register bits */ }; @@ -158,68 +154,54 @@ struct a2150_private { /* interrupt service routine */ static irqreturn_t a2150_interrupt(int irq, void *d) { - int i; - int status; - unsigned long flags; struct comedi_device *dev = d; struct a2150_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[0]; struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async; - struct comedi_cmd *cmd; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned short *buf = desc->virt_addr; unsigned int max_points, num_points, residue, leftover; unsigned short dpnt; + int status; + int i; - if (!dev->attached) { - dev_err(dev->class_dev, "premature interrupt\n"); + if (!dev->attached) return IRQ_HANDLED; - } - /* initialize async here to make sure s is not NULL */ - async = s->async; - cmd = &async->cmd; status = inw(dev->iobase + STATUS_REG); - - if ((status & INTR_BIT) == 0) { - dev_err(dev->class_dev, "spurious interrupt\n"); + if ((status & INTR_BIT) == 0) return IRQ_NONE; - } if (status & OVFL_BIT) { - dev_err(dev->class_dev, "fifo overflow\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); } if ((status & DMA_TC_BIT) == 0) { - dev_err(dev->class_dev, - "caught non-dma interrupt? Aborting.\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); return IRQ_HANDLED; } - flags = claim_dma_lock(); - disable_dma(devpriv->dma); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma); - - /* figure out how many points to read */ - max_points = comedi_bytes_to_samples(s, devpriv->dma_transfer_size); - /* residue is the number of points left to be done on the dma + /* + * residue is the number of bytes left to be done on the dma * transfer. It should always be zero at this point unless * the stop_src is set to external triggering. */ - residue = comedi_bytes_to_samples(s, get_dma_residue(devpriv->dma)); - num_points = max_points - residue; + residue = comedi_isadma_disable(desc->chan); + + /* figure out how many points to read */ + max_points = comedi_bytes_to_samples(s, desc->size); + num_points = max_points - comedi_bytes_to_samples(s, residue); if (devpriv->count < num_points && cmd->stop_src == TRIG_COUNT) num_points = devpriv->count; /* figure out how many points will be stored next time */ leftover = 0; if (cmd->stop_src == TRIG_NONE) { - leftover = comedi_bytes_to_samples(s, - devpriv->dma_transfer_size); + leftover = comedi_bytes_to_samples(s, desc->size); } else if (devpriv->count > max_points) { leftover = devpriv->count - max_points; if (leftover > max_points) @@ -234,7 +216,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) for (i = 0; i < num_points; i++) { /* write data point to comedi buffer */ - dpnt = devpriv->dma_buffer[i]; + dpnt = buf[i]; /* convert from 2's complement to unsigned coding */ dpnt ^= 0x8000; comedi_buf_write_samples(s, &dpnt, 1); @@ -245,14 +227,11 @@ static irqreturn_t a2150_interrupt(int irq, void *d) } } } - /* re-enable dma */ + /* re-enable dma */ if (leftover) { - set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer)); - set_dma_count(devpriv->dma, - comedi_samples_to_bytes(s, leftover)); - enable_dma(devpriv->dma); + desc->size = comedi_samples_to_bytes(s, leftover); + comedi_isadma_program(desc); } - release_dma_lock(flags); comedi_handle_events(dev, s); @@ -265,13 +244,15 @@ static irqreturn_t a2150_interrupt(int irq, void *d) static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct a2150_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[0]; /* disable dma on card */ devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT; outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); /* disable computer's dma */ - disable_dma(devpriv->dma); + comedi_isadma_disable(desc->chan); /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); @@ -503,10 +484,11 @@ static int a2150_ai_cmdtest(struct comedi_device *dev, static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct a2150_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[0]; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned long timer_base = dev->iobase + I8253_BASE_REG; - unsigned long lock_flags; unsigned int old_config_bits = devpriv->config_bits; unsigned int trigger_bits; @@ -542,27 +524,19 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* initialize number of samples remaining */ devpriv->count = cmd->stop_arg * cmd->chanlist_len; - /* enable computer's dma */ - lock_flags = claim_dma_lock(); - disable_dma(devpriv->dma); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer)); + comedi_isadma_disable(desc->chan); + /* set size of transfer to fill in 1/3 second */ #define ONE_THIRD_SECOND 333333333 - devpriv->dma_transfer_size = - sizeof(devpriv->dma_buffer[0]) * cmd->chanlist_len * - ONE_THIRD_SECOND / cmd->scan_begin_arg; - if (devpriv->dma_transfer_size > A2150_DMA_BUFFER_SIZE) - devpriv->dma_transfer_size = A2150_DMA_BUFFER_SIZE; - if (devpriv->dma_transfer_size < sizeof(devpriv->dma_buffer[0])) - devpriv->dma_transfer_size = sizeof(devpriv->dma_buffer[0]); - devpriv->dma_transfer_size -= - devpriv->dma_transfer_size % sizeof(devpriv->dma_buffer[0]); - set_dma_count(devpriv->dma, devpriv->dma_transfer_size); - enable_dma(devpriv->dma); - release_dma_lock(lock_flags); + desc->size = comedi_bytes_per_sample(s) * cmd->chanlist_len * + ONE_THIRD_SECOND / cmd->scan_begin_arg; + if (desc->size > desc->maxsize) + desc->size = desc->maxsize; + if (desc->size < comedi_bytes_per_sample(s)) + desc->size = comedi_bytes_per_sample(s); + desc->size -= desc->size % comedi_bytes_per_sample(s); + + comedi_isadma_program(desc); /* clear dma interrupt before enabling it, to try and get rid of that * one spurious interrupt that has been happening */ @@ -677,6 +651,45 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } +static void a2150_alloc_irq_and_dma(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct a2150_private *devpriv = dev->private; + unsigned int irq_num = it->options[1]; + unsigned int dma_chan = it->options[2]; + + /* + * Only IRQs 15, 14, 12-9, and 7-3 are valid. + * Only DMA channels 7-5 and 3-0 are valid. + */ + if (irq_num > 15 || dma_chan > 7 || + !((1 << irq_num) & 0xdef8) || !((1 << dma_chan) & 0xef)) + return; + + if (request_irq(irq_num, a2150_interrupt, 0, dev->board_name, dev)) + return; + + /* DMA uses 1 buffer */ + devpriv->dma = comedi_isadma_alloc(dev, 1, dma_chan, dma_chan, + A2150_DMA_BUFFER_SIZE, + COMEDI_ISADMA_READ); + if (!devpriv->dma) { + free_irq(irq_num, dev); + } else { + dev->irq = irq_num; + devpriv->irq_dma_bits = IRQ_LVL_BITS(irq_num) | + DMA_CHAN_BITS(dma_chan); + } +} + +static void a2150_free_dma(struct comedi_device *dev) +{ + struct a2150_private *devpriv = dev->private; + + if (devpriv) + comedi_isadma_free(devpriv->dma); +} + /* probes board type, returns offset */ static int a2150_probe(struct comedi_device *dev) { @@ -690,8 +703,6 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) const struct a2150_board *thisboard; struct a2150_private *devpriv; struct comedi_subdevice *s; - unsigned int irq = it->options[1]; - unsigned int dma = it->options[2]; static const int timeout = 2000; int i; int ret; @@ -712,31 +723,8 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) thisboard = dev->board_ptr; dev->board_name = thisboard->name; - if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) || - irq == 14 || irq == 15) { - ret = request_irq(irq, a2150_interrupt, 0, - dev->board_name, dev); - if (ret == 0) { - devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); - dev->irq = irq; - } - } - - if (dev->irq && dma <= 7 && dma != 4) { - ret = request_dma(dma, dev->board_name); - if (ret == 0) { - devpriv->dma = dma; - devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE, - GFP_KERNEL | GFP_DMA); - if (!devpriv->dma_buffer) - return -ENOMEM; - - disable_dma(dma); - set_dma_mode(dma, DMA_MODE_READ); - - devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); - } - } + /* an IRQ and DMA are required to support async commands */ + a2150_alloc_irq_and_dma(dev, it); ret = comedi_alloc_subdevices(dev, 1); if (ret) @@ -750,7 +738,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xffff; s->range_table = &range_a2150; s->insn_read = a2150_ai_rinsn; - if (dev->irq && devpriv->dma) { + if (dev->irq) { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; s->len_chanlist = s->n_chan; @@ -791,15 +779,9 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void a2150_detach(struct comedi_device *dev) { - struct a2150_private *devpriv = dev->private; - if (dev->iobase) outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG); - if (devpriv) { - if (devpriv->dma) - free_dma(devpriv->dma); - kfree(devpriv->dma_buffer); - } + a2150_free_dma(dev); comedi_legacy_detach(dev); }; diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 05370a4a74a5..9eeaf3c5a858 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -19,8 +19,7 @@ /* * Driver: ni_at_ao * Description: National Instruments AT-AO-6/10 - * Devices: (National Instruments) AT-AO-6 [at-ao-6] - * (National Instruments) AT-AO-10 [at-ao-10] + * Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10) * Status: should work * Author: David A. Schleef <ds@schleef.org> * Updated: Sun Dec 26 12:26:28 EST 2004 diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index 0c5ff287dcef..301f154be813 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -300,7 +300,6 @@ static int ni_atmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct ni_board_struct *boardtype; - struct ni_private *devpriv; struct pnp_dev *isapnp_dev; int ret; unsigned long iobase; @@ -310,7 +309,6 @@ static int ni_atmio_attach(struct comedi_device *dev, ret = ni_alloc_private(dev); if (ret) return ret; - devpriv = dev->private; iobase = it->options[0]; irq = it->options[1]; diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 5e472cb7fbd7..8f6396edd21c 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -51,10 +51,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> -#include "../comedidev.h" - -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> +#include "../comedi_pcmcia.h" /* daqcard700 registers */ #define DIO_W 0x04 /* WO 8bit */ diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 8cfabdbaa30c..a208cb348437 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -32,11 +32,7 @@ the PCMCIA interface. */ #include <linux/module.h> -#include "../comedidev.h" - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> +#include "../comedi_pcmcia.h" #include "8255.h" diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 1fbfdb4c80c0..a916047791b8 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -17,9 +17,8 @@ /* * Driver: ni_labpc * Description: National Instruments Lab-PC (& compatibles) - * Devices: (National Instruments) Lab-PC-1200 [lab-pc-1200] - * (National Instruments) Lab-PC-1200AI [lab-pc-1200ai] - * (National Instruments) Lab-PC+ [lab-pc+] + * Devices: [National Instruments] Lab-PC-1200 (lab-pc-1200), + * Lab-PC-1200AI (lab-pc-1200ai), Lab-PC+ (lab-pc+) * Author: Frank Mori Hess <fmhess@users.sourceforge.net> * Status: works * @@ -85,15 +84,10 @@ static const struct labpc_boardinfo labpc_boards[] = { static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct labpc_private *devpriv; unsigned int irq = it->options[1]; unsigned int dma_chan = it->options[2]; int ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_request_region(dev, it->options[0], 0x20); if (ret) return ret; @@ -110,11 +104,7 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void labpc_detach(struct comedi_device *dev) { - struct labpc_private *devpriv = dev->private; - - if (devpriv) - labpc_free_dma_chan(dev); - + labpc_free_dma_chan(dev); comedi_legacy_detach(dev); } diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h index ac2c01f9dfdc..be89ae479afc 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.h +++ b/drivers/staging/comedi/drivers/ni_labpc.h @@ -35,6 +35,8 @@ struct labpc_boardinfo { }; struct labpc_private { + struct comedi_isadma *dma; + /* number of data points left to be taken */ unsigned long long count; /* software copys of bits written to command registers */ @@ -61,11 +63,7 @@ struct labpc_private { * conversions */ unsigned int divisor_b1; - unsigned int dma_chan; /* dma channel to use */ - u16 *dma_buffer; /* buffer ai will dma into */ - phys_addr_t dma_addr; - /* transfer size in bytes for current transfer */ - unsigned int dma_transfer_size; + /* we are using dma/fifo-half-full/etc. */ enum transfer_type current_transfer; /* diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/staging/comedi/drivers/ni_labpc_common.c index d89d5852aeea..b88ee2614bfe 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_common.c +++ b/drivers/staging/comedi/drivers/ni_labpc_common.c @@ -368,10 +368,6 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, enum scan_mode mode) { struct labpc_private *devpriv = dev->private; - /* max value for 16 bit counter in mode 2 */ - const int max_counter_value = 0x10000; - /* min value for 16 bit counter in mode 2 */ - const int min_counter_value = 2; unsigned int base_period; unsigned int scan_period; unsigned int convert_period; @@ -388,11 +384,10 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, * clock speed on convert and scan counters) */ devpriv->divisor_b0 = (scan_period - 1) / - (I8254_OSC_BASE_2MHZ * max_counter_value) + 1; - if (devpriv->divisor_b0 < min_counter_value) - devpriv->divisor_b0 = min_counter_value; - if (devpriv->divisor_b0 > max_counter_value) - devpriv->divisor_b0 = max_counter_value; + (I8254_OSC_BASE_2MHZ * 0x10000) + 1; + + cfc_check_trigger_arg_min(&devpriv->divisor_b0, 2); + cfc_check_trigger_arg_max(&devpriv->divisor_b0, 0x10000); base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0; @@ -400,16 +395,16 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, switch (cmd->flags & CMDF_ROUND_MASK) { default: case CMDF_ROUND_NEAREST: - devpriv->divisor_a0 = - (convert_period + (base_period / 2)) / base_period; - devpriv->divisor_b1 = - (scan_period + (base_period / 2)) / base_period; + devpriv->divisor_a0 = DIV_ROUND_CLOSEST(convert_period, + base_period); + devpriv->divisor_b1 = DIV_ROUND_CLOSEST(scan_period, + base_period); break; case CMDF_ROUND_UP: - devpriv->divisor_a0 = - (convert_period + (base_period - 1)) / base_period; - devpriv->divisor_b1 = - (scan_period + (base_period - 1)) / base_period; + devpriv->divisor_a0 = DIV_ROUND_UP(convert_period, + base_period); + devpriv->divisor_b1 = DIV_ROUND_UP(scan_period, + base_period); break; case CMDF_ROUND_DOWN: devpriv->divisor_a0 = convert_period / base_period; @@ -417,14 +412,10 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, break; } /* make sure a0 and b1 values are acceptable */ - if (devpriv->divisor_a0 < min_counter_value) - devpriv->divisor_a0 = min_counter_value; - if (devpriv->divisor_a0 > max_counter_value) - devpriv->divisor_a0 = max_counter_value; - if (devpriv->divisor_b1 < min_counter_value) - devpriv->divisor_b1 = min_counter_value; - if (devpriv->divisor_b1 > max_counter_value) - devpriv->divisor_b1 = max_counter_value; + cfc_check_trigger_arg_min(&devpriv->divisor_a0, 2); + cfc_check_trigger_arg_max(&devpriv->divisor_a0, 0x10000); + cfc_check_trigger_arg_min(&devpriv->divisor_b1, 2); + cfc_check_trigger_arg_max(&devpriv->divisor_b1, 0x10000); /* write corrected timings to command */ labpc_set_ai_convert_period(cmd, mode, base_period * devpriv->divisor_a0); @@ -687,7 +678,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* figure out what method we will use to transfer data */ - if (labpc_have_dma_chan(dev) && + if (devpriv->dma && /* dma unsafe at RT priority, * and too much setup time for CMDF_WAKE_EOS */ (cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY)) == 0) @@ -823,7 +814,7 @@ static int labpc_drain_fifo(struct comedi_device *dev) } if (i == timeout) { dev_err(dev->class_dev, "ai timeout, fifo never empties\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; return -1; } @@ -875,7 +866,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) if (devpriv->stat1 & STAT1_OVERRUN) { /* clear error interrupt */ devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); dev_err(dev->class_dev, "overrun\n"); return IRQ_HANDLED; @@ -895,7 +886,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) if (devpriv->stat1 & STAT1_OVERFLOW) { /* clear error interrupt */ devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); dev_err(dev->class_dev, "overflow\n"); return IRQ_HANDLED; @@ -1215,11 +1206,15 @@ int labpc_common_attach(struct comedi_device *dev, unsigned int irq, unsigned long isr_flags) { const struct labpc_boardinfo *board = dev->board_ptr; - struct labpc_private *devpriv = dev->private; + struct labpc_private *devpriv; struct comedi_subdevice *s; int ret; int i; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + if (dev->mmio) { devpriv->read_byte = labpc_readb; devpriv->write_byte = labpc_writeb; diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index 0a8b3223f74e..746c4cd9978d 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -54,19 +54,11 @@ NI manuals: */ #include <linux/module.h> -#include "../comedidev.h" -#include <linux/delay.h> +#include "../comedi_pcmcia.h" -#include "8253.h" -#include "8255.h" -#include "comedi_fc.h" #include "ni_labpc.h" -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - static const struct labpc_boardinfo labpc_cs_boards[] = { { .name = "daqcard-1200", @@ -80,7 +72,6 @@ static int labpc_auto_attach(struct comedi_device *dev, unsigned long context) { struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); - struct labpc_private *devpriv; int ret; /* The ni_labpc driver needs the board_ptr */ @@ -96,10 +87,6 @@ static int labpc_auto_attach(struct comedi_device *dev, if (!link->irq) return -EINVAL; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - return labpc_common_attach(dev, link->irq, IRQF_SHARED); } diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c index 6d386050e59d..6b4ccd86b3d0 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c @@ -19,23 +19,25 @@ #include <linux/module.h> #include <linux/slab.h> -#include "../comedidev.h" -#include <asm/dma.h> +#include "../comedidev.h" +#include "comedi_isadma.h" #include "comedi_fc.h" #include "ni_labpc.h" #include "ni_labpc_regs.h" #include "ni_labpc_isadma.h" /* size in bytes of dma buffer */ -static const int dma_buffer_size = 0xff00; -/* 2 bytes per sample */ -static const int sample_size = 2; +#define LABPC_ISADMA_BUFFER_SIZE 0xff00 /* utility function that suggests a dma transfer size in bytes */ -static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd) +static unsigned int labpc_suggest_transfer_size(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int maxbytes) { + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int sample_size = comedi_bytes_per_sample(s); unsigned int size; unsigned int freq; @@ -49,8 +51,8 @@ static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd) size = (freq / 3) * sample_size; /* set a minimum and maximum size allowed */ - if (size > dma_buffer_size) - size = dma_buffer_size - dma_buffer_size % sample_size; + if (size > maxbytes) + size = maxbytes; else if (size < sample_size) size = sample_size; @@ -60,23 +62,18 @@ static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd) void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s) { struct labpc_private *devpriv = dev->private; + struct comedi_isadma_desc *desc = &devpriv->dma->desc[0]; struct comedi_cmd *cmd = &s->async->cmd; - unsigned long irq_flags; - - irq_flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma_chan); - set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); + unsigned int sample_size = comedi_bytes_per_sample(s); + /* set appropriate size of transfer */ - devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd); + desc->size = labpc_suggest_transfer_size(dev, s, desc->maxsize); if (cmd->stop_src == TRIG_COUNT && - devpriv->count * sample_size < devpriv->dma_transfer_size) - devpriv->dma_transfer_size = devpriv->count * sample_size; - set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_chan); - release_dma_lock(irq_flags); + devpriv->count * sample_size < desc->size) + desc->size = devpriv->count * sample_size; + + comedi_isadma_program(desc); + /* set CMD3 bits for caller to enable DMA and interrupt */ devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN); } @@ -85,61 +82,55 @@ EXPORT_SYMBOL_GPL(labpc_setup_dma); void labpc_drain_dma(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; + struct comedi_isadma_desc *desc = &devpriv->dma->desc[0]; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - int status; - unsigned long flags; - unsigned int max_points, num_points, residue, leftover; + unsigned int max_samples = comedi_bytes_to_samples(s, desc->size); + unsigned int residue; + unsigned int nsamples; + unsigned int leftover; - status = devpriv->stat1; - - flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma_chan); - - /* figure out how many points to read */ - max_points = devpriv->dma_transfer_size / sample_size; - /* residue is the number of points left to be done on the dma + /* + * residue is the number of bytes left to be done on the dma * transfer. It should always be zero at this point unless * the stop_src is set to external triggering. */ - residue = get_dma_residue(devpriv->dma_chan) / sample_size; - num_points = max_points - residue; - if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_points) - num_points = devpriv->count; - - /* figure out how many points will be stored next time */ - leftover = 0; - if (cmd->stop_src != TRIG_COUNT) { - leftover = devpriv->dma_transfer_size / sample_size; - } else if (devpriv->count > num_points) { - leftover = devpriv->count - num_points; - if (leftover > max_points) - leftover = max_points; - } - - comedi_buf_write_samples(s, devpriv->dma_buffer, num_points); + residue = comedi_isadma_disable(desc->chan); - if (cmd->stop_src == TRIG_COUNT) - devpriv->count -= num_points; + /* + * Figure out how many samples to read for this transfer and + * how many will be stored for next time. + */ + nsamples = max_samples - comedi_bytes_to_samples(s, residue); + if (cmd->stop_src == TRIG_COUNT) { + if (devpriv->count <= nsamples) { + nsamples = devpriv->count; + leftover = 0; + } else { + leftover = devpriv->count - nsamples; + if (leftover > max_samples) + leftover = max_samples; + } + devpriv->count -= nsamples; + } else { + leftover = max_samples; + } + desc->size = comedi_samples_to_bytes(s, leftover); - /* set address and count for next transfer */ - set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); - set_dma_count(devpriv->dma_chan, leftover * sample_size); - release_dma_lock(flags); + comedi_buf_write_samples(s, desc->virt_addr, nsamples); } EXPORT_SYMBOL_GPL(labpc_drain_dma); static void handle_isa_dma(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; + struct comedi_isadma_desc *desc = &devpriv->dma->desc[0]; labpc_drain_dma(dev); - enable_dma(devpriv->dma_chan); + if (desc->size) + comedi_isadma_program(desc); /* clear dma tc interrupt */ devpriv->write_byte(dev, 0x1, DMATC_CLEAR_REG); @@ -160,36 +151,18 @@ void labpc_handle_dma_status(struct comedi_device *dev) } EXPORT_SYMBOL_GPL(labpc_handle_dma_status); -int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan) +void labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan) { struct labpc_private *devpriv = dev->private; - void *dma_buffer; - unsigned long dma_flags; - int ret; + /* only DMA channels 3 and 1 are valid */ if (dma_chan != 1 && dma_chan != 3) - return -EINVAL; - - dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); - if (!dma_buffer) - return -ENOMEM; - - ret = request_dma(dma_chan, dev->board_name); - if (ret) { - kfree(dma_buffer); - return ret; - } - - devpriv->dma_buffer = dma_buffer; - devpriv->dma_chan = dma_chan; - devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer); - - dma_flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); - release_dma_lock(dma_flags); + return; - return 0; + /* DMA uses 1 buffer */ + devpriv->dma = comedi_isadma_alloc(dev, 1, dma_chan, dma_chan, + LABPC_ISADMA_BUFFER_SIZE, + COMEDI_ISADMA_READ); } EXPORT_SYMBOL_GPL(labpc_init_dma_chan); @@ -197,12 +170,8 @@ void labpc_free_dma_chan(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - kfree(devpriv->dma_buffer); - devpriv->dma_buffer = NULL; - if (devpriv->dma_chan) { - free_dma(devpriv->dma_chan); - devpriv->dma_chan = 0; - } + if (devpriv) + comedi_isadma_free(devpriv->dma); } EXPORT_SYMBOL_GPL(labpc_free_dma_chan); diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/staging/comedi/drivers/ni_labpc_isadma.h index 771af4bd5a76..b8a1b0ee6290 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_isadma.h +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.h @@ -5,18 +5,9 @@ #ifndef _NI_LABPC_ISADMA_H #define _NI_LABPC_ISADMA_H -#define NI_LABPC_HAVE_ISA_DMA IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA) +#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA) -#if NI_LABPC_HAVE_ISA_DMA - -static inline bool labpc_have_dma_chan(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - - return (bool)devpriv->dma_chan; -} - -int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan); +void labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan); void labpc_free_dma_chan(struct comedi_device *dev); void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s); void labpc_drain_dma(struct comedi_device *dev); @@ -24,15 +15,9 @@ void labpc_handle_dma_status(struct comedi_device *dev); #else -static inline bool labpc_have_dma_chan(struct comedi_device *dev) -{ - return false; -} - -static inline int labpc_init_dma_chan(struct comedi_device *dev, - unsigned int dma_chan) +static inline void labpc_init_dma_chan(struct comedi_device *dev, + unsigned int dma_chan) { - return -ENOTSUPP; } static inline void labpc_free_dma_chan(struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c index 3fc420406564..0407ff681dfd 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_pci.c +++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c @@ -17,7 +17,7 @@ /* * Driver: ni_labpc_pci * Description: National Instruments Lab-PC PCI-1200 - * Devices: (National Instruments) PCI-1200 [ni_pci-1200] + * Devices: [National Instruments] PCI-1200 (ni_pci-1200) * Author: Frank Mori Hess <fmhess@users.sourceforge.net> * Status: works * @@ -79,7 +79,6 @@ static int labpc_pci_auto_attach(struct comedi_device *dev, { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct labpc_boardinfo *board = NULL; - struct labpc_private *devpriv; int ret; if (context < ARRAY_SIZE(labpc_pci_boards)) @@ -101,10 +100,6 @@ static int labpc_pci_auto_attach(struct comedi_device *dev, if (!dev->mmio) return -ENOMEM; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - return labpc_common_attach(dev, pcidev->irq, IRQF_SHARED); } diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 11e70173712d..b6ddc015dedf 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1478,7 +1478,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, dev_err(dev->class_dev, "unknown mite interrupt (ai_mite_status=%08x)\n", ai_mite_status); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_ERROR; /* disable_irq(dev->irq); */ } #endif @@ -1491,8 +1491,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, /* we probably aren't even running a command now, * so it's a good idea to be careful. */ if (comedi_is_subdevice_running(s)) { - s->async->events |= - COMEDI_CB_ERROR | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_ERROR; comedi_handle_events(dev, s); } return; @@ -1579,7 +1578,7 @@ static void handle_b_interrupt(struct comedi_device *dev, dev_err(dev->class_dev, "unknown mite interrupt (ao_mite_status=%08x)\n", ao_mite_status); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + s->async->events |= COMEDI_CB_ERROR; } #endif diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index 9b201e48233e..e3d821bf2d6a 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -37,16 +37,12 @@ See the notes in the ni_atmio.o driver. */ #include <linux/module.h> -#include "../comedidev.h" - #include <linux/delay.h> +#include "../comedi_pcmcia.h" #include "ni_stc.h" #include "8255.h" -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> - /* * AT specific setup */ @@ -163,7 +159,6 @@ static int mio_cs_auto_attach(struct comedi_device *dev, { struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); static const struct ni_board_struct *board; - struct ni_private *devpriv; int ret; board = ni_getboardtype(dev, link); @@ -188,8 +183,6 @@ static int mio_cs_auto_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = dev->private; - return ni_E_init(dev, 0, 1); } diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index db7e8aac67b5..db399fe8c301 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -418,7 +418,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) CHSR_DRQ1 | CHSR_MRDY)) { dev_dbg(dev->class_dev, "unknown mite interrupt, disabling IRQ\n"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + async->events |= COMEDI_CB_ERROR; disable_irq(dev->irq); } } @@ -460,7 +460,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) break; } else if (flags & Waited) { writeb(ClearWaited, dev->mmio + Group_1_First_Clear); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + async->events |= COMEDI_CB_ERROR; break; } else if (flags & PrimaryTC) { writeb(ClearPrimaryTC, diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c index 0525292c1d8b..c20c51bef3e7 100644 --- a/drivers/staging/comedi/drivers/ni_tio.c +++ b/drivers/staging/comedi/drivers/ni_tio.c @@ -16,29 +16,28 @@ */ /* -Driver: ni_tio -Description: National Instruments general purpose counters -Devices: -Author: J.P. Mellor <jpmellor@rose-hulman.edu>, - Herman.Bruyninckx@mech.kuleuven.ac.be, - Wim.Meeussen@mech.kuleuven.ac.be, - Klaas.Gadeyne@mech.kuleuven.ac.be, - Frank Mori Hess <fmhess@users.sourceforge.net> -Updated: Thu Nov 16 09:50:32 EST 2006 -Status: works - -This module is not used directly by end-users. Rather, it -is used by other drivers (for example ni_660x and ni_pcimio) -to provide support for NI's general purpose counters. It was -originally based on the counter code from ni_660x.c and -ni_mio_common.c. - -References: -DAQ 660x Register-Level Programmer Manual (NI 370505A-01) -DAQ 6601/6602 User Manual (NI 322137B-01) -340934b.pdf DAQ-STC reference manual + * Module: ni_tio + * Description: National Instruments general purpose counters + * Author: J.P. Mellor <jpmellor@rose-hulman.edu>, + * Herman.Bruyninckx@mech.kuleuven.ac.be, + * Wim.Meeussen@mech.kuleuven.ac.be, + * Klaas.Gadeyne@mech.kuleuven.ac.be, + * Frank Mori Hess <fmhess@users.sourceforge.net> + * Updated: Thu Nov 16 09:50:32 EST 2006 + * Status: works + * + * This module is not used directly by end-users. Rather, it + * is used by other drivers (for example ni_660x and ni_pcimio) + * to provide support for NI's general purpose counters. It was + * originally based on the counter code from ni_660x.c and + * ni_mio_common.c. + * + * References: + * DAQ 660x Register-Level Programmer Manual (NI 370505A-01) + * DAQ 6601/6602 User Manual (NI 322137B-01) + * 340934b.pdf DAQ-STC reference manual + */ -*/ /* TODO: Support use of both banks X and Y diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 6037bec77ef1..d36c3abd3120 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -16,29 +16,28 @@ */ /* -Driver: ni_tiocmd -Description: National Instruments general purpose counters command support -Devices: -Author: J.P. Mellor <jpmellor@rose-hulman.edu>, - Herman.Bruyninckx@mech.kuleuven.ac.be, - Wim.Meeussen@mech.kuleuven.ac.be, - Klaas.Gadeyne@mech.kuleuven.ac.be, - Frank Mori Hess <fmhess@users.sourceforge.net> -Updated: Fri, 11 Apr 2008 12:32:35 +0100 -Status: works - -This module is not used directly by end-users. Rather, it -is used by other drivers (for example ni_660x and ni_pcimio) -to provide command support for NI's general purpose counters. -It was originally split out of ni_tio.c to stop the 'ni_tio' -module depending on the 'mite' module. - -References: -DAQ 660x Register-Level Programmer Manual (NI 370505A-01) -DAQ 6601/6602 User Manual (NI 322137B-01) -340934b.pdf DAQ-STC reference manual + * Module: ni_tiocmd + * Description: National Instruments general purpose counters command support + * Author: J.P. Mellor <jpmellor@rose-hulman.edu>, + * Herman.Bruyninckx@mech.kuleuven.ac.be, + * Wim.Meeussen@mech.kuleuven.ac.be, + * Klaas.Gadeyne@mech.kuleuven.ac.be, + * Frank Mori Hess <fmhess@users.sourceforge.net> + * Updated: Fri, 11 Apr 2008 12:32:35 +0100 + * Status: works + * + * This module is not used directly by end-users. Rather, it + * is used by other drivers (for example ni_660x and ni_pcimio) + * to provide command support for NI's general purpose counters. + * It was originally split out of ni_tio.c to stop the 'ni_tio' + * module depending on the 'mite' module. + * + * References: + * DAQ 660x Register-Level Programmer Manual (NI 370505A-01) + * DAQ 6601/6602 User Manual (NI 322137B-01) + * 340934b.pdf DAQ-STC reference manual + */ -*/ /* TODO: Support use of both banks X and Y diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c index 3b5a1b90366d..5f649f88d55c 100644 --- a/drivers/staging/comedi/drivers/ni_usb6501.c +++ b/drivers/staging/comedi/drivers/ni_usb6501.c @@ -96,9 +96,8 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/usb.h> -#include "../comedidev.h" +#include "../comedi_usb.h" #define NI6501_TIMEOUT 1000 diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index 938aebc8e0ea..cb7e4c37b8b9 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -22,10 +22,8 @@ /* * Driver: pcl711 * Description: Advantech PCL-711 and 711b, ADLink ACL-8112 - * Devices: (Advantech) PCL-711 [pcl711] - * (Advantech) PCL-711B [pcl711b] - * (AdLink) ACL-8112HG [acl8112hg] - * (AdLink) ACL-8112DG [acl8112dg] + * Devices: [Advantech] PCL-711 (pcl711), PCL-711B (pcl711b), + * [ADLink] ACL-8112HG (acl8112hg), ACL-8112DG (acl8112dg) * Author: David A. Schleef <ds@schleef.org> * Janne Jalkanen <jalkanen@cs.hut.fi> * Eric Bunn <ebu@cs.hut.fi> diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c index fcc440855e66..74b07e1744c7 100644 --- a/drivers/staging/comedi/drivers/pcl724.c +++ b/drivers/staging/comedi/drivers/pcl724.c @@ -8,14 +8,10 @@ /* * Driver: pcl724 * Description: Comedi driver for 8255 based ISA DIO boards - * Devices: (Advantech) PCL-724 [pcl724] - * (Advantech) PCL-722 [pcl722] - * (Advantech) PCL-731 [pcl731] - * (ADLink) ACL-7122 [acl7122] - * (ADLink) ACL-7124 [acl7124] - * (ADLink) PET-48DIO [pet48dio] - * (WinSystems) PCM-IO48 [pcmio48] - * (Diamond Systems) ONYX-MM-DIO [onyx-mm-dio] + * Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731), + * [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio), + * [WinSystems] PCM-IO48 (pcmio48), + * [Diamond Systems] ONYX-MM-DIO (onyx-mm-dio) * Author: Michal Dobes <dobes@tesnet.cz> * Status: untested * diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index 86f713fdf1d0..40798150cfd8 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -21,11 +21,8 @@ * Description: Advantech PCL-726 & compatibles * Author: David A. Schleef <ds@schleef.org> * Status: untested - * Devices: (Advantech) PCL-726 [pcl726] - * (Advantech) PCL-727 [pcl727] - * (Advantech) PCL-728 [pcl728] - * (ADLink) ACL-6126 [acl6126] - * (ADLink) ACL-6128 [acl6128] + * Devices: [Advantech] PCL-726 (pcl726), PCL-727 (pcl727), PCL-728 (pcl728), + * [ADLink] ACL-6126 (acl6126), ACL-6128 (acl6128) * * Configuration Options: * [0] - IO Base diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index a6c5770b2808..ce958eef2a61 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -7,19 +7,12 @@ /* * Driver: pcl730 * Description: Advantech PCL-730 (& compatibles) - * Devices: (Advantech) PCL-730 [pcl730] - * (ICP) ISO-730 [iso730] - * (Adlink) ACL-7130 [acl7130] - * (Advantech) PCM-3730 [pcm3730] - * (Advantech) PCL-725 [pcl725] - * (ICP) P8R8-DIO [p16r16dio] - * (Adlink) ACL-7225b [acl7225b] - * (ICP) P16R16-DIO [p16r16dio] - * (Advantech) PCL-733 [pcl733] - * (Advantech) PCL-734 [pcl734] - * (Diamond Systems) OPMM-1616-XT [opmm-1616-xt] - * (Diamond Systems) PEARL-MM-P [prearl-mm-p] - * (Diamond Systems) IR104-PBF [ir104-pbf] + * Devices: [Advantech] PCL-730 (pcl730), PCM-3730 (pcm3730), PCL-725 (pcl725), + * PCL-733 (pcl733), PCL-734 (pcl734), + * [ADLink] ACL-7130 (acl7130), ACL-7225b (acl7225b), + * [ICP] ISO-730 (iso730), P8R8-DIO (p8r8dio), P16R16-DIO (p16r16dio), + * [Diamond Systems] OPMM-1616-XT (opmm-1616-xt), PEARL-MM-P (pearl-mm-p), + * IR104-PBF (ir104-pbf), * Author: José Luis Sánchez (jsanchezv@teleline.es) * Status: untested * diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index ac243ca5e0f8..3ffb1ea2ecc8 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -111,12 +111,12 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/gfp.h> -#include "../comedidev.h" - #include <linux/delay.h> #include <linux/io.h> -#include <asm/dma.h> +#include "../comedidev.h" + +#include "comedi_isadma.h" #include "comedi_fc.h" #include "8253.h" @@ -507,19 +507,11 @@ static const struct pcl812_board boardtypes[] = { }; struct pcl812_private { - unsigned char dma; /* >0 use dma ( usedDMA channel) */ + struct comedi_isadma *dma; unsigned char range_correction; /* =1 we must add 1 to range number */ unsigned int last_ai_chanspec; unsigned char mode_reg_int; /* there is stored INT number for some card */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - unsigned int dmapages; - unsigned int hwdmasize; - unsigned long dmabuf[2]; /* PTR to DMA buf */ - unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ - 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 divisor1; unsigned int divisor2; @@ -546,90 +538,32 @@ static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers) } static void pcl812_ai_setup_dma(struct comedi_device *dev, - struct comedi_subdevice *s) + struct comedi_subdevice *s, + unsigned int unread_samples) { struct pcl812_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - unsigned int dma_flags; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; unsigned int bytes; + unsigned int max_samples; + unsigned int nsamples; - /* we use EOS, so adapt DMA buffer to one scan */ - if (devpriv->ai_eos) { - devpriv->dmabytestomove[0] = comedi_bytes_per_scan(s); - devpriv->dmabytestomove[1] = comedi_bytes_per_scan(s); - devpriv->dma_runs_to_end = 1; - } else { - devpriv->dmabytestomove[0] = devpriv->hwdmasize; - devpriv->dmabytestomove[1] = devpriv->hwdmasize; - if (s->async->prealloc_bufsz < devpriv->hwdmasize) { - devpriv->dmabytestomove[0] = - s->async->prealloc_bufsz; - devpriv->dmabytestomove[1] = - s->async->prealloc_bufsz; - } - if (cmd->stop_src == TRIG_NONE) { - devpriv->dma_runs_to_end = 1; - } else { - /* how many samples we must transfer? */ - bytes = cmd->stop_arg * comedi_bytes_per_scan(s); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = - bytes / devpriv->dmabytestomove[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = - bytes % devpriv->dmabytestomove[0]; - if (devpriv->dma_runs_to_end == 0) - devpriv->dmabytestomove[0] = - devpriv->last_dma_run; - devpriv->dma_runs_to_end--; - } - } - if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) { - devpriv->dmabytestomove[0] = devpriv->hwdmasize; - devpriv->ai_eos = 0; - } - if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) { - devpriv->dmabytestomove[1] = devpriv->hwdmasize; - devpriv->ai_eos = 0; - } - 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); -} + comedi_isadma_disable(dma->chan); -static void pcl812_ai_setup_next_dma(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl812_private *devpriv = dev->private; - unsigned long dma_flags; - - 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--; + /* if using EOS, adapt DMA buffer to one scan */ + bytes = devpriv->ai_eos ? comedi_bytes_per_scan(s) : desc->maxsize; + max_samples = comedi_bytes_to_samples(s, bytes); + + /* + * Determine dma size based on the buffer size plus the number of + * unread samples and the number of samples remaining in the command. + */ + nsamples = comedi_nsamples_left(s, max_samples + unread_samples); + if (nsamples > unread_samples) { + nsamples -= unread_samples; + desc->size = comedi_samples_to_bytes(s, nsamples); + comedi_isadma_program(desc); } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); } static void pcl812_ai_set_chan_range(struct comedi_device *dev, @@ -786,6 +720,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_cmd *cmd = &s->async->cmd; unsigned int ctrl = 0; unsigned int i; @@ -794,7 +729,7 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1); - if (devpriv->dma) { /* check if we can use DMA transfer */ + if (dma) { /* check if we can use DMA transfer */ devpriv->ai_dma = 1; for (i = 1; i < cmd->chanlist_len; i++) if (cmd->chanlist[0] != cmd->chanlist[i]) { @@ -817,8 +752,11 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_dma = 0; } - if (devpriv->ai_dma) - pcl812_ai_setup_dma(dev, s); + if (devpriv->ai_dma) { + /* setup and enable dma for the first buffer */ + dma->cur_dma = 0; + pcl812_ai_setup_dma(dev, s, 0); + } switch (cmd->convert_src) { case TRIG_TIMER: @@ -859,7 +797,7 @@ static void pcl812_handle_eoc(struct comedi_device *dev, if (pcl812_ai_eoc(dev, s, NULL, 0)) { dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + s->async->events |= COMEDI_CB_ERROR; return; } @@ -895,19 +833,21 @@ static void pcl812_handle_dma(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; - int len, bufptr; - unsigned short *ptr; - - ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; - len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - - devpriv->ai_poll_ptr; - - pcl812_ai_setup_next_dma(dev, s); + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned int nsamples; + int bufptr; + nsamples = comedi_bytes_to_samples(s, desc->size) - + devpriv->ai_poll_ptr; bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; - transfer_from_dma_buf(dev, s, ptr, bufptr, len); + /* restart dma with the next buffer */ + dma->cur_dma = 1 - dma->cur_dma; + pcl812_ai_setup_dma(dev, s, nsamples); + + transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples); } static irqreturn_t pcl812_interrupt(int irq, void *d) @@ -935,45 +875,37 @@ static irqreturn_t pcl812_interrupt(int irq, void *d) static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc; unsigned long flags; - unsigned int top1, top2, i; + unsigned int poll; + int ret; + /* poll is valid only for DMA transfer */ if (!devpriv->ai_dma) - return 0; /* poll is valid only for DMA transfer */ + return 0; spin_lock_irqsave(&dev->spinlock, flags); - for (i = 0; i < 10; i++) { - /* where is now DMA */ - top1 = get_dma_residue(devpriv->ai_dma); - top2 = get_dma_residue(devpriv->ai_dma); - if (top1 == top2) - break; - } - - if (top1 != top2) { - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; - } - /* where is now DMA in buffer */ - top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1; - top1 >>= 1; /* sample position */ - top2 = top1 - devpriv->ai_poll_ptr; - if (top2 < 1) { /* no new samples */ - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; + poll = comedi_isadma_poll(dma); + poll = comedi_bytes_to_samples(s, poll); + if (poll > devpriv->ai_poll_ptr) { + desc = &dma->desc[dma->cur_dma]; + transfer_from_dma_buf(dev, s, desc->virt_addr, + devpriv->ai_poll_ptr, + poll - devpriv->ai_poll_ptr); + /* new buffer position */ + devpriv->ai_poll_ptr = poll; + + ret = comedi_buf_n_bytes_ready(s); + } else { + /* no new samples */ + ret = 0; } - transfer_from_dma_buf(dev, s, - (void *)devpriv->dmabuf[1 - - devpriv->next_dma_buf], - devpriv->ai_poll_ptr, top2); - - devpriv->ai_poll_ptr = top1; /* new buffer position */ - spin_unlock_irqrestore(&dev->spinlock, flags); - return comedi_buf_n_bytes_ready(s); + return ret; } static int pcl812_ai_cancel(struct comedi_device *dev, @@ -982,7 +914,7 @@ static int pcl812_ai_cancel(struct comedi_device *dev, struct pcl812_private *devpriv = dev->private; if (devpriv->ai_dma) - disable_dma(devpriv->dma); + comedi_isadma_disable(devpriv->dma->chan); outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, dev->iobase + PCL812_CTRL_REG); @@ -1192,6 +1124,27 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev, } } +static void pcl812_alloc_dma(struct comedi_device *dev, unsigned int dma_chan) +{ + struct pcl812_private *devpriv = dev->private; + + /* only DMA channels 3 and 1 are valid */ + if (!(dma_chan == 3 || dma_chan == 1)) + return; + + /* DMA uses two 8K buffers */ + devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan, + PAGE_SIZE * 2, COMEDI_ISADMA_READ); +} + +static void pcl812_free_dma(struct comedi_device *dev) +{ + struct pcl812_private *devpriv = dev->private; + + if (devpriv) + comedi_isadma_free(devpriv->dma); +} + static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl812_board *board = dev->board_ptr; @@ -1200,7 +1153,6 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) int n_subdevices; int subdev; int ret; - int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -1218,31 +1170,8 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) } /* we need an IRQ to do DMA on channel 3 or 1 */ - if (dev->irq && board->has_dma && - (it->options[2] == 3 || it->options[2] == 1)) { - ret = request_dma(it->options[2], dev->board_name); - if (ret) { - dev_err(dev->class_dev, - "unable to request DMA channel %d\n", - it->options[2]); - return -EBUSY; - } - devpriv->dma = it->options[2]; - - 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); - } - } + if (dev->irq && board->has_dma) + pcl812_alloc_dma(dev, it->options[2]); /* differential analog inputs? */ switch (board->board_type) { @@ -1384,16 +1313,7 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void pcl812_detach(struct comedi_device *dev) { - struct pcl812_private *devpriv = dev->private; - - if (devpriv) { - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages); - if (devpriv->dma) - free_dma(devpriv->dma); - } + pcl812_free_dma(dev); comedi_legacy_detach(dev); } diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index 73deb4bd5c93..da35edfccbc3 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -33,14 +33,14 @@ Configuration Options: */ #include <linux/module.h> -#include "../comedidev.h" - #include <linux/gfp.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/interrupt.h> -#include <asm/dma.h> +#include "../comedidev.h" + +#include "comedi_isadma.h" #include "comedi_fc.h" #include "8253.h" @@ -114,14 +114,7 @@ static const struct pcl816_board boardtypes[] = { }; 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 hwdmaptr[2]; /* hardware address of DMA buffers */ - 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 */ + struct comedi_isadma *dma; unsigned int ai_poll_ptr; /* how many sampes transfer poll */ unsigned int divisor1; unsigned int divisor2; @@ -149,63 +142,27 @@ static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters) } static void pcl816_ai_setup_dma(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl816_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - unsigned int dma_flags; - unsigned int bytes; - - bytes = devpriv->hwdmasize; - if (cmd->stop_src == TRIG_COUNT) { - /* how many */ - bytes = cmd->stop_arg * comedi_bytes_per_scan(s); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize; - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize; - } else - devpriv->dma_runs_to_end = -1; - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); -} - -static void pcl816_ai_setup_next_dma(struct comedi_device *dev, - struct comedi_subdevice *s) + struct comedi_subdevice *s, + unsigned int unread_samples) { 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); + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize); + unsigned int nsamples; + + comedi_isadma_disable(dma->chan); + + /* + * Determine dma size based on the buffer maxsize plus the number of + * unread samples and the number of samples remaining in the command. + */ + nsamples = comedi_nsamples_left(s, max_samples + unread_samples); + if (nsamples > unread_samples) { + nsamples -= unread_samples; + desc->size = comedi_samples_to_bytes(s, nsamples); + comedi_isadma_program(desc); } - - devpriv->dma_runs_to_end--; } static void pcl816_ai_set_chan_range(struct comedi_device *dev, @@ -318,9 +275,10 @@ static irqreturn_t pcl816_interrupt(int irq, void *d) struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; struct pcl816_private *devpriv = dev->private; - unsigned short *ptr; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned int nsamples; unsigned int bufptr; - unsigned int len; if (!dev->attached || !devpriv->ai_cmd_running) { pcl816_ai_clear_eoc(dev); @@ -333,15 +291,16 @@ static irqreturn_t pcl816_interrupt(int irq, void *d) return IRQ_HANDLED; } - ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; - - pcl816_ai_setup_next_dma(dev, s); - - len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr; + nsamples = comedi_bytes_to_samples(s, desc->size) - + devpriv->ai_poll_ptr; bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; - transfer_from_dma_buf(dev, s, ptr, bufptr, len); + /* restart dma with the next buffer */ + dma->cur_dma = 1 - dma->cur_dma; + pcl816_ai_setup_dma(dev, s, nsamples); + + transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples); pcl816_ai_clear_eoc(dev); @@ -483,6 +442,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_cmd *cmd = &s->async->cmd; unsigned int ctrl; unsigned int seglen; @@ -502,7 +462,9 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_poll_ptr = 0; devpriv->ai_cmd_canceled = 0; - pcl816_ai_setup_dma(dev, s); + /* setup and enable dma for the first buffer */ + dma->cur_dma = 0; + pcl816_ai_setup_dma(dev, s, 0); pcl816_start_pacer(dev, true); @@ -513,7 +475,8 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) ctrl |= PCL816_CTRL_EXT_TRIG; outb(ctrl, dev->iobase + PCL816_CTRL_REG); - outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG); + outb((dma->chan << 4) | dev->irq, + dev->iobase + PCL816_STATUS_REG); return 0; } @@ -521,42 +484,34 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc; unsigned long flags; - unsigned int top1, top2, i; + unsigned int poll; + int ret; spin_lock_irqsave(&dev->spinlock, flags); - for (i = 0; i < 20; i++) { - top1 = get_dma_residue(devpriv->dma); /* where is now DMA */ - top2 = get_dma_residue(devpriv->dma); - if (top1 == top2) - break; - } - if (top1 != top2) { - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; - } - - /* where is now DMA in buffer */ - top1 = devpriv->hwdmasize - top1; - top1 >>= 1; /* sample position */ - top2 = top1 - devpriv->ai_poll_ptr; - if (top2 < 1) { /* no new samples */ - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; - } + poll = comedi_isadma_poll(dma); + poll = comedi_bytes_to_samples(s, poll); + if (poll > devpriv->ai_poll_ptr) { + desc = &dma->desc[dma->cur_dma]; + transfer_from_dma_buf(dev, s, desc->virt_addr, + devpriv->ai_poll_ptr, + poll - devpriv->ai_poll_ptr); + /* new buffer position */ + devpriv->ai_poll_ptr = poll; - transfer_from_dma_buf(dev, s, - (unsigned short *)devpriv->dmabuf[devpriv-> - next_dma_buf], - devpriv->ai_poll_ptr, top2); + comedi_handle_events(dev, s); - devpriv->ai_poll_ptr = top1; /* new buffer position */ + ret = comedi_buf_n_bytes_ready(s); + } else { + /* no new samples */ + ret = 0; + } spin_unlock_irqrestore(&dev->spinlock, flags); - comedi_handle_events(dev, s); - - return comedi_buf_n_bytes_ready(s); + return ret; } static int pcl816_ai_cancel(struct comedi_device *dev, @@ -657,13 +612,44 @@ static void pcl816_reset(struct comedi_device *dev) outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); } +static void pcl816_alloc_irq_and_dma(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct pcl816_private *devpriv = dev->private; + unsigned int irq_num = it->options[1]; + unsigned int dma_chan = it->options[2]; + + /* only IRQs 2-7 and DMA channels 3 and 1 are valid */ + if (!(irq_num >= 2 && irq_num <= 7) || + !(dma_chan == 3 || dma_chan == 1)) + return; + + if (request_irq(irq_num, pcl816_interrupt, 0, dev->board_name, dev)) + return; + + /* DMA uses two 16K buffers */ + devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan, + PAGE_SIZE * 4, COMEDI_ISADMA_READ); + if (!devpriv->dma) + free_irq(irq_num, dev); + else + dev->irq = irq_num; +} + +static void pcl816_free_dma(struct comedi_device *dev) +{ + struct pcl816_private *devpriv = dev->private; + + if (devpriv) + comedi_isadma_free(devpriv->dma); +} + static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl816_board *board = dev->board_ptr; struct pcl816_private *devpriv; struct comedi_subdevice *s; int ret; - int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -673,39 +659,8 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) 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]; - } - - /* we need an IRQ to do DMA on channel 3 or 1 */ - if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) { - ret = request_dma(it->options[2], dev->board_name); - if (ret) { - dev_err(dev->class_dev, - "unable to request DMA channel %d\n", - it->options[2]); - return -EBUSY; - } - devpriv->dma = it->options[2]; - - devpriv->dmapages = 2; /* we need 16KB */ - devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; - - for (i = 0; i < 2; i++) { - unsigned long dmabuf; - - dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); - if (!dmabuf) - return -ENOMEM; - - devpriv->dmabuf[i] = dmabuf; - devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); - } - } + /* an IRQ and DMA are required to support async commands */ + pcl816_alloc_irq_and_dma(dev, it); ret = comedi_alloc_subdevices(dev, 4); if (ret) @@ -718,7 +673,7 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = board->ai_maxdata; s->range_table = &range_pcl816; s->insn_read = pcl816_ai_insn_read; - if (devpriv->dma) { + if (dev->irq) { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; s->len_chanlist = board->ai_chanlist; @@ -764,18 +719,11 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void pcl816_detach(struct comedi_device *dev) { - struct pcl816_private *devpriv = dev->private; - if (dev->private) { pcl816_ai_cancel(dev, dev->read_subdev); pcl816_reset(dev); - if (devpriv->dma) - free_dma(devpriv->dma); - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages); } + pcl816_free_dma(dev); comedi_legacy_detach(dev); } diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index 8edea35532a9..7e4cdea5fe59 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -1,112 +1,105 @@ /* - comedi/drivers/pcl818.c - - Author: Michal Dobes <dobes@tesnet.cz> - - hardware driver for Advantech cards: - card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718 - driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718 -*/ -/* -Driver: pcl818 -Description: Advantech PCL-818 cards, PCL-718 -Author: Michal Dobes <dobes@tesnet.cz> -Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h), - PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818), - PCL-718 (pcl718) -Status: works - -All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO. -Differences are only at maximal sample speed, range list and FIFO -support. -The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support -only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0. -PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO -but this code is untested. -A word or two about DMA. Driver support DMA operations at two ways: -1) DMA uses two buffers and after one is filled then is generated - INT and DMA restart with second buffer. With this mode I'm unable run - more that 80Ksamples/secs without data dropouts on K6/233. -2) DMA uses one buffer and run in autoinit mode and the data are - from DMA buffer moved on the fly with 2kHz interrupts from RTC. - This mode is used if the interrupt 8 is available for allocation. - If not, then first DMA mode is used. With this I can run at - full speed one card (100ksamples/secs) or two cards with - 60ksamples/secs each (more is problem on account of ISA limitations). - To use this mode you must have compiled kernel with disabled - "Enhanced Real Time Clock Support". - Maybe you can have problems if you use xntpd or similar. - If you've data dropouts with DMA mode 2 then: - a) disable IDE DMA - b) switch text mode console to fb. - - Options for PCL-818L: - [0] - IO Base - [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) - [2] - DMA (0=disable, 1, 3) - [3] - 0, 10=10MHz clock for 8254 - 1= 1MHz clock for 8254 - [4] - 0, 5=A/D input -5V.. +5V - 1, 10=A/D input -10V..+10V - [5] - 0, 5=D/A output 0-5V (internal reference -5V) - 1, 10=D/A output 0-10V (internal reference -10V) - 2 =D/A output unknown (external reference) - - Options for PCL-818, PCL-818H: - [0] - IO Base - [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) - [2] - DMA (0=disable, 1, 3) - [3] - 0, 10=10MHz clock for 8254 - 1= 1MHz clock for 8254 - [4] - 0, 5=D/A output 0-5V (internal reference -5V) - 1, 10=D/A output 0-10V (internal reference -10V) - 2 =D/A output unknown (external reference) - - Options for PCL-818HD, PCL-818HG: - [0] - IO Base - [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) - [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA, - 1=use DMA ch 1, 3=use DMA ch 3) - [3] - 0, 10=10MHz clock for 8254 - 1= 1MHz clock for 8254 - [4] - 0, 5=D/A output 0-5V (internal reference -5V) - 1, 10=D/A output 0-10V (internal reference -10V) - 2 =D/A output unknown (external reference) - - Options for PCL-718: - [0] - IO Base - [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) - [2] - DMA (0=disable, 1, 3) - [3] - 0, 10=10MHz clock for 8254 - 1= 1MHz clock for 8254 - [4] - 0=A/D Range is +/-10V - 1= +/-5V - 2= +/-2.5V - 3= +/-1V - 4= +/-0.5V - 5= user defined bipolar - 6= 0-10V - 7= 0-5V - 8= 0-2V - 9= 0-1V - 10= user defined unipolar - [5] - 0, 5=D/A outputs 0-5V (internal reference -5V) - 1, 10=D/A outputs 0-10V (internal reference -10V) - 2=D/A outputs unknown (external reference) - [6] - 0, 60=max 60kHz A/D sampling - 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed) - -*/ + * comedi/drivers/pcl818.c + * + * Driver: pcl818 + * Description: Advantech PCL-818 cards, PCL-718 + * Author: Michal Dobes <dobes@tesnet.cz> + * Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h), + * PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818), + * PCL-718 (pcl718) + * Status: works + * + * All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO. + * Differences are only at maximal sample speed, range list and FIFO + * support. + * The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support + * only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0. + * PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO + * but this code is untested. + * A word or two about DMA. Driver support DMA operations at two ways: + * 1) DMA uses two buffers and after one is filled then is generated + * INT and DMA restart with second buffer. With this mode I'm unable run + * more that 80Ksamples/secs without data dropouts on K6/233. + * 2) DMA uses one buffer and run in autoinit mode and the data are + * from DMA buffer moved on the fly with 2kHz interrupts from RTC. + * This mode is used if the interrupt 8 is available for allocation. + * If not, then first DMA mode is used. With this I can run at + * full speed one card (100ksamples/secs) or two cards with + * 60ksamples/secs each (more is problem on account of ISA limitations). + * To use this mode you must have compiled kernel with disabled + * "Enhanced Real Time Clock Support". + * Maybe you can have problems if you use xntpd or similar. + * If you've data dropouts with DMA mode 2 then: + * a) disable IDE DMA + * b) switch text mode console to fb. + * + * Options for PCL-818L: + * [0] - IO Base + * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) + * [2] - DMA (0=disable, 1, 3) + * [3] - 0, 10=10MHz clock for 8254 + * 1= 1MHz clock for 8254 + * [4] - 0, 5=A/D input -5V.. +5V + * 1, 10=A/D input -10V..+10V + * [5] - 0, 5=D/A output 0-5V (internal reference -5V) + * 1, 10=D/A output 0-10V (internal reference -10V) + * 2 =D/A output unknown (external reference) + * + * Options for PCL-818, PCL-818H: + * [0] - IO Base + * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) + * [2] - DMA (0=disable, 1, 3) + * [3] - 0, 10=10MHz clock for 8254 + * 1= 1MHz clock for 8254 + * [4] - 0, 5=D/A output 0-5V (internal reference -5V) + * 1, 10=D/A output 0-10V (internal reference -10V) + * 2 =D/A output unknown (external reference) + * + * Options for PCL-818HD, PCL-818HG: + * [0] - IO Base + * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) + * [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA, + * 1=use DMA ch 1, 3=use DMA ch 3) + * [3] - 0, 10=10MHz clock for 8254 + * 1= 1MHz clock for 8254 + * [4] - 0, 5=D/A output 0-5V (internal reference -5V) + * 1, 10=D/A output 0-10V (internal reference -10V) + * 2 =D/A output unknown (external reference) + * + * Options for PCL-718: + * [0] - IO Base + * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) + * [2] - DMA (0=disable, 1, 3) + * [3] - 0, 10=10MHz clock for 8254 + * 1= 1MHz clock for 8254 + * [4] - 0=A/D Range is +/-10V + * 1= +/-5V + * 2= +/-2.5V + * 3= +/-1V + * 4= +/-0.5V + * 5= user defined bipolar + * 6= 0-10V + * 7= 0-5V + * 8= 0-2V + * 9= 0-1V + * 10= user defined unipolar + * [5] - 0, 5=D/A outputs 0-5V (internal reference -5V) + * 1, 10=D/A outputs 0-10V (internal reference -10V) + * 2=D/A outputs unknown (external reference) + * [6] - 0, 60=max 60kHz A/D sampling + * 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed) + * + */ #include <linux/module.h> #include <linux/gfp.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/interrupt.h> -#include <asm/dma.h> #include "../comedidev.h" +#include "comedi_isadma.h" #include "comedi_fc.h" #include "8253.h" @@ -303,20 +296,14 @@ static const struct pcl818_board boardtypes[] = { }; struct pcl818_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 hwdmaptr[2]; /* hardware address of DMA buffers */ - 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 ns_min; /* manimal allowed delay between samples (in us) for actual card */ + struct comedi_isadma *dma; + /* manimal allowed delay between samples (in us) for actual card */ + unsigned int ns_min; int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ - unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ + /* MUX setting for actual AI operations */ + unsigned int act_chanlist[16]; unsigned int act_chanlist_len; /* how long is actual MUX list */ unsigned int act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_data_len; /* len of data buffer */ unsigned int divisor1; unsigned int divisor2; unsigned int usefifo:1; @@ -340,58 +327,27 @@ static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters) } 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; - - disable_dma(devpriv->dma); /* disable dma */ - bytes = devpriv->hwdmasize; - if (cmd->stop_src == TRIG_COUNT) { - bytes = cmd->stop_arg * comedi_bytes_per_scan(s); - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; - devpriv->last_dma_run = bytes % devpriv->hwdmasize; - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize; - } - - 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); -} - -static void pcl818_ai_setup_next_dma(struct comedi_device *dev, - struct comedi_subdevice *s) + struct comedi_subdevice *s, + unsigned int unread_samples) { struct pcl818_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - unsigned long flags; - - 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); + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize); + unsigned int nsamples; + + comedi_isadma_disable(dma->chan); + + /* + * Determine dma size based on the buffer maxsize plus the number of + * unread samples and the number of samples remaining in the command. + */ + nsamples = comedi_nsamples_left(s, max_samples + unread_samples); + if (nsamples > unread_samples) { + nsamples -= unread_samples; + desc->size = comedi_samples_to_bytes(s, nsamples); + comedi_isadma_program(desc); } - - devpriv->dma_runs_to_end--; } static void pcl818_ai_set_chan_range(struct comedi_device *dev, @@ -493,11 +449,12 @@ static int pcl818_ai_eoc(struct comedi_device *dev, return -EBUSY; } -static bool pcl818_ai_dropout(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int chan) +static bool pcl818_ai_write_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, unsigned int val) { struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int expected_chan; expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos]; @@ -507,17 +464,11 @@ static bool pcl818_ai_dropout(struct comedi_device *dev, (devpriv->dma) ? "DMA" : (devpriv->usefifo) ? "FIFO" : "IRQ", chan, expected_chan); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - return true; + s->async->events |= COMEDI_CB_ERROR; + return false; } - 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; + comedi_buf_write_samples(s, &val, 1); devpriv->act_chanlist_pos++; if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) @@ -540,47 +491,35 @@ static void pcl818_handle_eoc(struct comedi_device *dev, if (pcl818_ai_eoc(dev, s, NULL, 0)) { dev_err(dev->class_dev, "A/D mode1/3 IRQ without DRDY!\n"); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + s->async->events |= COMEDI_CB_ERROR; return; } val = pcl818_ai_get_sample(dev, s, &chan); - - if (pcl818_ai_dropout(dev, s, chan)) - return; - - comedi_buf_write_samples(s, &val, 1); - - pcl818_ai_next_chan(dev, s); + pcl818_ai_write_sample(dev, s, chan, val); } static void pcl818_handle_dma(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; - unsigned short *ptr; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + unsigned short *ptr = desc->virt_addr; + unsigned int nsamples = comedi_bytes_to_samples(s, desc->size); unsigned int chan; unsigned int val; - int i, len, bufptr; - - pcl818_ai_setup_next_dma(dev, s); - - ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; + int i; - len = devpriv->hwdmasize >> 1; - bufptr = 0; + /* restart dma with the next buffer */ + dma->cur_dma = 1 - dma->cur_dma; + pcl818_ai_setup_dma(dev, s, nsamples); - for (i = 0; i < len; i++) { - val = ptr[bufptr++]; + for (i = 0; i < nsamples; i++) { + val = ptr[i]; chan = val & 0xf; val = (val >> 4) & s->maxdata; - - if (pcl818_ai_dropout(dev, s, chan)) - break; - - comedi_buf_write_samples(s, &val, 1); - - if (!pcl818_ai_next_chan(dev, s)) + if (!pcl818_ai_write_sample(dev, s, chan, val)) break; } } @@ -597,14 +536,14 @@ static void pcl818_handle_fifo(struct comedi_device *dev, if (status & 4) { dev_err(dev->class_dev, "A/D mode1/3 FIFO overflow!\n"); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + s->async->events |= COMEDI_CB_ERROR; return; } if (status & 1) { dev_err(dev->class_dev, "A/D mode1/3 FIFO interrupt without data!\n"); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + s->async->events |= COMEDI_CB_ERROR; return; } @@ -615,13 +554,7 @@ static void pcl818_handle_fifo(struct comedi_device *dev, for (i = 0; i < len; i++) { val = pcl818_ai_get_fifo_sample(dev, s, &chan); - - if (pcl818_ai_dropout(dev, s, chan)) - break; - - comedi_buf_write_samples(s, &val, 1); - - if (!pcl818_ai_next_chan(dev, s)) + if (!pcl818_ai_write_sample(dev, s, chan, val)) break; } } @@ -687,7 +620,8 @@ static int check_channel_list(struct comedi_device *dev, break; nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ + if (nowmustbechan != CR_CHAN(chanlist[i])) { + /* channel list isn't continuous :-( */ dev_dbg(dev->class_dev, "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", i, CR_CHAN(chanlist[i]), nowmustbechan, @@ -804,6 +738,7 @@ static int pcl818_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_cmd *cmd = &s->async->cmd; unsigned int ctrl = 0; unsigned int seglen; @@ -818,11 +753,9 @@ static int pcl818_ai_cmd(struct comedi_device *dev, return -EINVAL; pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen); - devpriv->ai_data_len = s->async->prealloc_bufsz; devpriv->ai_cmd_running = 1; devpriv->ai_cmd_canceled = 0; devpriv->act_chanlist_pos = 0; - devpriv->dma_runs_to_end = 0; if (cmd->convert_src == TRIG_TIMER) ctrl |= PCL818_CTRL_PACER_TRIG; @@ -831,8 +764,10 @@ static int pcl818_ai_cmd(struct comedi_device *dev, outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); - if (devpriv->dma) { - pcl818_ai_setup_dma(dev, s); + if (dma) { + /* setup and enable dma for the first buffer */ + dma->cur_dma = 0; + pcl818_ai_setup_dma(dev, s, 0); ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) | PCL818_CTRL_DMAE; @@ -854,12 +789,13 @@ static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_cmd *cmd = &s->async->cmd; if (!devpriv->ai_cmd_running) return 0; - if (devpriv->dma) { + if (dma) { if (cmd->stop_src == TRIG_NONE || (cmd->stop_src == TRIG_COUNT && s->async->scans_done < cmd->stop_arg)) { @@ -872,7 +808,7 @@ static int pcl818_ai_cancel(struct comedi_device *dev, return 0; } } - disable_dma(devpriv->dma); + comedi_isadma_disable(dma->chan); } outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); @@ -1054,13 +990,33 @@ static void pcl818_set_ai_range_table(struct comedi_device *dev, } } +static void pcl818_alloc_dma(struct comedi_device *dev, unsigned int dma_chan) +{ + struct pcl818_private *devpriv = dev->private; + + /* only DMA channels 3 and 1 are valid */ + if (!(dma_chan == 3 || dma_chan == 1)) + return; + + /* DMA uses two 16K buffers */ + devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan, + PAGE_SIZE * 4, COMEDI_ISADMA_READ); +} + +static void pcl818_free_dma(struct comedi_device *dev) +{ + struct pcl818_private *devpriv = dev->private; + + if (devpriv) + comedi_isadma_free(devpriv->dma); +} + static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl818_board *board = dev->board_ptr; struct pcl818_private *devpriv; struct comedi_subdevice *s; int ret; - int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -1084,31 +1040,8 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->usefifo = 1; /* we need an IRQ to do DMA on channel 3 or 1 */ - if (dev->irq && board->has_dma && - (it->options[2] == 3 || it->options[2] == 1)) { - ret = request_dma(it->options[2], dev->board_name); - if (ret) { - dev_err(dev->class_dev, - "unable to request DMA channel %d\n", - it->options[2]); - return -EBUSY; - } - devpriv->dma = it->options[2]; - - devpriv->dmapages = 2; /* we need 16KB */ - devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; - - for (i = 0; i < 2; i++) { - unsigned long dmabuf; - - dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); - if (!dmabuf) - return -ENOMEM; - - devpriv->dmabuf[i] = dmabuf; - devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); - } - } + if (dev->irq && board->has_dma) + pcl818_alloc_dma(dev, it->options[2]); ret = comedi_alloc_subdevices(dev, 4); if (ret) @@ -1194,8 +1127,10 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->ns_min = board->ns_min; if (!board->is_818) { - if ((it->options[6] == 1) || (it->options[6] == 100)) - devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */ + if ((it->options[6] == 1) || (it->options[6] == 100)) { + /* extended PCL718 to 100kHz DAC */ + devpriv->ns_min = 10000; + } } pcl818_reset(dev); @@ -1210,13 +1145,8 @@ static void pcl818_detach(struct comedi_device *dev) if (devpriv) { pcl818_ai_cancel(dev, dev->read_subdev); pcl818_reset(dev); - if (devpriv->dma) - free_dma(devpriv->dma); - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages); } + pcl818_free_dma(dev); comedi_legacy_detach(dev); } diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index e3ac8ac6190e..12f94fe82f5b 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -19,8 +19,7 @@ /* * Driver: pcmad * Description: Winsystems PCM-A/D12, PCM-A/D16 - * Devices: (Winsystems) PCM-A/D12 [pcmad12] - * (Winsystems) PCM-A/D16 [pcmad16] + * Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16) * Author: ds * Status: untested * diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 59108c06cedc..d86c5e2cd0c7 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -19,7 +19,7 @@ /* * Driver: pcmda12 * Description: A driver for the Winsystems PCM-D/A-12 - * Devices: (Winsystems) PCM-D/A-12 [pcmda12] + * Devices: [Winsystems] PCM-D/A-12 (pcmda12) * Author: Calin Culianu <calin@ajvar.org> * Updated: Fri, 13 Jan 2006 12:01:01 -0500 * Status: works diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index f0059e935da0..2c0e7ecbf494 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -19,7 +19,7 @@ /* * Driver: pcmmio * Description: A driver for the PCM-MIO multifunction board - * Devices: (Winsystems) PCM-MIO [pcmmio] + * Devices: [Winsystems] PCM-MIO (pcmmio) * Author: Calin Culianu <calin@ajvar.org> * Updated: Wed, May 16 2007 16:21:10 -0500 * Status: works diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 0f5483b6147f..a1641d981812 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -19,8 +19,7 @@ /* * Driver: pcmuio * Description: Winsystems PC-104 based 48/96-channel DIO boards. - * Devices: (Winsystems) PCM-UIO48A [pcmuio48] - * (Winsystems) PCM-UIO96A [pcmuio96] + * Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96) * Author: Calin Culianu <calin@ajvar.org> * Updated: Fri, 13 Jan 2006 12:01:01 -0500 * Status: works diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 96098110b0b3..8387fd0e4b7e 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -48,15 +48,10 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308 */ #include <linux/module.h> -#include "../comedidev.h" #include <linux/semaphore.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - #include <linux/completion.h> +#include "../comedi_pcmcia.h" #include "comedi_fc.h" struct daqp_private { @@ -210,8 +205,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) unsigned short data; if (status & DAQP_STATUS_DATA_LOST) { - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_OVERFLOW; + s->async->events |= COMEDI_CB_OVERFLOW; dev_warn(dev->class_dev, "data lost\n"); break; } @@ -239,7 +233,7 @@ 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"); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + s->async->events |= COMEDI_CB_ERROR; } comedi_handle_events(dev, s); diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 581aa58d9c0a..c94ad12ed446 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -19,10 +19,8 @@ /* * Driver: rtd520 * Description: Real Time Devices PCI4520/DM7520 - * Devices: (Real Time Devices) DM7520HR-1 [DM7520] - * (Real Time Devices) DM7520HR-8 [DM7520] - * (Real Time Devices) PCI4520 [PCI4520] - * (Real Time Devices) PCI4520-8 [PCI4520] + * Devices: [Real Time Devices] DM7520HR-1 (DM7520), DM7520HR-8, + * PCI4520 (PCI4520), PCI4520-8 * Author: Dan Christian * Status: Works. Only tested on DM7520-8. Not SMP safe. * @@ -1014,10 +1012,8 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) readw(dev->mmio + LAS0_CLEAR); /* TODO: allow multiple interrupt sources */ - if (devpriv->xfer_count > 0) /* transfer every N samples */ - writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT); - else /* 1/2 FIFO transfers */ - writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT); + /* transfer every N samples */ + writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT); /* BUG: start_src is ASSUMED to be TRIG_NOW */ /* BUG? it seems like things are running before the "start" */ @@ -1031,8 +1027,6 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct rtd_private *devpriv = dev->private; - u32 overrun; - u16 status; /* pacer stop source: SOFTWARE */ writel(0, dev->mmio + LAS0_PACER_STOP); @@ -1040,8 +1034,6 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) writel(0, dev->mmio + LAS0_ADC_CONVERSION); writew(0, dev->mmio + LAS0_IT); devpriv->ai_count = 0; /* stop and don't transfer any more */ - status = readw(dev->mmio + LAS0_IT); - overrun = readl(dev->mmio + LAS0_OVERRUN) & 0xffff; writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR); return 0; } diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index 67b4b378bd01..340ac776e951 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -19,8 +19,7 @@ /* * Driver: rti800 * Description: Analog Devices RTI-800/815 - * Devices: (Analog Devices) RTI-800 [rti800] - * (Analog Devices) RTI-815 [rti815] + * Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815) * Author: David A. Schleef <ds@schleef.org> * Status: unknown * Updated: Fri, 05 Sep 2008 14:50:44 +0100 diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index 96c3974207ae..6db58fcfd496 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -20,7 +20,7 @@ * Driver: rti802 * Description: Analog Devices RTI-802 * Author: Anders Blomdell <anders.blomdell@control.lth.se> - * Devices: (Analog Devices) RTI-802 [rti802] + * Devices: [Analog Devices] RTI-802 (rti802) * Status: works * * Configuration Options: diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 14932c5f3798..fc497dd92021 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -118,7 +118,7 @@ static void s626_mc_enable(struct comedi_device *dev, static void s626_mc_disable(struct comedi_device *dev, unsigned int cmd, unsigned int reg) { - writel(cmd << 16 , dev->mmio + reg); + writel(cmd << 16, dev->mmio + reg); mmiowb(); } diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 4737dbf8e01d..1cd7403a4e9c 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -16,10 +16,11 @@ /* * Driver: usbdux * Description: University of Stirling USB DAQ & INCITE Technology Limited - * Devices: (ITL) USB-DUX [usbdux] + * Devices: [ITL] USB-DUX (usbdux) * Author: Bernd Porr <mail@berndporr.me.uk> * Updated: 10 Oct 2014 * Status: Stable + * * Connection scheme for the counter at the digital port: * 0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1. * The sampling rate of the counter is approximately 500Hz. @@ -79,11 +80,10 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> -#include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> -#include "../comedidev.h" +#include "../comedi_usb.h" #include "comedi_fc.h" diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index ddc4cb9d5ed4..7ce27c16c2f9 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -15,7 +15,7 @@ /* * Driver: usbduxfast * Description: University of Stirling USB DAQ & INCITE Technology Limited - * Devices: (ITL) USB-DUX [usbduxfast] + * Devices: [ITL] USB-DUX-FAST (usbduxfast) * Author: Bernd Porr <mail@berndporr.me.uk> * Updated: 10 Oct 2014 * Status: stable @@ -46,11 +46,10 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> -#include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> #include "comedi_fc.h" -#include "../comedidev.h" +#include "../comedi_usb.h" /* * timeout for the USB-transfer diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index dc19435b6520..394969b7458c 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -16,7 +16,7 @@ /* * Driver: usbduxsigma * Description: University of Stirling USB DAQ & INCITE Technology Limited - * Devices: (ITL) USB-DUX [usbduxsigma] + * Devices: [ITL] USB-DUX-SIGMA (usbduxsigma) * Author: Bernd Porr <mail@berndporr.me.uk> * Updated: 10 Oct 2014 * Status: stable @@ -45,13 +45,12 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> -#include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> #include <asm/unaligned.h> #include "comedi_fc.h" -#include "../comedidev.h" +#include "../comedi_usb.h" /* timeout for the USB-transfer in ms*/ #define BULK_TIMEOUT 1000 @@ -215,7 +214,6 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - unsigned int dio_state; uint32_t val; int ret; int i; @@ -224,9 +222,6 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev, if (devpriv->ai_counter == 0) { devpriv->ai_counter = devpriv->ai_timer; - /* get the state of the dio pins to allow external trigger */ - dio_state = be32_to_cpu(devpriv->in_buf[0]); - /* get the data from the USB bus and hand it over to comedi */ for (i = 0; i < cmd->chanlist_len; i++) { /* transfer data, note first byte is the DIO state */ diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index a19a56ee0eef..e37118321a27 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -18,21 +18,22 @@ GNU General Public License for more details. */ /* -Driver: vmk80xx -Description: Velleman USB Board Low-Level Driver -Devices: K8055/K8061 aka VM110/VM140 -Author: Manuel Gebele <forensixs@gmx.de> -Updated: Sun, 10 May 2009 11:14:59 +0200 -Status: works - -Supports: - - analog input - - analog output - - digital input - - digital output - - counter - - pwm -*/ + * Driver: vmk80xx + * Description: Velleman USB Board Low-Level Driver + * Devices: [Velleman] K8055 (K8055/VM110), K8061 (K8061/VM140), + * VM110 (K8055/VM110), VM140 (K8061/VM140) + * Author: Manuel Gebele <forensixs@gmx.de> + * Updated: Sun, 10 May 2009 11:14:59 +0200 + * Status: works + * + * Supports: + * - analog input + * - analog output + * - digital input + * - digital output + * - counter + * - pwm + */ #include <linux/kernel.h> #include <linux/module.h> @@ -41,10 +42,9 @@ Supports: #include <linux/input.h> #include <linux/slab.h> #include <linux/poll.h> -#include <linux/usb.h> #include <linux/uaccess.h> -#include "../comedidev.h" +#include "../comedi_usb.h" enum { DEVICE_VMK8055, @@ -550,41 +550,35 @@ static int vmk80xx_cnt_insn_config(struct comedi_device *dev, unsigned int *data) { struct vmk80xx_private *devpriv = dev->private; - unsigned int insn_cmd; - int chan; + unsigned int chan = CR_CHAN(insn->chanspec); int cmd; int reg; - int n; - - insn_cmd = data[0]; - if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET) - return -EINVAL; + int ret; down(&devpriv->limit_sem); - - chan = CR_CHAN(insn->chanspec); - - if (devpriv->model == VMK8055_MODEL) { - if (!chan) { - cmd = VMK8055_CMD_RST_CNT1; - reg = VMK8055_CNT1_REG; + switch (data[0]) { + case INSN_CONFIG_RESET: + if (devpriv->model == VMK8055_MODEL) { + if (!chan) { + cmd = VMK8055_CMD_RST_CNT1; + reg = VMK8055_CNT1_REG; + } else { + cmd = VMK8055_CMD_RST_CNT2; + reg = VMK8055_CNT2_REG; + } + devpriv->usb_tx_buf[reg] = 0x00; } else { - cmd = VMK8055_CMD_RST_CNT2; - reg = VMK8055_CNT2_REG; + cmd = VMK8061_CMD_RST_CNT; } - - devpriv->usb_tx_buf[reg] = 0x00; - } else { - cmd = VMK8061_CMD_RST_CNT; + ret = vmk80xx_write_packet(dev, cmd); + break; + default: + ret = -EINVAL; + break; } - - for (n = 0; n < insn->n; n++) - if (vmk80xx_write_packet(dev, cmd)) - break; - up(&devpriv->limit_sem); - return n; + return ret ? ret : insn->n; } static int vmk80xx_cnt_insn_write(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/z8536.h b/drivers/staging/comedi/drivers/z8536.h new file mode 100644 index 000000000000..7be53109cc8d --- /dev/null +++ b/drivers/staging/comedi/drivers/z8536.h @@ -0,0 +1,202 @@ +/* + * Z8536 CIO Internal registers + */ + +#ifndef _Z8536_H +#define _Z8536_H + +/* Master Interrupt Control register */ +#define Z8536_INT_CTRL_REG 0x00 +#define Z8536_INT_CTRL_MIE BIT(7) /* Master Interrupt Enable */ +#define Z8536_INT_CTRL_DLC BIT(6) /* Disable Lower Chain */ +#define Z8536_INT_CTRL_NV BIT(5) /* No Vector */ +#define Z8536_INT_CTRL_PA_VIS BIT(4) /* Port A Vect Inc Status */ +#define Z8536_INT_CTRL_PB_VIS BIT(3) /* Port B Vect Inc Status */ +#define Z8536_INT_CTRL_VT_VIS BIT(2) /* C/T Vect Inc Status */ +#define Z8536_INT_CTRL_RJA BIT(1) /* Right Justified Addresses */ +#define Z8536_INT_CTRL_RESET BIT(0) /* Reset */ + +/* Master Configuration Control register */ +#define Z8536_CFG_CTRL_REG 0x01 +#define Z8536_CFG_CTRL_PBE BIT(7) /* Port B Enable */ +#define Z8536_CFG_CTRL_CT1E BIT(6) /* C/T 1 Enable */ +#define Z8536_CFG_CTRL_CT2E BIT(5) /* C/T 2 Enable */ +#define Z8536_CFG_CTRL_PCE_CT3E BIT(4) /* Port C & C/T 3 Enable */ +#define Z8536_CFG_CTRL_PLC BIT(3) /* Port A/B Link Control */ +#define Z8536_CFG_CTRL_PAE BIT(2) /* Port A Enable */ +#define Z8536_CFG_CTRL_LC_INDEP (0 << 0)/* C/Ts Independent */ +#define Z8536_CFG_CTRL_LC_GATE (1 << 0)/* C/T 1 Out Gates C/T 2 */ +#define Z8536_CFG_CTRL_LC_TRIG (2 << 0)/* C/T 1 Out Triggers C/T 2 */ +#define Z8536_CFG_CTRL_LC_CLK (3 << 0)/* C/T 1 Out Clocks C/T 2 */ +#define Z8536_CFG_CTRL_LC_MASK (3 << 0)/* C/T Link Control mask */ + +/* Interrupt Vector registers */ +#define Z8536_PA_INT_VECT_REG 0x02 +#define Z8536_PB_INT_VECT_REG 0x03 +#define Z8536_CT_INT_VECT_REG 0x04 +#define Z8536_CURR_INT_VECT_REG 0x1f + +/* Port A/B & Counter/Timer 1/2/3 Command and Status registers */ +#define Z8536_PA_CMDSTAT_REG 0x08 +#define Z8536_PB_CMDSTAT_REG 0x09 +#define Z8536_CT1_CMDSTAT_REG 0x0a +#define Z8536_CT2_CMDSTAT_REG 0x0b +#define Z8536_CT3_CMDSTAT_REG 0x0c +#define Z8536_CT_CMDSTAT_REG(x) (0x0a + (x)) +#define Z8536_CMD_NULL (0 << 5)/* Null Code */ +#define Z8536_CMD_CLR_IP_IUS (1 << 5)/* Clear IP & IUS */ +#define Z8536_CMD_SET_IUS (2 << 5)/* Set IUS */ +#define Z8536_CMD_CLR_IUS (3 << 5)/* Clear IUS */ +#define Z8536_CMD_SET_IP (4 << 5)/* Set IP */ +#define Z8536_CMD_CLR_IP (5 << 5)/* Clear IP */ +#define Z8536_CMD_SET_IE (6 << 5)/* Set IE */ +#define Z8536_CMD_CLR_IE (7 << 5)/* Clear IE */ +#define Z8536_CMD_MASK (7 << 5) + +#define Z8536_STAT_IUS BIT(7) /* Interrupt Under Service */ +#define Z8536_STAT_IE BIT(6) /* Interrupt Enable */ +#define Z8536_STAT_IP BIT(5) /* Interrupt Pending */ +#define Z8536_STAT_ERR BIT(4) /* Interrupt Error */ +#define Z8536_STAT_IE_IP (Z8536_STAT_IE | Z8536_STAT_IP) + +#define Z8536_PAB_STAT_ORE BIT(3) /* Output Register Empty */ +#define Z8536_PAB_STAT_IRF BIT(2) /* Input Register Full */ +#define Z8536_PAB_STAT_PMF BIT(1) /* Pattern Match Flag */ +#define Z8536_PAB_CMDSTAT_IOE BIT(0) /* Interrupt On Error */ + +#define Z8536_CT_CMD_RCC BIT(3) /* Read Counter Control */ +#define Z8536_CT_CMDSTAT_GCB BIT(2) /* Gate Command Bit */ +#define Z8536_CT_CMD_TCB BIT(1) /* Trigger Command Bit */ +#define Z8536_CT_STAT_CIP BIT(0) /* Count In Progress */ + +/* Port Data registers */ +#define Z8536_PA_DATA_REG 0x0d +#define Z8536_PB_DATA_REG 0x0e +#define Z8536_PC_DATA_REG 0x0f + +/* Counter/Timer 1/2/3 Current Count registers */ +#define Z8536_CT1_VAL_MSB_REG 0x10 +#define Z8536_CT1_VAL_LSB_REG 0x11 +#define Z8536_CT2_VAL_MSB_REG 0x12 +#define Z8536_CT2_VAL_LSB_REG 0x13 +#define Z8536_CT3_VAL_MSB_REG 0x14 +#define Z8536_CT3_VAL_LSB_REG 0x15 +#define Z8536_CT_VAL_MSB_REG(x) (0x10 + ((x) * 2)) +#define Z8536_CT_VAL_LSB_REG(x) (0x11 + ((x) * 2)) + +/* Counter/Timer 1/2/3 Time Constant registers */ +#define Z8536_CT1_RELOAD_MSB_REG 0x16 +#define Z8536_CT1_RELOAD_LSB_REG 0x17 +#define Z8536_CT2_RELOAD_MSB_REG 0x18 +#define Z8536_CT2_RELOAD_LSB_REG 0x19 +#define Z8536_CT3_RELOAD_MSB_REG 0x1a +#define Z8536_CT3_RELOAD_LSB_REG 0x1b +#define Z8536_CT_RELOAD_MSB_REG(x) (0x16 + ((x) * 2)) +#define Z8536_CT_RELOAD_LSB_REG(x) (0x17 + ((x) * 2)) + +/* Counter/Timer 1/2/3 Mode Specification registers */ +#define Z8536_CT1_MODE_REG 0x1c +#define Z8536_CT2_MODE_REG 0x1d +#define Z8536_CT3_MODE_REG 0x1e +#define Z8536_CT_MODE_REG(x) (0x1c + (x)) +#define Z8536_CT_MODE_CSC BIT(7) /* Continuous/Single Cycle */ +#define Z8536_CT_MODE_EOE BIT(6) /* External Output Enable */ +#define Z8536_CT_MODE_ECE BIT(5) /* External Count Enable */ +#define Z8536_CT_MODE_ETE BIT(4) /* External Trigger Enable */ +#define Z8536_CT_MODE_EGE BIT(3) /* External Gate Enable */ +#define Z8536_CT_MODE_REB BIT(2) /* Retrigger Enable Bit */ +#define Z8536_CT_MODE_DCS_PULSE (0 << 0)/* Duty Cycle - Pulse */ +#define Z8536_CT_MODE_DCS_ONESHOT (1 << 0)/* Duty Cycle - One-Shot */ +#define Z8536_CT_MODE_DCS_SQRWAVE (2 << 0)/* Duty Cycle - Square Wave */ +#define Z8536_CT_MODE_DCS_DO_NOT_USE (3 << 0)/* Duty Cycle - Do Not Use */ +#define Z8536_CT_MODE_DCS_MASK (3 << 0)/* Duty Cycle mask */ + +/* Port A/B Mode Specification registers */ +#define Z8536_PA_MODE_REG 0x20 +#define Z8536_PB_MODE_REG 0x28 +#define Z8536_PAB_MODE_PTS_BIT (0 << 6)/* Bit Port */ +#define Z8536_PAB_MODE_PTS_INPUT (1 << 6)/* Input Port */ +#define Z8536_PAB_MODE_PTS_OUTPUT (2 << 6)/* Output Port */ +#define Z8536_PAB_MODE_PTS_BIDIR (3 << 6)/* Bidirectional Port */ +#define Z8536_PAB_MODE_PTS_MASK (3 << 6)/* Port Type Select mask */ +#define Z8536_PAB_MODE_ITB BIT(5) /* Interrupt on Two Bytes */ +#define Z8536_PAB_MODE_SB BIT(4) /* Single Buffered mode */ +#define Z8536_PAB_MODE_IMO BIT(3) /* Interrupt on Match Only */ +#define Z8536_PAB_MODE_PMS_DISABLE (0 << 1)/* Disable Pattern Match */ +#define Z8536_PAB_MODE_PMS_AND (1 << 1)/* "AND" mode */ +#define Z8536_PAB_MODE_PMS_OR (2 << 1)/* "OR" mode */ +#define Z8536_PAB_MODE_PMS_OR_PEV (3 << 1)/* "OR-Priority" mode */ +#define Z8536_PAB_MODE_PMS_MASK (3 << 1)/* Pattern Mode mask */ +#define Z8536_PAB_MODE_LPM BIT(0) /* Latch on Pattern Match */ +#define Z8536_PAB_MODE_DTE BIT(0) /* Deskew Timer Enabled */ + +/* Port A/B Handshake Specification registers */ +#define Z8536_PA_HANDSHAKE_REG 0x21 +#define Z8536_PB_HANDSHAKE_REG 0x29 +#define Z8536_PAB_HANDSHAKE_HST_INTER (0 << 6)/* Interlocked Handshake */ +#define Z8536_PAB_HANDSHAKE_HST_STROBED (1 << 6)/* Strobed Handshake */ +#define Z8536_PAB_HANDSHAKE_HST_PULSED (2 << 6)/* Pulsed Handshake */ +#define Z8536_PAB_HANDSHAKE_HST_3WIRE (3 << 6)/* Three-Wire Handshake */ +#define Z8536_PAB_HANDSHAKE_HST_MASK (3 << 6)/* Handshake Type mask */ +#define Z8536_PAB_HANDSHAKE_RWS_DISABLE (0 << 3)/* Req/Wait Disabled */ +#define Z8536_PAB_HANDSHAKE_RWS_OUTWAIT (1 << 3)/* Output Wait */ +#define Z8536_PAB_HANDSHAKE_RWS_INWAIT (3 << 3)/* Input Wait */ +#define Z8536_PAB_HANDSHAKE_RWS_SPREQ (4 << 3)/* Special Request */ +#define Z8536_PAB_HANDSHAKE_RWS_OUTREQ (5 << 4)/* Output Request */ +#define Z8536_PAB_HANDSHAKE_RWS_INREQ (7 << 3)/* Input Request */ +#define Z8536_PAB_HANDSHAKE_RWS_MASK (7 << 3)/* Req/Wait mask */ +#define Z8536_PAB_HANDSHAKE_DESKEW(x) ((x) << 0)/* Deskew Time */ +#define Z8536_PAB_HANDSHAKE_DESKEW_MASK (3 << 0)/* Deskew Time mask */ + +/* + * Port A/B/C Data Path Polarity registers + * + * 0 = Non-Inverting + * 1 = Inverting + */ +#define Z8536_PA_DPP_REG 0x22 +#define Z8536_PB_DPP_REG 0x2a +#define Z8536_PC_DPP_REG 0x05 + +/* + * Port A/B/C Data Direction registers + * + * 0 = Output bit + * 1 = Input bit + */ +#define Z8536_PA_DD_REG 0x23 +#define Z8536_PB_DD_REG 0x2b +#define Z8536_PC_DD_REG 0x06 + +/* + * Port A/B/C Special I/O Control registers + * + * 0 = Normal Input or Output + * 1 = Output with open drain or Input with 1's catcher + */ +#define Z8536_PA_SIO_REG 0x24 +#define Z8536_PB_SIO_REG 0x2c +#define Z8536_PC_SIO_REG 0x07 + +/* + * Port A/B Pattern Polarity/Transition/Mask registers + * + * PM PT PP Pattern Specification + * -- -- -- ------------------------------------- + * 0 0 x Bit masked off + * 0 1 x Any transition + * 1 0 0 Zero (low-level) + * 1 0 1 One (high-level) + * 1 1 0 One-to-zero transition (falling-edge) + * 1 1 1 Zero-to-one transition (rising-edge) + */ +#define Z8536_PA_PP_REG 0x25 +#define Z8536_PB_PP_REG 0x2d + +#define Z8536_PA_PT_REG 0x26 +#define Z8536_PB_PT_REG 0x2e + +#define Z8536_PA_PM_REG 0x27 +#define Z8536_PB_PM_REG 0x2f + +#endif /* _Z8536_H */ |