diff options
Diffstat (limited to 'drivers/staging/comedi')
160 files changed, 3854 insertions, 8300 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 87e852a0ef49..8c8a55132257 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -110,15 +110,6 @@ menuconfig COMEDI_ISA_DRIVERS if COMEDI_ISA_DRIVERS -config COMEDI_ACL7225B - tristate "ADlink NuDAQ ACL-7225b and compatibles support" - ---help--- - Enable support for ADlink NuDAQ ACL-7225b and compatibles, - ADlink ACL-7225b (acl7225b), ICP P16R16DIO (p16r16dio) - - To compile this driver as a module, choose M here: the module will be - called acl7225b. - config COMEDI_PCL711 tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support" ---help--- @@ -137,14 +128,6 @@ config COMEDI_PCL724 To compile this driver as a module, choose M here: the module will be called pcl724. -config COMEDI_PCL725 - tristate "Advantech PCL-725 and compatible ISA card support" - ---help--- - Enable support for Advantech PCL-725 and compatible ISA cards. - - To compile this driver as a module, choose M here: the module will be - called pcl725. - config COMEDI_PCL726 tristate "Advantech PCL-726 and compatible ISA card support" ---help--- @@ -154,10 +137,21 @@ config COMEDI_PCL726 called pcl726. config COMEDI_PCL730 - tristate "Advantech PCL-730 and ADlink ACL-7130 ISA card support" + tristate "Simple Digital I/O board support (8-bit ports)" ---help--- - Enable support for Advantech PCL-730, ICP ISO-730 and ADlink - ACL-7130 ISA cards + Enable support for various simple ISA or PC/104 Digital I/O boards. + These boards all use 8-bit I/O ports. + + Advantech PCL-730 isolated - 16 in/16 out ttl - 16 in/16 out + ICP ISO-730 isolated - 16 in/16 out ttl - 16 in/16 out + ADlink ACL-7130 isolated - 16 in/16 out ttl - 16 in/16 out + Advantech PCM-3730 isolated - 8 in/8 out ttl - 16 in/16 out + Advantech PCL-725 isolated - 8 in/8 out + ICP P8R8-DIO isolated - 8 in/8 out + ADlink ACL-7225b isolated - 16 in/16 out + ICP P16R16-DIO isolated - 16 in/16 out + Advantech PCL-733 isolated - 32 in + Advantech PCL-734 isolated - 32 out To compile this driver as a module, choose M here: the module will be called pcl730. @@ -201,14 +195,6 @@ config COMEDI_PCM3724 To compile this driver as a module, choose M here: the module will be called pcm3724. -config COMEDI_PCM3730 - tristate "Advantech PCM-3730 and clone PC/104 board support" - ---help--- - Enable support for Advantech PCM-3730 and clone PC/104 boards - - To compile this driver as a module, choose M here: the module will be - called pcm3730. - config COMEDI_AMPLC_DIO200_ISA tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E" select COMEDI_AMPLC_DIO200 @@ -543,12 +529,19 @@ config COMEDI_POC tristate "Generic driver for very simple devices" ---help--- Enable generic support for very simple / POC (Piece of Crap) boards, - Keithley Metrabyte DAC-02 (dac02), Advantech PCL-733 (pcl733) and - PCL-734 (pcl734) + Keithley Metrabyte DAC-02 (dac02). To compile this driver as a module, choose M here: the module will be called poc. +config COMEDI_S526 + tristate "Sensoray s526 support" + ---help--- + Enable support for Sensoray s526 + + To compile this driver as a module, choose M here: the module will be + called s526. + endif # COMEDI_ISA_DRIVERS menuconfig COMEDI_PCI_DRIVERS @@ -1076,14 +1069,6 @@ config COMEDI_RTD520 To compile this driver as a module, choose M here: the module will be called rtd520. -config COMEDI_S526 - tristate "Sensoray s526 support" - ---help--- - Enable support for Sensoray s526 - - To compile this driver as a module, choose M here: the module will be - called s526. - config COMEDI_S626 tristate "Sensoray 626 support" select COMEDI_FC diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index 4233605df30a..6bbbe5b08954 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_H diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index d4be0e68509b..b4c001b6f88f 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "comedidev.h" diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index ad208cdd53d4..2dfb06aedb15 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #include <linux/uaccess.h> diff --git a/drivers/staging/comedi/comedi_compat32.h b/drivers/staging/comedi/comedi_compat32.h index 60cf51c4a793..28e3c3059037 100644 --- a/drivers/staging/comedi/comedi_compat32.h +++ b/drivers/staging/comedi/comedi_compat32.h @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_COMPAT32_H diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 924c54c9c31f..8647518259f6 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #undef DEBUG @@ -536,6 +531,23 @@ static bool comedi_is_subdevice_idle(struct comedi_subdevice *s) return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true; } +/** + * comedi_alloc_spriv() - Allocate memory for the subdevice private data. + * @s: comedi_subdevice struct + * @size: size of the memory to allocate + * + * This also sets the subdevice runflags to allow the core to automatically + * free the private data during the detach. + */ +void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size) +{ + s->private = kzalloc(size, GFP_KERNEL); + if (s->private) + comedi_set_subdevice_runflags(s, ~0, SRF_FREE_SPRIV); + return s->private; +} +EXPORT_SYMBOL_GPL(comedi_alloc_spriv); + /* This function restores a subdevice to an idle state. */ @@ -665,7 +677,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, if (copy_from_user(&bc, arg, sizeof(bc))) return -EFAULT; - if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0) + if (bc.subdevice >= dev->n_subdevices) return -EINVAL; s = &dev->subdevices[bc.subdevice]; @@ -918,7 +930,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, if (copy_from_user(&bi, arg, sizeof(bi))) return -EFAULT; - if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0) + if (bi.subdevice >= dev->n_subdevices) return -EINVAL; s = &dev->subdevices[bi.subdevice]; @@ -2317,9 +2329,6 @@ static int comedi_close(struct inode *inode, struct file *file) mutex_unlock(&dev->mutex); - if (file->f_flags & FASYNC) - comedi_fasync(-1, file, 0); - return 0; } diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/staging/comedi/comedi_pci.c index 5fad084cfbd4..abbc0e4f5c51 100644 --- a/drivers/staging/comedi/comedi_pci.c +++ b/drivers/staging/comedi/comedi_pci.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/pci.h> diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/staging/comedi/comedi_pcmcia.c index 453ff3b28617..9d49d5d01ad9 100644 --- a/drivers/staging/comedi/comedi_pcmcia.c +++ b/drivers/staging/comedi/comedi_pcmcia.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/staging/comedi/comedi_usb.c index 9d9716a248f1..13f18bef6091 100644 --- a/drivers/staging/comedi/comedi_usb.c +++ b/drivers/staging/comedi/comedi_usb.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/usb.h> @@ -35,6 +31,18 @@ struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_to_usb_interface); /** + * comedi_to_usb_dev() - comedi_device pointer to usb_device pointer. + * @dev: comedi_device struct + */ +struct usb_device *comedi_to_usb_dev(struct comedi_device *dev) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + + return intf ? interface_to_usbdev(intf) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_usb_dev); + +/** * comedi_usb_auto_config() - Configure/probe a comedi USB driver. * @intf: usb_interface struct * @driver: comedi_driver struct diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index cdd472094cee..b75915f30f48 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDIDEV_H @@ -270,11 +265,14 @@ enum subdevice_runflags { /* indicates an COMEDI_CB_ERROR event has occurred since the last * command was started */ SRF_ERROR = 0x00000004, - SRF_RUNNING = 0x08000000 + SRF_RUNNING = 0x08000000, + SRF_FREE_SPRIV = 0x80000000, /* free s->private on detach */ }; bool comedi_is_subdevice_running(struct comedi_subdevice *s); +void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size); + int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist); @@ -312,6 +310,18 @@ struct comedi_lrange { struct comedi_krange range[GCC_ZERO_LENGTH_ARRAY]; }; +static inline bool comedi_range_is_bipolar(struct comedi_subdevice *s, + unsigned int range) +{ + return s->range_table->range[range].min < 0; +} + +static inline bool comedi_range_is_unipolar(struct comedi_subdevice *s, + unsigned int range) +{ + return s->range_table->range[range].min >= 0; +} + /* some silly little inline functions */ static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) @@ -349,7 +359,12 @@ void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, int comedi_alloc_subdevices(struct comedi_device *, int); -void comedi_spriv_free(struct comedi_device *, int subdev_num); +int comedi_load_firmware(struct comedi_device *, struct device *, + const char *name, + int (*cb)(struct comedi_device *, + const u8 *data, size_t size, + unsigned long context), + unsigned long context); int __comedi_request_region(struct comedi_device *, unsigned long start, unsigned long len); @@ -489,6 +504,7 @@ struct usb_driver; struct usb_interface; struct usb_interface *comedi_to_usb_interface(struct comedi_device *); +struct usb_device *comedi_to_usb_dev(struct comedi_device *); int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *, unsigned long context); diff --git a/drivers/staging/comedi/comedilib.h b/drivers/staging/comedi/comedilib.h index ca92c43fdb38..1a78b15543c4 100644 --- a/drivers/staging/comedi/comedilib.h +++ b/drivers/staging/comedi/comedilib.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _LINUX_COMEDILIB_H diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 06d190f8fd34..e25eba5713c1 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #include <linux/device.h> @@ -38,6 +33,7 @@ #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/interrupt.h> +#include <linux/firmware.h> #include "comedidev.h" #include "comedi_internal.h" @@ -87,18 +83,6 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) } EXPORT_SYMBOL_GPL(comedi_alloc_subdevices); -void comedi_spriv_free(struct comedi_device *dev, int subdev_num) -{ - struct comedi_subdevice *s; - - if (dev->subdevices && subdev_num < dev->n_subdevices) { - s = &dev->subdevices[subdev_num]; - kfree(s->private); - s->private = NULL; - } -} -EXPORT_SYMBOL_GPL(comedi_spriv_free); - static void cleanup_device(struct comedi_device *dev) { int i; @@ -107,6 +91,8 @@ static void cleanup_device(struct comedi_device *dev) if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; + if (s->runflags & SRF_FREE_SPRIV) + kfree(s->private); comedi_free_subdevice_minor(s); if (s->async) { comedi_buf_alloc(dev, s, 0); @@ -352,6 +338,38 @@ static void comedi_report_boards(struct comedi_driver *driv) } /** + * comedi_load_firmware() - Request and load firmware for a device. + * @dev: comedi_device struct + * @hw_device: device struct for the comedi_device + * @name: the name of the firmware image + * @cb: callback to the upload the firmware image + * @context: private context from the driver + */ +int comedi_load_firmware(struct comedi_device *dev, + struct device *device, + const char *name, + int (*cb)(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context), + unsigned long context) +{ + const struct firmware *fw; + int ret; + + if (!cb) + return -EINVAL; + + ret = request_firmware(&fw, name, device); + if (ret == 0) { + ret = cb(dev, fw->data, fw->size, context); + release_firmware(fw); + } + + return ret; +} +EXPORT_SYMBOL_GPL(comedi_load_firmware); + +/** * __comedi_request_region() - Request an I/O reqion for a legacy driver. * @dev: comedi_device struct * @start: base address of the I/O reqion diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index 429e0d60c0a3..3abedcd2527b 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _8253_H diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 1d48aa602ece..94e17500150f 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: 8255 @@ -81,7 +76,6 @@ I/O port base address can be found in the output of 'lspci -v'. #include "../comedidev.h" #include <linux/ioport.h> -#include <linux/slab.h> #include "comedi_fc.h" #include "8255.h" @@ -290,15 +284,13 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, { struct subdev_8255_private *spriv; - spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); if (!spriv) return -ENOMEM; spriv->iobase = iobase; spriv->io = io ? io : subdev_8255_io; - s->private = spriv; - s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 24; @@ -391,7 +383,6 @@ static void dev_8255_detach(struct comedi_device *dev) spriv = s->private; release_region(spriv->iobase, _8255_SIZE); } - comedi_spriv_free(dev, i); } } diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index 0f6e7492b7db..4f16ea78f86a 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _8255_H diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index 76dec96aeb2a..3d3547c19480 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -19,10 +19,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -242,10 +238,7 @@ static int pci_8255_auto_attach(struct comedi_device *dev, static void pci_8255_detach(struct comedi_device *dev) { struct pci_8255_private *devpriv = dev->private; - int i; - for (i = 0; i < dev->n_subdevices; i++) - comedi_spriv_free(dev, i); if (devpriv && devpriv->mmio_base) iounmap(devpriv->mmio_base); comedi_pci_disable(dev); diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 57e984f0f462..dbb93e332487 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -11,19 +11,16 @@ obj-$(CONFIG_COMEDI_SERIAL2002) += serial2002.o obj-$(CONFIG_COMEDI_SKEL) += skel.o # Comedi ISA drivers -obj-$(CONFIG_COMEDI_ACL7225B) += acl7225b.o obj-$(CONFIG_COMEDI_AMPLC_DIO200_ISA) += amplc_dio200.o obj-$(CONFIG_COMEDI_AMPLC_PC263_ISA) += amplc_pc263.o obj-$(CONFIG_COMEDI_PCL711) += pcl711.o obj-$(CONFIG_COMEDI_PCL724) += pcl724.o -obj-$(CONFIG_COMEDI_PCL725) += pcl725.o obj-$(CONFIG_COMEDI_PCL726) += pcl726.o obj-$(CONFIG_COMEDI_PCL730) += pcl730.o obj-$(CONFIG_COMEDI_PCL812) += pcl812.o obj-$(CONFIG_COMEDI_PCL816) += pcl816.o obj-$(CONFIG_COMEDI_PCL818) += pcl818.o obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o -obj-$(CONFIG_COMEDI_PCM3730) += pcm3730.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o @@ -55,6 +52,7 @@ obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o obj-$(CONFIG_COMEDI_POC) += poc.o +obj-$(CONFIG_COMEDI_S526) += s526.o # Comedi PCI drivers obj-$(CONFIG_COMEDI_8255_PCI) += 8255_pci.o @@ -110,7 +108,6 @@ obj-$(CONFIG_COMEDI_NI_LABPC_PCI) += ni_labpc_pci.o obj-$(CONFIG_COMEDI_NI_PCIDIO) += ni_pcidio.o obj-$(CONFIG_COMEDI_NI_PCIMIO) += ni_pcimio.o obj-$(CONFIG_COMEDI_RTD520) += rtd520.o -obj-$(CONFIG_COMEDI_S526) += s526.o obj-$(CONFIG_COMEDI_S626) += s626.o obj-$(CONFIG_COMEDI_SSV_DNP) += ssv_dnp.o diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c deleted file mode 100644 index 9e2c7aeea535..000000000000 --- a/drivers/staging/comedi/drivers/acl7225b.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * comedi/drivers/acl7225b.c - * Driver for Adlink NuDAQ ACL-7225b and clones - * José Luis Sánchez - */ -/* -Driver: acl7225b -Description: Adlink NuDAQ ACL-7225b & compatibles -Author: José Luis Sánchez (jsanchezv@teleline.es) -Status: testing -Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio) -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -#define ACL7225_RIO_LO 0 /* Relays input/output low byte (R0-R7) */ -#define ACL7225_RIO_HI 1 /* Relays input/output high byte (R8-R15) */ -#define ACL7225_DI_LO 2 /* Digital input low byte (DI0-DI7) */ -#define ACL7225_DI_HI 3 /* Digital input high byte (DI8-DI15) */ - -struct acl7225b_boardinfo { - const char *name; - int io_range; -}; - -static const struct acl7225b_boardinfo acl7225b_boards[] = { - { - .name = "acl7225b", - .io_range = 8, /* only 4 are used */ - }, { - .name = "p16r16dio", - .io_range = 4, - }, -}; - -static int acl7225b_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned long reg = (unsigned long)s->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - - if (mask & 0x00ff) - outb(s->state & 0xff, dev->iobase + reg); - if (mask & 0xff00) - outb((s->state >> 8), dev->iobase + reg + 1); - } - - data[1] = s->state; - - return insn->n; -} - -static int acl7225b_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned long reg = (unsigned long)s->private; - - data[1] = inb(dev->iobase + reg) | - (inb(dev->iobase + reg + 1) << 8); - - return insn->n; -} - -static int acl7225b_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - const struct acl7225b_boardinfo *board = comedi_board(dev); - struct comedi_subdevice *s; - int ret; - - ret = comedi_request_region(dev, it->options[0], board->io_range); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 3); - if (ret) - return ret; - - s = &dev->subdevices[0]; - /* Relays outputs */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = acl7225b_do_insn_bits; - s->range_table = &range_digital; - s->private = (void *)ACL7225_RIO_LO; - - s = &dev->subdevices[1]; - /* Relays status */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = acl7225b_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)ACL7225_RIO_LO; - - s = &dev->subdevices[2]; - /* Isolated digital inputs */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = acl7225b_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)ACL7225_DI_LO; - - return 0; -} - -static struct comedi_driver acl7225b_driver = { - .driver_name = "acl7225b", - .module = THIS_MODULE, - .attach = acl7225b_attach, - .detach = comedi_legacy_detach, - .board_name = &acl7225b_boards[0].name, - .num_names = ARRAY_SIZE(acl7225b_boards), - .offset = sizeof(struct acl7225b_boardinfo), -}; -module_comedi_driver(acl7225b_driver); - -MODULE_DESCRIPTION("Comedi: NuDAQ ACL-7225B, 16 Relay & 16 Isolated DI Card"); -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c index 5bd7fe64637c..d91f586fdd26 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c index 6b38ce7a275b..27de18e79895 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c index 70a7f953fa2f..c9db601da2c9 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c index be0c6adbdc94..6bbcb06cc279 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c index a211e78dd3ba..5c830337db85 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c index 97e7eec343d7..6ef1d6a434d9 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c index 3bc9826ce40b..0b79531ac24b 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c index c8238b8921cd..fb56360444ee 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 0c3db57a50f4..f25e0085219d 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -20,13 +20,6 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this -source code. - @endverbatim */ /* @@ -46,10 +39,6 @@ source code. +-----------------------------------------------------------------------+ */ -#ifndef COMEDI_SUBD_TTLIO -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#endif - static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -105,23 +94,14 @@ static int addi_auto_attach(struct comedi_device *dev, if (ret) return ret; - if (!this_board->pc_EepromChip || - strcmp(this_board->pc_EepromChip, ADDIDATA_9054)) { - /* board does not have an eeprom or is not ADDIDATA_9054 */ - if (this_board->i_IorangeBase1) - dev->iobase = pci_resource_start(pcidev, 1); - else - dev->iobase = pci_resource_start(pcidev, 0); - - devpriv->iobase = dev->iobase; - devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); - devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); - } else { - /* board has an ADDIDATA_9054 eeprom */ - dev->iobase = pci_resource_start(pcidev, 2); - devpriv->iobase = pci_resource_start(pcidev, 2); - devpriv->dw_AiBase = pci_ioremap_bar(pcidev, 3); - } + if (this_board->i_IorangeBase1) + dev->iobase = pci_resource_start(pcidev, 1); + else + dev->iobase = pci_resource_start(pcidev, 0); + + devpriv->iobase = dev->iobase; + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); /* Initialize parameters that can be overridden in EEPROM */ @@ -132,7 +112,6 @@ static int addi_auto_attach(struct comedi_device *dev, devpriv->s_EeParameters.i_NbrDiChannel = this_board->i_NbrDiChannel; devpriv->s_EeParameters.i_NbrDoChannel = this_board->i_NbrDoChannel; devpriv->s_EeParameters.i_DoMaxdata = this_board->i_DoMaxdata; - devpriv->s_EeParameters.i_Dma = this_board->i_Dma; devpriv->s_EeParameters.i_Timer = this_board->i_Timer; devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = this_board->ui_MinAcquisitiontimeNs; @@ -191,9 +170,6 @@ static int addi_auto_attach(struct comedi_device *dev, s->len_chanlist = this_board->i_AiChannelList; s->range_table = this_board->pr_AiRangelist; - /* Set the initialisation flag */ - devpriv->b_AiInitialisation = 1; - s->insn_config = this_board->ai_config; s->insn_read = this_board->ai_read; s->insn_write = this_board->ai_write; @@ -215,8 +191,6 @@ static int addi_auto_attach(struct comedi_device *dev, s->maxdata = devpriv->s_EeParameters.i_AoMaxdata; s->len_chanlist = devpriv->s_EeParameters.i_NbrAoChannel; - s->range_table = this_board->pr_AoRangelist; - s->insn_config = this_board->ao_config; s->insn_write = this_board->ao_write; } else { s->type = COMEDI_SUBD_UNUSED; @@ -281,22 +255,7 @@ static int addi_auto_attach(struct comedi_device *dev, /* Allocate and Initialise TTL */ s = &dev->subdevices[5]; - if (this_board->i_NbrTTLChannel) { - s->type = COMEDI_SUBD_TTLIO; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->i_NbrTTLChannel; - s->maxdata = 1; - s->io_bits = 0; /* all bits input */ - s->len_chanlist = this_board->i_NbrTTLChannel; - s->range_table = &range_digital; - s->insn_config = this_board->ttl_config; - s->insn_bits = this_board->ttl_bits; - s->insn_read = this_board->ttl_read; - s->insn_write = this_board->ttl_write; - } else { - s->type = COMEDI_SUBD_UNUSED; - } + s->type = COMEDI_SUBD_UNUSED; /* EEPROM */ s = &dev->subdevices[6]; @@ -323,8 +282,6 @@ static void i_ADDI_Detach(struct comedi_device *dev) i_ADDI_Reset(dev); if (dev->irq) free_irq(dev->irq, dev); - if (devpriv->dw_AiBase) - iounmap(devpriv->dw_AiBase); } comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index c034bf1426eb..f1be5ade9962 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -18,12 +18,8 @@ #include <linux/sched.h> #include <linux/interrupt.h> -#define LOBYTE(W) (unsigned char)((W) & 0xFF) -#define HIBYTE(W) (unsigned char)(((W) >> 8) & 0xFF) -#define MAKEWORD(H, L) (unsigned short)((L) | ((H) << 8)) #define LOWORD(W) (unsigned short)((W) & 0xFFFF) #define HIWORD(W) (unsigned short)(((W) >> 16) & 0xFFFF) -#define MAKEDWORD(H, L) (unsigned int)((L) | ((H) << 16)) #define ADDI_ENABLE 1 #define ADDI_DISABLE 0 @@ -33,8 +29,6 @@ #define ADDIDATA_NO_EEPROM 0 #define ADDIDATA_93C76 "93C76" #define ADDIDATA_S5920 "S5920" -#define ADDIDATA_S5933 "S5933" -#define ADDIDATA_9054 "9054" /* ADDIDATA Enable Disable */ #define ADDIDATA_ENABLE 1 @@ -55,17 +49,12 @@ struct addi_board { int i_AiMaxdata; /* resolution of A/D */ int i_AoMaxdata; /* resolution of D/A */ const struct comedi_lrange *pr_AiRangelist; /* rangelist for A/D */ - const struct comedi_lrange *pr_AoRangelist; /* rangelist for D/A */ int i_NbrDiChannel; /* Number of DI channels */ int i_NbrDoChannel; /* Number of DO channels */ int i_DoMaxdata; /* data to set all channels high */ - int i_NbrTTLChannel; /* Number of TTL channels */ - - int i_Dma; /* dma present or not */ int i_Timer; /* timer subdevice present or not */ - unsigned char b_AvailableConvertUnit; unsigned int ui_MinAcquisitiontimeNs; /* Minimum Acquisition in Nano secs */ unsigned int ui_MinDelaytimeNs; /* Minimum Delay in Nano secs */ @@ -90,12 +79,8 @@ struct addi_board { int (*ai_cancel)(struct comedi_device *, struct comedi_subdevice *); /* Analog Output */ - int (*ao_config)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); int (*ao_write)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*ao_bits)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); /* Digital Input */ int (*di_config)(struct comedi_device *, struct comedi_subdevice *, @@ -126,16 +111,6 @@ struct addi_board { struct comedi_insn *, unsigned int *); int (*timer_bits)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - - /* TTL IO */ - int (*ttl_config)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*ttl_bits)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*ttl_read)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*ttl_write)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); }; /* MODULE INFO STRUCTURE */ @@ -283,58 +258,41 @@ union str_ModuleInfo { /* Private structure for the addi_apci3120 driver */ struct addi_private { - int iobase; int i_IobaseAmcc; /* base+size for AMCC chip */ int i_IobaseAddon; /* addon base address */ int i_IobaseReserved; - void __iomem *dw_AiBase; unsigned char b_AiContinuous; /* we do unlimited AI */ - unsigned char b_AiInitialisation; unsigned int ui_AiActualScan; /* how many scans we finished */ - unsigned int ui_AiBufferPtr; /* data buffer ptr in samples */ unsigned int ui_AiNbrofChannels; /* how many channels is measured */ unsigned int ui_AiScanLength; /* Length of actual scanlist */ - unsigned int ui_AiActualScanPosition; /* position in actual scan */ unsigned int *pui_AiChannelList; /* actual chanlist */ unsigned int ui_AiChannelList[32]; /* actual chanlist */ - unsigned char b_AiChannelConfiguration[32]; /* actual chanlist */ unsigned int ui_AiReadData[32]; - unsigned int dw_AiInitialised; unsigned int ui_AiTimer0; /* Timer Constant for Timer0 */ unsigned int ui_AiTimer1; /* Timer constant for Timer1 */ unsigned int ui_AiFlags; unsigned int ui_AiDataLength; - short *AiData; /* Pointer to sample data */ unsigned int ui_AiNbrofScans; /* number of scans to do */ unsigned short us_UseDma; /* To use Dma or not */ unsigned char b_DmaDoubleBuffer; /* we can use double buffering */ unsigned int ui_DmaActualBuffer; /* which buffer is used now */ - /* UPDATE-0.7.57->0.7.68 */ - /* unsigned int ul_DmaBufferVirtual[2]; pointers to begin of DMA buffer */ short *ul_DmaBufferVirtual[2]; /* pointers to begin of DMA buffer */ unsigned int ul_DmaBufferHw[2]; /* hw address of DMA buff */ unsigned int ui_DmaBufferSize[2]; /* size of dma buffer in bytes */ unsigned int ui_DmaBufferUsesize[2]; /* which size we may now used for transfer */ - unsigned int ui_DmaBufferSamples[2]; /* size in samples */ unsigned int ui_DmaBufferPages[2]; /* number of pages in buffer */ unsigned char b_DigitalOutputRegister; /* Digital Output Register */ unsigned char b_OutputMemoryStatus; - unsigned char b_AnalogInputChannelNbr; /* Analog input channel Nbr */ - unsigned char b_AnalogOutputChannelNbr; /* Analog input Output Nbr */ unsigned char b_TimerSelectMode; /* Contain data written at iobase + 0C */ unsigned char b_ModeSelectRegister; /* Contain data written at iobase + 0E */ unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */ - unsigned char b_InterruptState; - unsigned char b_TimerInit; /* Specify if InitTimerWatchdog was load */ - unsigned char b_TimerStarted; /* Specify if timer 2 is running or not */ unsigned char b_Timer2Mode; /* Specify the timer 2 mode */ unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */ unsigned char b_AiCyclicAcquisition; /* indicate cyclic acquisition */ unsigned char b_InterruptMode; /* eoc eos or dma */ unsigned char b_EocEosInterrupt; /* Enable disable eoc eos interrupt */ unsigned int ui_EocEosConversionTime; - unsigned char b_EocEosConversionTimeBase; unsigned char b_SingelDiff; unsigned char b_ExttrigEnable; /* To enable or disable external trigger */ @@ -365,7 +323,6 @@ struct addi_private { } s_InterruptParameters; union str_ModuleInfo s_ModuleInfo[4]; - unsigned int ul_TTLPortConfiguration[10]; /* Parameters read from EEPROM overriding static board info */ struct { @@ -376,7 +333,6 @@ struct addi_private { int i_NbrDiChannel; /* Number of DI channels */ int i_NbrDoChannel; /* Number of DO channels */ int i_DoMaxdata; /* data to set all channels high */ - int i_Dma; /* dma present or not */ int i_Timer; /* timer subdevice present or not */ unsigned int ui_MinAcquisitiontimeNs; /* Minimum Acquisition in Nano secs */ diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c index 5124ac9f1818..dc031c494a27 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c @@ -20,13 +20,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * You should also find the complete GPL in the COPYING file accompanying - * this source code. */ #define NVRAM_USER_DATA_START 0x100 @@ -302,7 +295,7 @@ static void addi_eeprom_read_ai_info(struct comedi_device *dev, devpriv->s_EeParameters.ui_MinDelaytimeNs = tmp * 1000; tmp = addi_eeprom_readw(iobase, type, addr + 20); - devpriv->s_EeParameters.i_Dma = (tmp >> 13) & 0x01; + /* dma = (tmp >> 13) & 0x01; */ tmp = addi_eeprom_readw(iobase, type, addr + 72) & 0xff; if (tmp) { /* > 0 */ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c index b05f8505c894..b1a7ec1035e1 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index 3d66e48e0cf7..1128c22e7517 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 24c4c983db38..054910511e9e 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index fc31c4b93407..e3cc429403c0 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index 74065baa3c08..a89e505c8a3a 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* @@ -724,9 +720,7 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, inb(dev->iobase + APCI3120_RESET_FIFO); inw(dev->iobase + APCI3120_RD_STATUS); devpriv->ui_AiActualScan = 0; - devpriv->ui_AiActualScanPosition = 0; s->async->cur_chan = 0; - devpriv->ui_AiBufferPtr = 0; devpriv->b_AiContinuous = 0; devpriv->ui_DmaActualBuffer = 0; @@ -895,9 +889,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ devpriv->ui_AiActualScan = 0; - devpriv->ui_AiActualScanPosition = 0; s->async->cur_chan = 0; - devpriv->ui_AiBufferPtr = 0; devpriv->ui_DmaActualBuffer = 0; /* value for timer2 minus -2 has to be done .....dunno y?? */ @@ -1351,8 +1343,6 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, devpriv->ui_AiScanLength = cmd->scan_end_arg; devpriv->pui_AiChannelList = cmd->chanlist; - /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */ - devpriv->AiData = s->async->prealloc_buf; /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */ devpriv->ui_AiDataLength = s->async->prealloc_bufsz; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index c7908730caa5..32dce0329fd5 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c deleted file mode 100644 index a45a2a26e0da..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c +++ /dev/null @@ -1,1376 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : APCI-3XXX | Compiler : GCC | - | Module name : hwdrv_apci3xxx.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: S. Weber | Date : 15/09/2005 | - +-----------------------------------------------------------------------+ - | Description :APCI3XXX Module. Hardware abstraction Layer for APCI3XXX| - +-----------------------------------------------------------------------+ - | UPDATE'S | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -#ifndef COMEDI_SUBD_TTLIO -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#endif - -#define APCI3XXX_SINGLE 0 -#define APCI3XXX_DIFF 1 -#define APCI3XXX_CONFIGURATION 0 - -#define APCI3XXX_TTL_INIT_DIRECTION_PORT2 0 - -static const struct comedi_lrange range_apci3XXX_ai = { - 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -static const struct comedi_lrange range_apci3XXX_ao = { - 2, { - BIP_RANGE(10), - UNI_RANGE(10) - } -}; - -/* -+----------------------------------------------------------------------------+ -| ANALOG INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_TestConversionStarted | -| (struct comedi_device *dev) | -+----------------------------------------------------------------------------+ -| Task Test if any conversion started | -+----------------------------------------------------------------------------+ -| Input Parameters : - | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 : Conversion not started | -| 1 : Conversion started | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_TestConversionStarted(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - - if ((readl(devpriv->dw_AiBase + 8) & 0x80000UL) == 0x80000UL) - return 1; - else - return 0; - -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_AnalogInputConfigOperatingMode | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Converting mode and convert time selection | -+----------------------------------------------------------------------------+ -| Input Parameters : b_SingleDiff = (unsigned char) data[1]; | -| b_TimeBase = (unsigned char) data[2]; (0: ns, 1:micros 2:ms)| -| dw_ReloadValue = (unsigned int) data[3]; | -| ........ | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0 : No error | -| -1 : Single/Diff selection error | -| -2 : Convert time base unity selection error | -| -3 : Convert time value selection error | -| -10: Any conversion started | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct addi_board *this_board = comedi_board(dev); - struct addi_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_TimeBase = 0; - unsigned char b_SingleDiff = 0; - unsigned int dw_ReloadValue = 0; - unsigned int dw_TestReloadValue = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n == 4) { - /****************************/ - /* Get the Singel/Diff flag */ - /****************************/ - - b_SingleDiff = (unsigned char) data[1]; - - /****************************/ - /* Get the time base unitiy */ - /****************************/ - - b_TimeBase = (unsigned char) data[2]; - - /*************************************/ - /* Get the convert time reload value */ - /*************************************/ - - dw_ReloadValue = (unsigned int) data[3]; - - /**********************/ - /* Test the time base */ - /**********************/ - - if ((this_board->b_AvailableConvertUnit & (1 << b_TimeBase)) != - 0) { - /*******************************/ - /* Test the convert time value */ - /*******************************/ - - if (dw_ReloadValue <= 65535) { - dw_TestReloadValue = dw_ReloadValue; - - if (b_TimeBase == 1) { - dw_TestReloadValue = - dw_TestReloadValue * 1000UL; - } - if (b_TimeBase == 2) { - dw_TestReloadValue = - dw_TestReloadValue * 1000000UL; - } - - /*******************************/ - /* Test the convert time value */ - /*******************************/ - - if (dw_TestReloadValue >= - devpriv->s_EeParameters. - ui_MinAcquisitiontimeNs) { - if ((b_SingleDiff == APCI3XXX_SINGLE) - || (b_SingleDiff == - APCI3XXX_DIFF)) { - if (((b_SingleDiff == APCI3XXX_SINGLE) - && (devpriv->s_EeParameters.i_NbrAiChannel == 0)) - || ((b_SingleDiff == APCI3XXX_DIFF) - && (this_board->i_NbrAiChannelDiff == 0)) - ) { - /*******************************/ - /* Single/Diff selection error */ - /*******************************/ - - printk("Single/Diff selection error\n"); - i_ReturnValue = -1; - } else { - /**********************************/ - /* Test if conversion not started */ - /**********************************/ - - if (i_APCI3XXX_TestConversionStarted(dev) == 0) { - devpriv-> - ui_EocEosConversionTime - = - (unsigned int) - dw_ReloadValue; - devpriv-> - b_EocEosConversionTimeBase - = - b_TimeBase; - devpriv-> - b_SingelDiff - = - b_SingleDiff; - devpriv-> - b_AiInitialisation - = 1; - - /*******************************/ - /* Set the convert timing unit */ - /*******************************/ - - writel((unsigned int)b_TimeBase, - devpriv->dw_AiBase + 36); - - /**************************/ - /* Set the convert timing */ - /*************************/ - - writel(dw_ReloadValue, devpriv->dw_AiBase + 32); - } else { - /**************************/ - /* Any conversion started */ - /**************************/ - - printk("Any conversion started\n"); - i_ReturnValue = - -10; - } - } - } else { - /*******************************/ - /* Single/Diff selection error */ - /*******************************/ - - printk("Single/Diff selection error\n"); - i_ReturnValue = -1; - } - } else { - /************************/ - /* Time selection error */ - /************************/ - - printk("Convert time value selection error\n"); - i_ReturnValue = -3; - } - } else { - /************************/ - /* Time selection error */ - /************************/ - - printk("Convert time value selection error\n"); - i_ReturnValue = -3; - } - } else { - /*****************************/ - /* Time base selection error */ - /*****************************/ - - printk("Convert time base unity selection error\n"); - i_ReturnValue = -2; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnConfigAnalogInput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Converting mode and convert time selection | -+----------------------------------------------------------------------------+ -| Input Parameters : b_ConvertMode = (unsigned char) data[0]; | -| b_TimeBase = (unsigned char) data[1]; (0: ns, 1:micros 2:ms)| -| dw_ReloadValue = (unsigned int) data[2]; | -| ........ | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - switch ((unsigned char) data[0]) { - case APCI3XXX_CONFIGURATION: - i_ReturnValue = - i_APCI3XXX_AnalogInputConfigOperatingMode(dev, - s, insn, data); - break; - - default: - i_ReturnValue = -100; - printk("Config command error %d\n", data[0]); - break; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnReadAnalogInput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Read 1 analog input | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Range = CR_RANGE(insn->chanspec); | -| b_Channel = CR_CHAN(insn->chanspec); | -| dw_NbrOfAcquisition = insn->n; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -3 : Channel selection error | -| -4 : Configuration selelection error | -| -10: Any conversion started | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct addi_board *this_board = comedi_board(dev); - struct addi_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_Configuration = (unsigned char) CR_RANGE(insn->chanspec); - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned int dw_Temp = 0; - unsigned int dw_Configuration = 0; - unsigned int dw_AcquisitionCpt = 0; - unsigned char b_Interrupt = 0; - - /*************************************/ - /* Test if operating mode configured */ - /*************************************/ - - if (devpriv->b_AiInitialisation) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (((b_Channel < devpriv->s_EeParameters.i_NbrAiChannel) - && (devpriv->b_SingelDiff == APCI3XXX_SINGLE)) - || ((b_Channel < this_board->i_NbrAiChannelDiff) - && (devpriv->b_SingelDiff == APCI3XXX_DIFF))) { - /**********************************/ - /* Test the channel configuration */ - /**********************************/ - - if (b_Configuration > 7) { - /***************************/ - /* Channel not initialised */ - /***************************/ - - i_ReturnValue = -4; - printk("Channel %d range %d selection error\n", - b_Channel, b_Configuration); - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", b_Channel); - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /************************/ - /* Test the buffer size */ - /************************/ - - if ((b_Interrupt != 0) || ((b_Interrupt == 0) - && (insn->n >= 1))) { - /**********************************/ - /* Test if conversion not started */ - /**********************************/ - - if (i_APCI3XXX_TestConversionStarted(dev) == 0) { - /******************/ - /* Clear the FIFO */ - /******************/ - - writel(0x10000UL, devpriv->dw_AiBase + 12); - - /*******************************/ - /* Get and save the delay mode */ - /*******************************/ - - dw_Temp = readl(devpriv->dw_AiBase + 4); - dw_Temp = dw_Temp & 0xFFFFFEF0UL; - - /***********************************/ - /* Channel configuration selection */ - /***********************************/ - - writel(dw_Temp, devpriv->dw_AiBase + 4); - - /**************************/ - /* Make the configuration */ - /**************************/ - - dw_Configuration = - (b_Configuration & 3) | - ((unsigned int) (b_Configuration >> 2) - << 6) | ((unsigned int) devpriv-> - b_SingelDiff << 7); - - /***************************/ - /* Write the configuration */ - /***************************/ - - writel(dw_Configuration, - devpriv->dw_AiBase + 0); - - /*********************/ - /* Channel selection */ - /*********************/ - - writel(dw_Temp | 0x100UL, - devpriv->dw_AiBase + 4); - writel((unsigned int) b_Channel, - devpriv->dw_AiBase + 0); - - /***********************/ - /* Restaure delay mode */ - /***********************/ - - writel(dw_Temp, devpriv->dw_AiBase + 4); - - /***********************************/ - /* Set the number of sequence to 1 */ - /***********************************/ - - writel(1, devpriv->dw_AiBase + 48); - - /***************************/ - /* Save the interrupt flag */ - /***************************/ - - devpriv->b_EocEosInterrupt = - b_Interrupt; - - /*******************************/ - /* Save the number of channels */ - /*******************************/ - - devpriv->ui_AiNbrofChannels = 1; - - /******************************/ - /* Test if interrupt not used */ - /******************************/ - - if (b_Interrupt == 0) { - for (dw_AcquisitionCpt = 0; - dw_AcquisitionCpt < - insn->n; - dw_AcquisitionCpt++) { - /************************/ - /* Start the conversion */ - /************************/ - - writel(0x80000UL, devpriv->dw_AiBase + 8); - - /****************/ - /* Wait the EOS */ - /****************/ - - do { - dw_Temp = readl(devpriv->dw_AiBase + 20); - dw_Temp = dw_Temp & 1; - } while (dw_Temp != 1); - - /*************************/ - /* Read the analog value */ - /*************************/ - - data[dw_AcquisitionCpt] = (unsigned int)readl(devpriv->dw_AiBase + 28); - } - } else { - /************************/ - /* Start the conversion */ - /************************/ - - writel(0x180000UL, devpriv->dw_AiBase + 8); - } - } else { - /**************************/ - /* Any conversion started */ - /**************************/ - - printk("Any conversion started\n"); - i_ReturnValue = -10; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - printk("Operating mode not configured\n"); - i_ReturnValue = -1; - } - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function name : void v_APCI3XXX_Interrupt (int irq, | -| void *d) | -+----------------------------------------------------------------------------+ -| Task :Interrupt handler for APCI3XXX | -| When interrupt occurs this gets called. | -| First it finds which interrupt has been generated and | -| handles corresponding interrupt | -+----------------------------------------------------------------------------+ -| Input Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - | -+----------------------------------------------------------------------------+ -*/ - -static void v_APCI3XXX_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct addi_private *devpriv = dev->private; - unsigned char b_CopyCpt = 0; - unsigned int dw_Status = 0; - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - dw_Status = readl(devpriv->dw_AiBase + 16); - if ( (dw_Status & 0x2UL) == 0x2UL) { - /***********************/ - /* Reset the interrupt */ - /***********************/ - - writel(dw_Status, devpriv->dw_AiBase + 16); - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if (devpriv->b_EocEosInterrupt == 1) { - /********************************/ - /* Read all analog inputs value */ - /********************************/ - - for (b_CopyCpt = 0; - b_CopyCpt < devpriv->ui_AiNbrofChannels; - b_CopyCpt++) { - devpriv->ui_AiReadData[b_CopyCpt] = - (unsigned int)readl(devpriv->dw_AiBase + 28); - } - - /**************************/ - /* Set the interrupt flag */ - /**************************/ - - devpriv->b_EocEosInterrupt = 2; - - /**********************************************/ - /* Send a signal to from kernel to user space */ - /**********************************************/ - - send_sig(SIGIO, devpriv->tsk_Current, 0); - } - } -} - -/* -+----------------------------------------------------------------------------+ -| ANALOG OUTPUT SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnWriteAnalogOutput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Read 1 analog input | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Range = CR_RANGE(insn->chanspec); | -| b_Channel = CR_CHAN(insn->chanspec); | -| data[0] = analog value; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -3 : Channel selection error | -| -4 : Configuration selelection error | -| .... | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_Range = (unsigned char) CR_RANGE(insn->chanspec); - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned int dw_Status = 0; - int i_ReturnValue = insn->n; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (b_Channel < devpriv->s_EeParameters.i_NbrAoChannel) { - /**********************************/ - /* Test the channel configuration */ - /**********************************/ - - if (b_Range < 2) { - /***************************/ - /* Set the range selection */ - /***************************/ - - writel(b_Range, devpriv->dw_AiBase + 96); - - /**************************************************/ - /* Write the analog value to the selected channel */ - /**************************************************/ - - writel((data[0] << 8) | b_Channel, - devpriv->dw_AiBase + 100); - - /****************************/ - /* Wait the end of transfer */ - /****************************/ - - do { - dw_Status = readl(devpriv->dw_AiBase + 96); - } while ((dw_Status & 0x100) != 0x100); - } else { - /***************************/ - /* Channel not initialised */ - /***************************/ - - i_ReturnValue = -4; - printk("Channel %d range %d selection error\n", - b_Channel, b_Range); - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", b_Channel); - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| TTL FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnConfigInitTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task You must calling this function be | -| for you call any other function witch access of TTL. | -| APCI3XXX_TTL_INIT_DIRECTION_PORT2(user inputs for direction)| -+----------------------------------------------------------------------------+ -| Input Parameters : b_InitType = (unsigned char) data[0]; | -| b_Port2Mode = (unsigned char) data[1]; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -1: Port 2 mode selection is wrong | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_Command = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) { - /***************************************/ - /* Test the initialisation buffer size */ - /***************************************/ - - if ((b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) - && (insn->n != 2)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("Command selection error\n"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - /*********************************************************************************/ - /* Test if no error occur and APCI3XXX_TTL_INIT_DIRECTION_PORT2 command selected */ - /*********************************************************************************/ - - if ((i_ReturnValue >= 0) - && (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)) { - /**********************/ - /* Test the direction */ - /**********************/ - - if ((data[1] == 0) || (data[1] == 0xFF)) { - /**************************/ - /* Save the configuration */ - /**************************/ - - devpriv->ul_TTLPortConfiguration[0] = - devpriv->ul_TTLPortConfiguration[0] | data[1]; - } else { - /************************/ - /* Port direction error */ - /************************/ - - printk("Port 2 direction selection error\n"); - i_ReturnValue = -1; - } - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /***********************************/ - /* Test if TTL port initilaisation */ - /***********************************/ - - if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) { - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(data[1], devpriv->iobase + 224); - } - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| TTL INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnBitsTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Write the selected output mask and read the status from| -| all TTL channles | -+----------------------------------------------------------------------------+ -| Input Parameters : dw_ChannelMask = data [0]; | -| dw_BitMask = data [1]; | -+----------------------------------------------------------------------------+ -| Output Parameters : data[1] : All TTL channles states | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -4 : Channel mask error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_ChannelCpt = 0; - unsigned int dw_ChannelMask = 0; - unsigned int dw_BitMask = 0; - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 2) { - /*******************************/ - /* Get the channe and bit mask */ - /*******************************/ - - dw_ChannelMask = data[0]; - dw_BitMask = data[1]; - - /*************************/ - /* Test the channel mask */ - /*************************/ - - if (((dw_ChannelMask & 0XFF00FF00) == 0) && - (((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0xFF) - || (((devpriv->ul_TTLPortConfiguration[0] & - 0xFF) == 0) - && ((dw_ChannelMask & 0XFF0000) == - 0)))) { - /*********************************/ - /* Test if set/reset any channel */ - /*********************************/ - - if (dw_ChannelMask) { - /****************************************/ - /* Test if set/rest any port 0 channels */ - /****************************************/ - - if (dw_ChannelMask & 0xFF) { - /*******************************************/ - /* Read port 0 (first digital output port) */ - /*******************************************/ - - dw_Status = inl(devpriv->iobase + 80); - - for (b_ChannelCpt = 0; b_ChannelCpt < 8; - b_ChannelCpt++) { - if ((dw_ChannelMask >> - b_ChannelCpt) & - 1) { - dw_Status = - (dw_Status & - (0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt)); - } - } - - outl(dw_Status, devpriv->iobase + 80); - } - - /****************************************/ - /* Test if set/rest any port 2 channels */ - /****************************************/ - - if (dw_ChannelMask & 0xFF0000) { - dw_BitMask = dw_BitMask >> 16; - dw_ChannelMask = dw_ChannelMask >> 16; - - /********************************************/ - /* Read port 2 (second digital output port) */ - /********************************************/ - - dw_Status = inl(devpriv->iobase + 112); - - for (b_ChannelCpt = 0; b_ChannelCpt < 8; - b_ChannelCpt++) { - if ((dw_ChannelMask >> - b_ChannelCpt) & - 1) { - dw_Status = - (dw_Status & - (0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt)); - } - } - - outl(dw_Status, devpriv->iobase + 112); - } - } - - /*******************************************/ - /* Read port 0 (first digital output port) */ - /*******************************************/ - - data[1] = inl(devpriv->iobase + 80); - - /******************************************/ - /* Read port 1 (first digital input port) */ - /******************************************/ - - data[1] = data[1] | (inl(devpriv->iobase + 64) << 8); - - /************************/ - /* Test if port 2 input */ - /************************/ - - if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0) { - data[1] = - data[1] | (inl(devpriv->iobase + - 96) << 16); - } else { - data[1] = - data[1] | (inl(devpriv->iobase + - 112) << 16); - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("Channel mask error\n"); - i_ReturnValue = -4; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnReadTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from selected channel | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Channel = CR_CHAN(insn->chanspec) | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Selected TTL channel state | -+----------------------------------------------------------------------------+ -| Return Value : 0 : No error | -| -3 : Channel selection error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnReadTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - int i_ReturnValue = insn->n; - unsigned int *pls_ReadData = data; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /***********************/ - /* Test if read port 0 */ - /***********************/ - - if (b_Channel < 8) { - /*******************************************/ - /* Read port 0 (first digital output port) */ - /*******************************************/ - - pls_ReadData[0] = inl(devpriv->iobase + 80); - pls_ReadData[0] = (pls_ReadData[0] >> b_Channel) & 1; - } else { - /***********************/ - /* Test if read port 1 */ - /***********************/ - - if ((b_Channel > 7) && (b_Channel < 16)) { - /******************************************/ - /* Read port 1 (first digital input port) */ - /******************************************/ - - pls_ReadData[0] = inl(devpriv->iobase + 64); - pls_ReadData[0] = - (pls_ReadData[0] >> (b_Channel - - 8)) & 1; - } else { - /***********************/ - /* Test if read port 2 */ - /***********************/ - - if ((b_Channel > 15) && (b_Channel < 24)) { - /************************/ - /* Test if port 2 input */ - /************************/ - - if ((devpriv->ul_TTLPortConfiguration[0] - & 0xFF) == 0) { - pls_ReadData[0] = - inl(devpriv->iobase + - 96); - pls_ReadData[0] = - (pls_ReadData[0] >> - (b_Channel - 16)) & 1; - } else { - pls_ReadData[0] = - inl(devpriv->iobase + - 112); - pls_ReadData[0] = - (pls_ReadData[0] >> - (b_Channel - 16)) & 1; - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", - b_Channel); - } - } - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| TTL OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnWriteTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Set the state from TTL output channel | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Channel = CR_CHAN(insn->chanspec) | -| b_State = data [0] | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 : No error | -| -3 : Channel selection error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned char b_State = 0; - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - b_State = (unsigned char) data[0]; - - /***********************/ - /* Test if read port 0 */ - /***********************/ - - if (b_Channel < 8) { - /*****************************************************************************/ - /* Read port 0 (first digital output port) and set/reset the selected channel */ - /*****************************************************************************/ - - dw_Status = inl(devpriv->iobase + 80); - dw_Status = - (dw_Status & (0xFF - - (1 << b_Channel))) | ((b_State & 1) << - b_Channel); - outl(dw_Status, devpriv->iobase + 80); - } else { - /***********************/ - /* Test if read port 2 */ - /***********************/ - - if ((b_Channel > 15) && (b_Channel < 24)) { - /*************************/ - /* Test if port 2 output */ - /*************************/ - - if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF) - == 0xFF) { - /*****************************************************************************/ - /* Read port 2 (first digital output port) and set/reset the selected channel */ - /*****************************************************************************/ - - dw_Status = inl(devpriv->iobase + 112); - dw_Status = - (dw_Status & (0xFF - - (1 << (b_Channel - - 16)))) | - ((b_State & 1) << (b_Channel - - 16)); - outl(dw_Status, devpriv->iobase + 112); - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", - b_Channel); - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", - b_Channel); - } - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -static int apci3xxx_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - data[1] = inl(devpriv->iobase + 32) & 0xf; - - return insn->n; -} - -static int apci3xxx_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - s->state = inl(devpriv->iobase + 48) & 0xf; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - - outl(s->state, devpriv->iobase + 48); - } - - data[1] = s->state; - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_Reset(struct comedi_device *dev) | +----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI3XXX_Reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_Cpt = 0; - - /*************************/ - /* Disable the interrupt */ - /*************************/ - - disable_irq(dev->irq); - - /****************************/ - /* Reset the interrupt flag */ - /****************************/ - - devpriv->b_EocEosInterrupt = 0; - - /***************************/ - /* Clear the start command */ - /***************************/ - - writel(0, devpriv->dw_AiBase + 8); - - /*****************************/ - /* Reset the interrupt flags */ - /*****************************/ - - writel(readl(devpriv->dw_AiBase + 16), devpriv->dw_AiBase + 16); - - /*****************/ - /* clear the EOS */ - /*****************/ - - readl(devpriv->dw_AiBase + 20); - - /******************/ - /* Clear the FIFO */ - /******************/ - - for (b_Cpt = 0; b_Cpt < 16; b_Cpt++) { - readl(devpriv->dw_AiBase + 28); - } - - /************************/ - /* Enable the interrupt */ - /************************/ - - enable_irq(dev->irq); - - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 3d4878facc26..8a93542faedc 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -20,13 +20,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA - * - * You should also find the complete GPL in the COPYING file accompanying this - * source code. */ #include <linux/pci.h> diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index ed01c56630bb..b626738bb73c 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -20,13 +20,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * You should also find the complete GPL in the COPYING file accompanying - * this source code. */ #include <linux/pci.h> @@ -203,7 +196,6 @@ static void apci1516_detach(struct comedi_device *dev) { if (dev->iobase) apci1516_reset(dev); - comedi_spriv_free(dev, 2); comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index 4c6a9b5a06ae..1f7bed9a3f7f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -20,13 +20,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * You should also find the complete GPL in the COPYING file accompanying - * this source code. */ #include <linux/pci.h> diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index b666637f61be..89ead8eb3c70 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -20,13 +20,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * You should also find the complete GPL in the COPYING file accompanying - * this source code. */ #include <linux/pci.h> @@ -354,7 +347,6 @@ static void apci2032_detach(struct comedi_device *dev) free_irq(dev->irq, dev); if (dev->read_subdev) kfree(dev->read_subdev->private); - comedi_spriv_free(dev, 1); comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index 1cdc08d79792..ca1bd92ecb17 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -20,13 +20,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * You should also find the complete GPL in the COPYING file accompanying - * this source code. */ #include <linux/pci.h> @@ -130,7 +123,6 @@ static void apci2200_detach(struct comedi_device *dev) { if (dev->iobase) apci2200_reset(dev); - comedi_spriv_free(dev, 2); comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 317a26d97c2e..61452848510f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -103,8 +103,6 @@ static int apci3120_auto_attach(struct comedi_device *dev, if (devpriv->ul_DmaBufferVirtual[i]) { devpriv->ui_DmaBufferPages[i] = pages; devpriv->ui_DmaBufferSize[i] = PAGE_SIZE * pages; - devpriv->ui_DmaBufferSamples[i] = - devpriv->ui_DmaBufferSize[i] >> 1; devpriv->ul_DmaBufferHw[i] = virt_to_bus((void *)devpriv-> ul_DmaBufferVirtual[i]); @@ -138,9 +136,6 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = this_board->i_AiChannelList; s->range_table = &range_apci3120_ai; - /* Set the initialisation flag */ - devpriv->b_AiInitialisation = 1; - s->insn_config = i_APCI3120_InsnConfigAnalogInput; s->insn_read = i_APCI3120_InsnReadAnalogInput; s->do_cmdtest = i_APCI3120_CommandTestAnalogInput; diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index a0cf6ecdef0e..f9b63689a12a 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -20,13 +20,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * You should also find the complete GPL in the COPYING file accompanying - * this source code. */ #include <linux/pci.h> diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index ec4d6ca6863f..5b37cbf9228e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -1,14 +1,57 @@ +/* + * addi_apci_3xxx.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: S. Weber + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + #include <linux/pci.h> +#include <linux/interrupt.h> #include "../comedidev.h" + #include "comedi_fc.h" -#include "amcc_s5933.h" -#include "addi-data/addi_common.h" +#define CONV_UNIT_NS (1 << 0) +#define CONV_UNIT_US (1 << 1) +#define CONV_UNIT_MS (1 << 2) -#include "addi-data/addi_eeprom.c" -#include "addi-data/hwdrv_apci3xxx.c" -#include "addi-data/addi_common.c" +static const struct comedi_lrange apci3xxx_ai_range = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1) + } +}; + +static const struct comedi_lrange apci3xxx_ao_range = { + 2, { + BIP_RANGE(10), + UNI_RANGE(10) + } +}; enum apci3xxx_boardid { BOARD_APCI3000_16, @@ -38,651 +81,853 @@ enum apci3xxx_boardid { BOARD_APCI3500, }; -static const struct addi_board apci3xxx_boardtypes[] = { +struct apci3xxx_boardinfo { + const char *name; + int ai_subdev_flags; + int ai_n_chan; + unsigned int ai_maxdata; + unsigned char ai_conv_units; + unsigned int ai_min_acq_ns; + unsigned int has_ao:1; + unsigned int has_dig_in:1; + unsigned int has_dig_out:1; + unsigned int has_ttl_io:1; +}; + +static const struct apci3xxx_boardinfo apci3xxx_boardtypes[] = { [BOARD_APCI3000_16] = { - .pc_DriverName = "apci3000-16", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_AiMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3000-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, }, [BOARD_APCI3000_8] = { - .pc_DriverName = "apci3000-8", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_AiMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3000-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, }, [BOARD_APCI3000_4] = { - .pc_DriverName = "apci3000-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 4, - .i_NbrAiChannelDiff = 2, - .i_AiChannelList = 4, - .i_AiMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3000-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, }, [BOARD_APCI3006_16] = { - .pc_DriverName = "apci3006-16", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3006-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, }, [BOARD_APCI3006_8] = { - .pc_DriverName = "apci3006-8", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3006-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, }, [BOARD_APCI3006_4] = { - .pc_DriverName = "apci3006-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 4, - .i_NbrAiChannelDiff = 2, - .i_AiChannelList = 4, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3006-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, }, [BOARD_APCI3010_16] = { - .pc_DriverName = "apci3010-16", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_AiMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3010-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3010_8] = { - .pc_DriverName = "apci3010-8", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_AiMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3010-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3010_4] = { - .pc_DriverName = "apci3010-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 4, - .i_NbrAiChannelDiff = 2, - .i_AiChannelList = 4, - .i_AiMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3010-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3016_16] = { - .pc_DriverName = "apci3016-16", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3016-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3016_8] = { - .pc_DriverName = "apci3016-8", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3016-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3016_4] = { - .pc_DriverName = "apci3016-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 4, - .i_NbrAiChannelDiff = 2, - .i_AiChannelList = 4, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3016-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3100_16_4] = { - .pc_DriverName = "apci3100-16-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 4095, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3100-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, }, [BOARD_APCI3100_8_4] = { - .pc_DriverName = "apci3100-8-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 4095, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3100-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, }, [BOARD_APCI3106_16_4] = { - .pc_DriverName = "apci3106-16-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 65535, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3106-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, }, [BOARD_APCI3106_8_4] = { - .pc_DriverName = "apci3106-8-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 65535, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 10000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3106-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, }, [BOARD_APCI3110_16_4] = { - .pc_DriverName = "apci3110-16-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 4095, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3110-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3110_8_4] = { - .pc_DriverName = "apci3110-8-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 4095, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3110-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3116_16_4] = { - .pc_DriverName = "apci3116-16-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 65535, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3116-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3116_8_4] = { - .pc_DriverName = "apci3116-8-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannel = 8, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 8, - .i_NbrAoChannel = 4, - .i_AiMaxdata = 65535, - .i_AoMaxdata = 4095, - .pr_AiRangelist = &range_apci3XXX_ai, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .i_NbrTTLChannel = 24, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3116-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, }, [BOARD_APCI3003] = { - .pc_DriverName = "apci3003", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 4, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .b_AvailableConvertUnit = 7, - .ui_MinAcquisitiontimeNs = 2500, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, + .name = "apci3003", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US | + CONV_UNIT_NS, + .ai_min_acq_ns = 2500, + .has_dig_in = 1, + .has_dig_out = 1, }, [BOARD_APCI3002_16] = { - .pc_DriverName = "apci3002-16", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannelDiff = 16, - .i_AiChannelList = 16, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, + .name = "apci3002-16", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, }, [BOARD_APCI3002_8] = { - .pc_DriverName = "apci3002-8", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 8, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, + .name = "apci3002-8", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, }, [BOARD_APCI3002_4] = { - .pc_DriverName = "apci3002-4", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAiChannelDiff = 4, - .i_AiChannelList = 4, - .i_AiMaxdata = 65535, - .pr_AiRangelist = &range_apci3XXX_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 1, - .b_AvailableConvertUnit = 6, - .ui_MinAcquisitiontimeNs = 5000, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ai_config = i_APCI3XXX_InsnConfigAnalogInput, - .ai_read = i_APCI3XXX_InsnReadAnalogInput, - .di_bits = apci3xxx_di_insn_bits, - .do_bits = apci3xxx_do_insn_bits, + .name = "apci3002-4", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, }, [BOARD_APCI3500] = { - .pc_DriverName = "apci3500", - .i_IorangeBase1 = 256, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .pc_EepromChip = ADDIDATA_9054, - .i_NbrAoChannel = 4, - .i_AoMaxdata = 4095, - .pr_AoRangelist = &range_apci3XXX_ao, - .i_NbrTTLChannel = 24, - .interrupt = v_APCI3XXX_Interrupt, - .reset = i_APCI3XXX_Reset, - .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, - .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, - .ttl_read = i_APCI3XXX_InsnReadTTLIO, - .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + .name = "apci3500", + .has_ao = 1, + .has_ttl_io = 1, }, }; +struct apci3xxx_private { + void __iomem *mmio; + unsigned int ai_timer; + unsigned char ai_time_base; +}; + +static irqreturn_t apci3xxx_irq_handler(int irq, void *d) +{ + struct comedi_device *dev = d; + struct apci3xxx_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int status; + unsigned int val; + + /* Test if interrupt occur */ + status = readl(devpriv->mmio + 16); + if ((status & 0x2) == 0x2) { + /* Reset the interrupt */ + writel(status, devpriv->mmio + 16); + + val = readl(devpriv->mmio + 28); + comedi_buf_put(s->async, val); + + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int apci3xxx_ai_started(struct comedi_device *dev) +{ + struct apci3xxx_private *devpriv = dev->private; + + if ((readl(devpriv->mmio + 8) & 0x80000) == 0x80000) + return 1; + else + return 0; + +} + +static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int delay_mode; + unsigned int val; + + if (apci3xxx_ai_started(dev)) + return -EBUSY; + + /* Clear the FIFO */ + writel(0x10000, devpriv->mmio + 12); + + /* Get and save the delay mode */ + delay_mode = readl(devpriv->mmio + 4); + delay_mode &= 0xfffffef0; + + /* Channel configuration selection */ + writel(delay_mode, devpriv->mmio + 4); + + /* Make the configuration */ + val = (range & 3) | ((range >> 2) << 6) | + ((aref == AREF_DIFF) << 7); + writel(val, devpriv->mmio + 0); + + /* Channel selection */ + writel(delay_mode | 0x100, devpriv->mmio + 4); + writel(chan, devpriv->mmio + 0); + + /* Restore delay mode */ + writel(delay_mode, devpriv->mmio + 4); + + /* Set the number of sequence to 1 */ + writel(1, devpriv->mmio + 48); + + return 0; +} + +static int apci3xxx_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int val; + int ret; + int i; + + ret = apci3xxx_ai_setup(dev, insn->chanspec); + if (ret) + return ret; + + for (i = 0; i < insn->n; i++) { + /* Start the conversion */ + writel(0x80000, devpriv->mmio + 8); + + /* Wait the EOS */ + do { + val = readl(devpriv->mmio + 20); + val &= 0x1; + } while (!val); + + /* Read the analog value */ + data[i] = readl(devpriv->mmio + 28); + } + + return insn->n; +} + +static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev, + unsigned int *ns, int round_mode) +{ + const struct apci3xxx_boardinfo *board = comedi_board(dev); + struct apci3xxx_private *devpriv = dev->private; + unsigned int base; + unsigned int timer; + int time_base; + + /* time_base: 0 = ns, 1 = us, 2 = ms */ + for (time_base = 0; time_base < 3; time_base++) { + /* skip unsupported time bases */ + if (!(board->ai_conv_units & (1 << time_base))) + continue; + + switch (time_base) { + case 0: + base = 1; + break; + case 1: + base = 1000; + break; + case 2: + base = 1000000; + break; + } + + switch (round_mode) { + case TRIG_ROUND_NEAREST: + default: + timer = (*ns + base / 2) / base; + break; + case TRIG_ROUND_DOWN: + timer = *ns / base; + break; + case TRIG_ROUND_UP: + timer = (*ns + base - 1) / base; + break; + } + + if (timer < 0x10000) { + devpriv->ai_time_base = time_base; + devpriv->ai_timer = timer; + *ns = timer * time_base; + return 0; + } + } + return -EINVAL; +} + +static int apci3xxx_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + const struct apci3xxx_boardinfo *board = comedi_board(dev); + int err = 0; + unsigned int tmp; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ai_min_acq_ns); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* + * FIXME: The hardware supports multiple scan modes but the original + * addi-data driver only supported reading a single channel with + * interrupts. Need a proper datasheet to fix this. + * + * The following scan modes are supported by the hardware: + * 1) Single software scan + * 2) Single hardware triggered scan + * 3) Continuous software scan + * 4) Continuous software scan with timer delay + * 5) Continuous hardware triggered scan + * 6) Continuous hardware triggered scan with timer delay + * + * For now, limit the chanlist to a single channel. + */ + if (cmd->chanlist_len > 1) { + cmd->chanlist_len = 1; + err |= -EINVAL; + } + + tmp = cmd->convert_arg; + err |= apci3xxx_ai_ns_to_timer(dev, &cmd->convert_arg, + cmd->flags & TRIG_ROUND_MASK); + if (tmp != cmd->convert_arg) + err |= -EINVAL; + + if (err) + return 4; + + return 0; +} + +static int apci3xxx_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci3xxx_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; + + ret = apci3xxx_ai_setup(dev, cmd->chanlist[0]); + if (ret) + return ret; + + /* Set the convert timing unit */ + writel(devpriv->ai_time_base, devpriv->mmio + 36); + + /* Set the convert timing */ + writel(devpriv->ai_timer, devpriv->mmio + 32); + + /* Start the conversion */ + writel(0x180000, devpriv->mmio + 8); + + return 0; +} + +static int apci3xxx_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + return 0; +} + +static int apci3xxx_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int status; + int i; + + for (i = 0; i < insn->n; i++) { + /* Set the range selection */ + writel(range, devpriv->mmio + 96); + + /* Write the analog value to the selected channel */ + writel((data[i] << 8) | chan, devpriv->mmio + 100); + + /* Wait the end of transfer */ + do { + status = readl(devpriv->mmio + 96); + } while ((status & 0x100) != 0x100); + } + + return insn->n; +} + +static int apci3xxx_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inl(dev->iobase + 32) & 0xf; + + return insn->n; +} + +static int apci3xxx_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask = data[0]; + unsigned int bits = data[1]; + + s->state = inl(dev->iobase + 48) & 0xf; + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + outl(s->state, dev->iobase + 48); + } + + data[1] = s->state; + + return insn->n; +} + +static int apci3xxx_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask = 1 << chan; + unsigned int bits; + + /* + * Port 0 (channels 0-7) are always inputs + * Port 1 (channels 8-15) are always outputs + * Port 2 (channels 16-23) are programmable i/o + * + * Changing any channel in port 2 changes the entire port. + */ + if (mask & 0xff0000) + bits = 0xff0000; + else + bits = 0; + + switch (data[0]) { + case INSN_CONFIG_DIO_INPUT: + s->io_bits &= ~bits; + break; + case INSN_CONFIG_DIO_OUTPUT: + s->io_bits |= bits; + break; + case INSN_CONFIG_DIO_QUERY: + data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; + return insn->n; + default: + return -EINVAL; + } + + /* update port 2 configuration */ + if (bits) + outl((s->io_bits >> 24) & 0xff, dev->iobase + 224); + + return insn->n; +} + +static int apci3xxx_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask = data[0]; + unsigned int bits = data[1]; + unsigned int val; + + /* only update output channels */ + mask &= s->io_bits; + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + if (mask & 0xff) + outl(s->state & 0xff, dev->iobase + 80); + if (mask & 0xff0000) + outl((s->state >> 16) & 0xff, dev->iobase + 112); + } + + val = inl(dev->iobase + 80); + val |= (inl(dev->iobase + 64) << 8); + if (s->io_bits & 0xff0000) + val |= (inl(dev->iobase + 112) << 16); + else + val |= (inl(dev->iobase + 96) << 16); + + data[1] = val; + + return insn->n; +} + +static int apci3xxx_reset(struct comedi_device *dev) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int val; + int i; + + /* Disable the interrupt */ + disable_irq(dev->irq); + + /* Clear the start command */ + writel(0, devpriv->mmio + 8); + + /* Reset the interrupt flags */ + val = readl(devpriv->mmio + 16); + writel(val, devpriv->mmio + 16); + + /* clear the EOS */ + readl(devpriv->mmio + 20); + + /* Clear the FIFO */ + for (i = 0; i < 16; i++) + val = readl(devpriv->mmio + 28); + + /* Enable the interrupt */ + enable_irq(dev->irq); + + return 0; +} + static int apci3xxx_auto_attach(struct comedi_device *dev, unsigned long context) { - const struct addi_board *board = NULL; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct apci3xxx_boardinfo *board = NULL; + struct apci3xxx_private *devpriv; + struct comedi_subdevice *s; + int n_subdevices; + int subdev; + int ret; if (context < ARRAY_SIZE(apci3xxx_boardtypes)) board = &apci3xxx_boardtypes[context]; if (!board) return -ENODEV; dev->board_ptr = board; + dev->board_name = board->name; + + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 2); + devpriv->mmio = pci_ioremap_bar(pcidev, 3); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, apci3xxx_irq_handler, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + n_subdevices = (board->ai_n_chan ? 0 : 1) + board->has_ao + + board->has_dig_in + board->has_dig_out + + board->has_ttl_io; + ret = comedi_alloc_subdevices(dev, n_subdevices); + if (ret) + return ret; + + subdev = 0; + + /* Analog Input subdevice */ + if (board->ai_n_chan) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | board->ai_subdev_flags; + s->n_chan = board->ai_n_chan; + s->maxdata = board->ai_maxdata; + s->len_chanlist = s->n_chan; + s->range_table = &apci3xxx_ai_range; + s->insn_read = apci3xxx_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->do_cmdtest = apci3xxx_ai_cmdtest; + s->do_cmd = apci3xxx_ai_cmd; + s->cancel = apci3xxx_ai_cancel; + } + + subdev++; + } + + /* Analog Output subdevice */ + if (board->has_ao) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->range_table = &apci3xxx_ao_range; + s->insn_write = apci3xxx_ao_insn_write; + + subdev++; + } + + /* Digital Input subdevice */ + if (board->has_dig_in) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3xxx_di_insn_bits; + + subdev++; + } + + /* Digital Output subdevice */ + if (board->has_dig_out) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3xxx_do_insn_bits; + + subdev++; + } + + /* TTL Digital I/O subdevice */ + if (board->has_ttl_io) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->n_chan = 24; + s->maxdata = 1; + s->io_bits = 0xff; /* channels 0-7 are always outputs */ + s->range_table = &range_digital; + s->insn_config = apci3xxx_dio_insn_config; + s->insn_bits = apci3xxx_dio_insn_bits; + + subdev++; + } + + apci3xxx_reset(dev); + return 0; +} + +static void apci3xxx_detach(struct comedi_device *dev) +{ + struct apci3xxx_private *devpriv = dev->private; - return addi_auto_attach(dev, context); + if (devpriv) { + if (dev->iobase) + apci3xxx_reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); + if (devpriv->mmio) + iounmap(devpriv->mmio); + } + comedi_pci_disable(dev); } static struct comedi_driver apci3xxx_driver = { .driver_name = "addi_apci_3xxx", .module = THIS_MODULE, .auto_attach = apci3xxx_auto_attach, - .detach = i_ADDI_Detach, + .detach = apci3xxx_detach, }; static int apci3xxx_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c index 1666b5f510d3..7b21acc93929 100644 --- a/drivers/staging/comedi/drivers/addi_watchdog.c +++ b/drivers/staging/comedi/drivers/addi_watchdog.c @@ -16,10 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "../comedidev.h" @@ -130,14 +126,12 @@ int addi_watchdog_init(struct comedi_subdevice *s, unsigned long iobase) { struct addi_watchdog_private *spriv; - spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); if (!spriv) return -ENOMEM; spriv->iobase = iobase; - s->private = spriv; - s->type = COMEDI_SUBD_TIMER; s->subdev_flags = SDF_WRITEABLE; s->n_chan = 1; diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 8a438ff1bd45..b5e4e53f737f 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -20,10 +20,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: adl_pci6208 diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index e3960745f506..0d9243a5f495 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -19,10 +19,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index b3ec60afe3a0..0b591b0b5501 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index 6247fdcedcbf..af51c7460048 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -17,10 +17,6 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 71142e36e7fb..d187a7bf0a55 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: adq12b diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index ccc114d6c08b..8430a27ec1b5 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -1,4 +1,4 @@ -/******************************************************************************* +/* comedi/drivers/pci1723.c COMEDI - Linux Control and Measurement Device Interface @@ -13,12 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*******************************************************************************/ +*/ /* Driver: adv_pci1723 Description: Advantech PCI-1723 diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c index e60f12578d44..da7462e01faa 100644 --- a/drivers/staging/comedi/drivers/adv_pci1724.c +++ b/drivers/staging/comedi/drivers/adv_pci1724.c @@ -17,12 +17,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ /* diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index f70c67471c13..8e6ec75bd294 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -1173,19 +1173,11 @@ static int pci_dio_auto_attach(struct comedi_device *dev, static void pci_dio_detach(struct comedi_device *dev) { struct pci_dio_private *devpriv = dev->private; - struct comedi_subdevice *s; - int i; if (devpriv) { if (devpriv->valid) pci_dio_reset(dev); } - for (i = 0; i < dev->n_subdevices; i++) { - s = &dev->subdevices[i]; - if (s->type == COMEDI_SUBD_DIO) - comedi_spriv_free(dev, i); - s->private = NULL; /* some private data is static */ - } comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index e2dc08a058bc..279dfe8951f7 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -259,17 +255,11 @@ static int aio_aio12_8_attach(struct comedi_device *dev, return 0; } -static void aio_aio12_8_detach(struct comedi_device *dev) -{ - comedi_spriv_free(dev, 2); - comedi_legacy_detach(dev); -} - static struct comedi_driver aio_aio12_8_driver = { .driver_name = "aio_aio12_8", .module = THIS_MODULE, .attach = aio_aio12_8_attach, - .detach = aio_aio12_8_detach, + .detach = comedi_legacy_detach, .board_name = &board_types[0].name, .num_names = ARRAY_SIZE(board_types), .offset = sizeof(struct aio12_8_boardtype), diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 126854c05093..029834d0ff1f 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 297750bef0f7..e2478105ac1a 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* * Driver: amplc_dio200 diff --git a/drivers/staging/comedi/drivers/amplc_dio200.h b/drivers/staging/comedi/drivers/amplc_dio200.h index cf2e7261740e..43160b9944bb 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.h +++ b/drivers/staging/comedi/drivers/amplc_dio200.h @@ -18,11 +18,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef AMPLC_DIO200_H_INCLUDED diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index 3403e5ccfa93..649fc69724fb 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #include <linux/interrupt.h> @@ -561,7 +556,7 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s, const struct dio200_layout *layout = dio200_dev_layout(dev); struct dio200_subdev_intr *subpriv; - subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); + subpriv = comedi_alloc_spriv(s, sizeof(*subpriv)); if (!subpriv) return -ENOMEM; @@ -573,7 +568,6 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s, /* Disable interrupt sources. */ dio200_write8(dev, subpriv->ofs, 0); - s->private = subpriv; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_CMD_READ; if (layout->has_int_sce) { @@ -888,11 +882,10 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, struct dio200_subdev_8254 *subpriv; unsigned int chan; - subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); + subpriv = comedi_alloc_spriv(s, sizeof(*subpriv)); if (!subpriv) return -ENOMEM; - s->private = subpriv; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 3; @@ -1024,11 +1017,12 @@ static int dio200_subdev_8255_init(struct comedi_device *dev, { struct dio200_subdev_8255 *subpriv; - subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); + subpriv = comedi_alloc_spriv(s, sizeof(*subpriv)); if (!subpriv) return -ENOMEM; + subpriv->ofs = offset; - s->private = subpriv; + s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 24; @@ -1230,28 +1224,11 @@ void amplc_dio200_common_detach(struct comedi_device *dev) { const struct dio200_board *thisboard = comedi_board(dev); struct dio200_private *devpriv = dev->private; - const struct dio200_layout *layout; - unsigned n; if (!thisboard || !devpriv) return; if (dev->irq) free_irq(dev->irq, dev); - if (dev->subdevices) { - layout = dio200_board_layout(thisboard); - for (n = 0; n < dev->n_subdevices; n++) { - switch (layout->sdtype[n]) { - case sd_8254: - case sd_8255: - case sd_intr: - comedi_spriv_free(dev, n); - break; - case sd_timer: - default: - break; - } - } - } } EXPORT_SYMBOL_GPL(amplc_dio200_common_detach); diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c index 4be44e877373..d7d9f5cc3ab4 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_pci.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* * Driver: amplc_dio200_pci diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 115ecd51677e..4e889b82cbf2 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: amplc_pc236 @@ -543,7 +538,6 @@ static void pc236_detach(struct comedi_device *dev) return; if (dev->iobase) pc236_intr_disable(dev); - comedi_spriv_free(dev, 0); if (is_isa_board(thisboard)) { comedi_legacy_detach(dev); } else if (is_pci_board(thisboard)) { diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 94a752d852bb..6546095e7a45 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: amplc_pc263 diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 4d7eab9b5565..f1e36f08b103 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: amplc_pci224 diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 49200fbd60b9..846d6448fa4d 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -16,10 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: amplc_pci230 @@ -2834,7 +2830,6 @@ static void pci230_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - comedi_spriv_free(dev, 2); if (dev->irq) free_irq(dev->irq, dev); comedi_pci_disable(dev); diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index 8b57533bf406..4da900cc5845 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: amplc_pci263 diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index 92376dc86dd8..929218a35975 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: c6xdigio diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index f874fff44523..ae9a2082b5a4 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -15,10 +15,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - PCMCIA support code for this driver is adapted from the dummy_cs.c driver of the Linux PCMCIA Card Services package. diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 53dd298d2b54..58bca184bf22 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -19,12 +19,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: cb_pcidas @@ -1608,7 +1602,6 @@ static void cb_pcidas_detach(struct comedi_device *dev) } if (dev->irq) free_irq(dev->irq, dev); - comedi_spriv_free(dev, 2); comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index c3e5495b4f06..43c0bf58771a 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -28,12 +28,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ /* * Driver: cb_pcidas64 @@ -4163,7 +4158,6 @@ static void detach(struct comedi_device *dev) devpriv->ao_dma_desc_bus_addr); } } - comedi_spriv_free(dev, 4); comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index f9b459888b8b..2d3e920e5987 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -397,18 +393,11 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, return 0; } -static void cb_pcidda_detach(struct comedi_device *dev) -{ - comedi_spriv_free(dev, 1); - comedi_spriv_free(dev, 2); - comedi_pci_disable(dev); -} - static struct comedi_driver cb_pcidda_driver = { .driver_name = "cb_pcidda", .module = THIS_MODULE, .auto_attach = cb_pcidda_auto_attach, - .detach = cb_pcidda_detach, + .detach = comedi_pci_disable, }; static int cb_pcidda_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index 29813c9d4a2a..8b5c198862a1 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: cb_pcimdas diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 88f03ae6f3e6..406cba8cba88 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -15,11 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: cb_pcimdda @@ -197,17 +192,11 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, return 1; } -static void cb_pcimdda_detach(struct comedi_device *dev) -{ - comedi_spriv_free(dev, 1); - comedi_pci_disable(dev); -} - static struct comedi_driver cb_pcimdda_driver = { .driver_name = "cb_pcimdda", .module = THIS_MODULE, .auto_attach = cb_pcimdda_auto_attach, - .detach = cb_pcimdda_detach, + .detach = comedi_pci_disable, }; static int cb_pcimdda_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 1bb53816eca3..1a51866be6f7 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -15,11 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: comedi_bond diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c index 37dc79637d2a..b3d89c82d087 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ b/drivers/staging/comedi/drivers/comedi_fc.c @@ -17,12 +17,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ #include "../comedidev.h" diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index 31afab79f39a..a4dea7cb86be 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -17,12 +17,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ #ifndef _COMEDI_FC_H #define _COMEDI_FC_H diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index 3e061cc9b48e..772a8f5f0c1c 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: comedi_parport diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index c1d8e86f53a2..907e7a3822f5 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -21,12 +21,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ /* Driver: comedi_test Description: generates fake waveforms diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index f2230bfd4eb9..0fb9027dde2d 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -13,11 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: contec_pci_dio diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index b87f95c3e17d..44c912b48b6e 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: daqboard2000 @@ -110,7 +105,6 @@ Configuration options: not applicable, uses PCI auto config #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/firmware.h> #include "../comedidev.h" @@ -524,7 +518,8 @@ static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) } static int initialize_daqboard2000(struct comedi_device *dev, - const u8 *cpld_array, size_t len) + const u8 *cpld_array, size_t len, + unsigned long context) { struct daqboard2000_private *devpriv = dev->private; int result = -EIO; @@ -565,22 +560,6 @@ static int initialize_daqboard2000(struct comedi_device *dev, return result; } -static int daqboard2000_upload_firmware(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, DAQBOARD2000_FIRMWARE, &pcidev->dev); - if (ret) - return ret; - - ret = initialize_daqboard2000(dev, fw->data, fw->size); - release_firmware(fw); - - return ret; -} - static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev) { } @@ -724,7 +703,9 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, readl(devpriv->plx + 0x6c); - result = daqboard2000_upload_firmware(dev); + result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + DAQBOARD2000_FIRMWARE, + initialize_daqboard2000, 0); if (result < 0) return result; @@ -766,7 +747,6 @@ static void daqboard2000_detach(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; - comedi_spriv_free(dev, 2); if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index ba12c1d605fb..2e7e3e202390 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -16,12 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ***************************************************************** */ /* @@ -566,12 +560,6 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) } EXPORT_SYMBOL_GPL(das08_common_attach); -void das08_common_detach(struct comedi_device *dev) -{ - comedi_spriv_free(dev, 4); -} -EXPORT_SYMBOL_GPL(das08_common_detach); - static int __init das08_init(void) { return 0; diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index 89bb8d6fdfc6..cce1b584200a 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _DAS08_H @@ -52,6 +47,5 @@ struct das08_private_struct { }; int das08_common_attach(struct comedi_device *dev, unsigned long iobase); -void das08_common_detach(struct comedi_device *dev); #endif /* _DAS08_H */ diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index d9f3e92317d3..885fb179c9b4 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -16,19 +16,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - PCMCIA support code for this driver is adapted from the dummy_cs.c driver of the Linux PCMCIA Card Services package. The initial developer of the original code is David A. Hinds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - -***************************************************************** - */ /* Driver: das08_cs @@ -93,17 +86,11 @@ static int das08_cs_auto_attach(struct comedi_device *dev, return das08_common_attach(dev, iobase); } -static void das08_cs_detach(struct comedi_device *dev) -{ - das08_common_detach(dev); - comedi_pcmcia_disable(dev); -} - static struct comedi_driver driver_das08_cs = { .driver_name = "das08_cs", .module = THIS_MODULE, .auto_attach = das08_cs_auto_attach, - .detach = das08_cs_detach, + .detach = comedi_pcmcia_disable, }; static int das08_pcmcia_attach(struct pcmcia_device *link) diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c index f09f6966ed65..21a94389b8b2 100644 --- a/drivers/staging/comedi/drivers/das08_isa.c +++ b/drivers/staging/comedi/drivers/das08_isa.c @@ -16,10 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -193,17 +189,11 @@ static int das08_isa_attach(struct comedi_device *dev, return das08_common_attach(dev, dev->iobase); } -static void das08_isa_detach(struct comedi_device *dev) -{ - das08_common_detach(dev); - comedi_legacy_detach(dev); -} - static struct comedi_driver das08_isa_driver = { .driver_name = "isa-das08", .module = THIS_MODULE, .attach = das08_isa_attach, - .detach = das08_isa_detach, + .detach = comedi_legacy_detach, .board_name = &das08_isa_boards[0].name, .num_names = ARRAY_SIZE(das08_isa_boards), .offset = sizeof(das08_isa_boards[0]), diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c index 53fa943dd0b7..9c5d234e063f 100644 --- a/drivers/staging/comedi/drivers/das08_pci.c +++ b/drivers/staging/comedi/drivers/das08_pci.c @@ -16,10 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -79,17 +75,11 @@ static int das08_pci_auto_attach(struct comedi_device *dev, return das08_common_attach(dev, dev->iobase); } -static void das08_pci_detach(struct comedi_device *dev) -{ - das08_common_detach(dev); - comedi_pci_disable(dev); -} - static struct comedi_driver das08_pci_comedi_driver = { .driver_name = "pci-das08", .module = THIS_MODULE, .auto_attach = das08_pci_auto_attach, - .detach = das08_pci_detach, + .detach = comedi_pci_disable, }; static int das08_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 762b5a6eac5a..dbec3ba99548 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -16,12 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: das16 @@ -1339,7 +1333,6 @@ static void das16_detach(struct comedi_device *dev) struct das16_private_struct *devpriv = dev->private; das16_reset(dev); - comedi_spriv_free(dev, 4); if (devpriv) { int i; for (i = 0; i < 2; i++) { diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 9cb9c3b04797..0b33808c3a7d 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -17,12 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: das16m1 @@ -672,7 +666,6 @@ static void das16m1_detach(struct comedi_device *dev) { struct das16m1_private_struct *devpriv = dev->private; - comedi_spriv_free(dev, 3); if (devpriv && devpriv->extra_iobase) release_region(devpriv->extra_iobase, DAS16M1_SIZE2); comedi_legacy_detach(dev); diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index abf7638a9f71..23b4a661eb1a 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -15,12 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: das1800 diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 11424fb5b4d4..f0530778bb3b 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -22,11 +22,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: das6402 diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 9ce6cbcc7ee8..091cd911b38a 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -15,12 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: das800 diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 6c85dd2d549b..e29847d73b43 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dmm32at diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 8757b54ad4ac..5348cdae408a 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -18,10 +18,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: dt2811 diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index 7c95b3b68131..87e9749c4be7 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt2814 diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index b24e87681fe3..0fcd4fe7acdc 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt2815 diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c index b5c8e8213faf..2f46be715f79 100644 --- a/drivers/staging/comedi/drivers/dt2817.c +++ b/drivers/staging/comedi/drivers/dt2817.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt2817 diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 90f2de9bc402..c1950e3b19a2 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt282x diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 7e03929c9a14..01a2f889d5b0 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt3000 diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 81eb5ed6ec97..6c60949d9193 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -15,11 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ /* @@ -43,14 +38,11 @@ for my needs. * says P1). */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/kref.h> #include <linux/uaccess.h> #include <linux/usb.h> @@ -60,6 +52,9 @@ for my needs. #define DT9812_MAX_WRITE_CMD_PIPE_SIZE 32 #define DT9812_MAX_READ_CMD_PIPE_SIZE 32 +/* usb_bulk_msg() timout in milliseconds */ +#define DT9812_USB_TIMEOUT 1000 + /* * See Silican Laboratories C8051F020/1/2/3 manual */ @@ -242,87 +237,25 @@ struct dt9812_usb_cmd { struct dt9812_write_multi write_multi_info; struct dt9812_rmw_multi rmw_multi_info; } u; -#if 0 - WRITE_BYTE_INFO WriteByteInfo; - READ_BYTE_INFO ReadByteInfo; - WRITE_MULTI_INFO WriteMultiInfo; - READ_MULTI_INFO ReadMultiInfo; - RMW_BYTE_INFO RMWByteInfo; - RMW_MULTI_INFO RMWMultiInfo; - DAC_THRESHOLD_INFO DacThresholdInfo; - INT_ON_CHANGE_MASK_INFO IntOnChangeMaskInfo; - CGL_INFO CglInfo; - SUBSYSTEM_INFO SubsystemInfo; - CAL_POT_CMD CalPotCmd; - WRITE_DEV_BYTE_INFO WriteDevByteInfo; - READ_DEV_BYTE_INFO ReadDevByteInfo; - WRITE_DEV_MULTI_INFO WriteDevMultiInfo; - READ_DEV_MULTI_INFO ReadDevMultiInfo; - READ_SINGLE_VALUE_INFO ReadSingleValueInfo; - WRITE_SINGLE_VALUE_INFO WriteSingleValueInfo; -#endif }; -#define DT9812_NUM_SLOTS 16 - -static DEFINE_SEMAPHORE(dt9812_mutex); - -static const struct usb_device_id dt9812_table[] = { - {USB_DEVICE(0x0867, 0x9812)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, dt9812_table); - -struct usb_dt9812 { - struct slot_dt9812 *slot; - struct usb_device *udev; - struct usb_interface *interface; - u16 vendor; - u16 product; - u16 device; - u32 serial; +struct dt9812_private { + struct semaphore sem; struct { __u8 addr; size_t size; - } message_pipe, command_write, command_read, write_stream, read_stream; - struct kref kref; - u16 analog_out_shadow[2]; - u8 digital_out_shadow; -}; - -struct comedi_dt9812 { - struct slot_dt9812 *slot; - u32 serial; -}; - -struct slot_dt9812 { - struct semaphore mutex; - u32 serial; - struct usb_dt9812 *usb; - struct comedi_dt9812 *comedi; + } cmd_wr, cmd_rd; + u16 device; + u16 ao_shadow[2]; }; -static struct slot_dt9812 dt9812[DT9812_NUM_SLOTS]; - -static inline struct usb_dt9812 *to_dt9812_dev(struct kref *d) -{ - return container_of(d, struct usb_dt9812, kref); -} - -static void dt9812_delete(struct kref *kref) -{ - struct usb_dt9812 *dev = to_dt9812_dev(kref); - - usb_put_dev(dev->udev); - kfree(dev); -} - -static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, - size_t buf_size) +static int dt9812_read_info(struct comedi_device *dev, + int offset, void *buf, size_t buf_size) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int count, retval; + int count, ret; cmd.cmd = cpu_to_le32(DT9812_R_FLASH_DATA); cmd.u.flash_data_info.address = @@ -330,25 +263,23 @@ static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, cmd.u.flash_data_info.numbytes = cpu_to_le16(buf_size); /* DT9812 only responds to 32 byte writes!! */ - count = 32; - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - if (retval) - return retval; - retval = usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->command_read.addr), - buf, buf_size, &count, HZ * 1); - return retval; + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); + if (ret) + return ret; + + return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr), + buf, buf_size, &count, DT9812_USB_TIMEOUT); } -static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, - u8 *address, u8 *value) +static int dt9812_read_multiple_registers(struct comedi_device *dev, + int reg_count, u8 *address, + u8 *value) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int i, count, retval; + int i, count, ret; cmd.cmd = cpu_to_le32(DT9812_R_MULTI_BYTE_REG); cmd.u.read_multi_info.count = reg_count; @@ -356,26 +287,23 @@ static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, cmd.u.read_multi_info.address[i] = address[i]; /* DT9812 only responds to 32 byte writes!! */ - count = 32; - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - if (retval) - return retval; - retval = usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->command_read.addr), - value, reg_count, &count, HZ * 1); - return retval; + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); + if (ret) + return ret; + + return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr), + value, reg_count, &count, DT9812_USB_TIMEOUT); } -static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, +static int dt9812_write_multiple_registers(struct comedi_device *dev, int reg_count, u8 *address, u8 *value) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int i, count, retval; + int i, count; cmd.cmd = cpu_to_le32(DT9812_W_MULTI_BYTE_REG); cmd.u.read_multi_info.count = reg_count; @@ -383,19 +311,20 @@ static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, cmd.u.write_multi_info.write[i].address = address[i]; cmd.u.write_multi_info.write[i].value = value[i]; } + /* DT9812 only responds to 32 byte writes!! */ - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - return retval; + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); } -static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count, +static int dt9812_rmw_multiple_registers(struct comedi_device *dev, + int reg_count, struct dt9812_rmw_byte *rmw) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int i, count, retval; + int i, count; cmd.cmd = cpu_to_le32(DT9812_RMW_MULTI_BYTE_REG); cmd.u.rmw_multi_info.count = reg_count; @@ -403,76 +332,52 @@ static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count, cmd.u.rmw_multi_info.rmw[i] = rmw[i]; /* DT9812 only responds to 32 byte writes!! */ - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - return retval; + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); } -static int dt9812_digital_in(struct slot_dt9812 *slot, u8 *bits) +static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) { - int result = -ENODEV; - - down(&slot->mutex); - if (slot->usb) { - u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 }; - u8 value[2]; + struct dt9812_private *devpriv = dev->private; + u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 }; + u8 value[2]; + int ret; - result = dt9812_read_multiple_registers(slot->usb, 2, reg, - value); - if (result == 0) { - /* - * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital - * input port bit 3 in F020_SFR_P1 is bit 7 in the - * digital input port - */ - *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); - /* printk("%2.2x, %2.2x -> %2.2x\n", - value[0], value[1], *bits); */ - } + down(&devpriv->sem); + ret = dt9812_read_multiple_registers(dev, 2, reg, value); + if (ret == 0) { + /* + * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital + * input port bit 3 in F020_SFR_P1 is bit 7 in the + * digital input port + */ + *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); } - up(&slot->mutex); + up(&devpriv->sem); - return result; + return ret; } -static int dt9812_digital_out(struct slot_dt9812 *slot, u8 bits) +static int dt9812_digital_out(struct comedi_device *dev, u8 bits) { - int result = -ENODEV; - - down(&slot->mutex); - if (slot->usb) { - u8 reg[1]; - u8 value[1]; - - reg[0] = F020_SFR_P2; - value[0] = bits; - result = dt9812_write_multiple_registers(slot->usb, 1, reg, - value); - slot->usb->digital_out_shadow = bits; - } - up(&slot->mutex); - return result; -} + struct dt9812_private *devpriv = dev->private; + u8 reg[1] = { F020_SFR_P2 }; + u8 value[1] = { bits }; + int ret; -static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 *bits) -{ - int result = -ENODEV; + down(&devpriv->sem); + ret = dt9812_write_multiple_registers(dev, 1, reg, value); + up(&devpriv->sem); - down(&slot->mutex); - if (slot->usb) { - *bits = slot->usb->digital_out_shadow; - result = 0; - } - up(&slot->mutex); - return result; + return ret; } -static void dt9812_configure_mux(struct usb_dt9812 *dev, +static void dt9812_configure_mux(struct comedi_device *dev, struct dt9812_rmw_byte *rmw, int channel) { - if (dev->device == DT9812_DEVID_DT9812_10) { + struct dt9812_private *devpriv = dev->private; + + if (devpriv->device == DT9812_DEVID_DT9812_10) { /* In the DT9812/10V MUX is selected by P1.5-7 */ rmw->address = F020_SFR_P1; rmw->and_mask = 0xe0; @@ -485,18 +390,21 @@ static void dt9812_configure_mux(struct usb_dt9812 *dev, } } -static void dt9812_configure_gain(struct usb_dt9812 *dev, +static void dt9812_configure_gain(struct comedi_device *dev, struct dt9812_rmw_byte *rmw, enum dt9812_gain gain) { - if (dev->device == DT9812_DEVID_DT9812_10) { - /* In the DT9812/10V, there is an external gain of 0.5 */ + struct dt9812_private *devpriv = dev->private; + + /* In the DT9812/10V, there is an external gain of 0.5 */ + if (devpriv->device == DT9812_DEVID_DT9812_10) gain <<= 1; - } rmw->address = F020_SFR_ADC0CF; rmw->and_mask = F020_MASK_ADC0CF_AMP0GN2 | - F020_MASK_ADC0CF_AMP0GN1 | F020_MASK_ADC0CF_AMP0GN0; + F020_MASK_ADC0CF_AMP0GN1 | + F020_MASK_ADC0CF_AMP0GN0; + switch (gain) { /* * 000 -> Gain = 1 @@ -508,8 +416,10 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev, */ case DT9812_GAIN_0PT5: rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 | - F020_MASK_ADC0CF_AMP0GN1; + F020_MASK_ADC0CF_AMP0GN1; break; + default: + /* this should never happen, just use a gain of 1 */ case DT9812_GAIN_1: rmw->or_value = 0x00; break; @@ -521,20 +431,18 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev, break; case DT9812_GAIN_8: rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 | - F020_MASK_ADC0CF_AMP0GN0; + F020_MASK_ADC0CF_AMP0GN0; break; case DT9812_GAIN_16: rmw->or_value = F020_MASK_ADC0CF_AMP0GN2; break; - default: - dev_err(&dev->interface->dev, "Illegal gain %d\n", gain); - } } -static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value, - enum dt9812_gain gain) +static int dt9812_analog_in(struct comedi_device *dev, + int channel, u16 *value, enum dt9812_gain gain) { + struct dt9812_private *devpriv = dev->private; struct dt9812_rmw_byte rmw[3]; u8 reg[3] = { F020_SFR_ADC0CN, @@ -542,31 +450,30 @@ static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value, F020_SFR_ADC0L }; u8 val[3]; - int result = -ENODEV; + int ret; - down(&slot->mutex); - if (!slot->usb) - goto exit; + down(&devpriv->sem); /* 1 select the gain */ - dt9812_configure_gain(slot->usb, &rmw[0], gain); + dt9812_configure_gain(dev, &rmw[0], gain); /* 2 set the MUX to select the channel */ - dt9812_configure_mux(slot->usb, &rmw[1], channel); + dt9812_configure_mux(dev, &rmw[1], channel); /* 3 start conversion */ rmw[2].address = F020_SFR_ADC0CN; rmw[2].and_mask = 0xff; rmw[2].or_value = F020_MASK_ADC0CN_AD0EN | F020_MASK_ADC0CN_AD0BUSY; - result = dt9812_rmw_multiple_registers(slot->usb, 3, rmw); - if (result) + ret = dt9812_rmw_multiple_registers(dev, 3, rmw); + if (ret) goto exit; /* read the status and ADC */ - result = dt9812_read_multiple_registers(slot->usb, 3, reg, val); - if (result) + ret = dt9812_read_multiple_registers(dev, 3, reg, val); + if (ret) goto exit; + /* * An ADC conversion takes 16 SAR clocks cycles, i.e. about 9us. * Therefore, between the instant that AD0BUSY was set via @@ -578,7 +485,7 @@ static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value, */ if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) == F020_MASK_ADC0CN_AD0INT) { - switch (slot->usb->device) { + switch (devpriv->device) { case DT9812_DEVID_DT9812_10: /* * For DT9812-10V the personality module set the @@ -594,422 +501,284 @@ static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value, } exit: - up(&slot->mutex); - return result; + up(&devpriv->sem); + + return ret; } -static int dt9812_analog_out_shadow(struct slot_dt9812 *slot, int channel, - u16 *value) +static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) { - int result = -ENODEV; + struct dt9812_private *devpriv = dev->private; + struct dt9812_rmw_byte rmw[3]; + int ret; - down(&slot->mutex); - if (slot->usb) { - *value = slot->usb->analog_out_shadow[channel]; - result = 0; + down(&devpriv->sem); + + switch (channel) { + case 0: + /* 1. Set DAC mode */ + rmw[0].address = F020_SFR_DAC0CN; + rmw[0].and_mask = 0xff; + rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + + /* 2 load low byte of DAC value first */ + rmw[1].address = F020_SFR_DAC0L; + rmw[1].and_mask = 0xff; + rmw[1].or_value = value & 0xff; + + /* 3 load high byte of DAC value next to latch the + 12-bit value */ + rmw[2].address = F020_SFR_DAC0H; + rmw[2].and_mask = 0xff; + rmw[2].or_value = (value >> 8) & 0xf; + break; + + case 1: + /* 1. Set DAC mode */ + rmw[0].address = F020_SFR_DAC1CN; + rmw[0].and_mask = 0xff; + rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + + /* 2 load low byte of DAC value first */ + rmw[1].address = F020_SFR_DAC1L; + rmw[1].and_mask = 0xff; + rmw[1].or_value = value & 0xff; + + /* 3 load high byte of DAC value next to latch the + 12-bit value */ + rmw[2].address = F020_SFR_DAC1H; + rmw[2].and_mask = 0xff; + rmw[2].or_value = (value >> 8) & 0xf; + break; } - up(&slot->mutex); + ret = dt9812_rmw_multiple_registers(dev, 3, rmw); + devpriv->ao_shadow[channel] = value; - return result; + up(&devpriv->sem); + + return ret; } -static int dt9812_analog_out(struct slot_dt9812 *slot, int channel, u16 value) +static int dt9812_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int result = -ENODEV; + u8 bits = 0; + int ret; - down(&slot->mutex); - if (slot->usb) { - struct dt9812_rmw_byte rmw[3]; + ret = dt9812_digital_in(dev, &bits); + if (ret) + return ret; - switch (channel) { - case 0: - /* 1. Set DAC mode */ - rmw[0].address = F020_SFR_DAC0CN; - rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; - - /* 2 load low byte of DAC value first */ - rmw[1].address = F020_SFR_DAC0L; - rmw[1].and_mask = 0xff; - rmw[1].or_value = value & 0xff; - - /* 3 load high byte of DAC value next to latch the - 12-bit value */ - rmw[2].address = F020_SFR_DAC0H; - rmw[2].and_mask = 0xff; - rmw[2].or_value = (value >> 8) & 0xf; - break; + data[1] = bits; - case 1: - /* 1. Set DAC mode */ - rmw[0].address = F020_SFR_DAC1CN; - rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; - - /* 2 load low byte of DAC value first */ - rmw[1].address = F020_SFR_DAC1L; - rmw[1].and_mask = 0xff; - rmw[1].or_value = value & 0xff; - - /* 3 load high byte of DAC value next to latch the - 12-bit value */ - rmw[2].address = F020_SFR_DAC1H; - rmw[2].and_mask = 0xff; - rmw[2].or_value = (value >> 8) & 0xf; - break; - } - result = dt9812_rmw_multiple_registers(slot->usb, 3, rmw); - slot->usb->analog_out_shadow[channel] = value; + return insn->n; +} + +static int dt9812_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask = data[0]; + unsigned int bits = data[1]; + + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + dt9812_digital_out(dev, s->state); } - up(&slot->mutex); - return result; + data[1] = s->state; + + return insn->n; } -/* - * USB framework functions - */ +static int dt9812_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + u16 val = 0; + int ret; + int i; -static int dt9812_probe(struct usb_interface *interface, - const struct usb_device_id *id) + for (i = 0; i < insn->n; i++) { + ret = dt9812_analog_in(dev, chan, &val, DT9812_GAIN_1); + if (ret) + return ret; + data[i] = val; + } + + return insn->n; +} + +static int dt9812_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int retval = -ENOMEM; - struct usb_dt9812 *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; + struct dt9812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - u8 fw; - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) - goto error; + down(&devpriv->sem); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_shadow[chan]; + up(&devpriv->sem); + + return insn->n; +} + +static int dt9812_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; + int i; - kref_init(&dev->kref); + for (i = 0; i < insn->n; i++) { + ret = dt9812_analog_out(dev, chan, data[i]); + if (ret) + return ret; + } - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; + return insn->n; +} - /* Check endpoints */ - iface_desc = interface->cur_altsetting; +static int dt9812_find_endpoints(struct comedi_device *dev) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_host_interface *host = intf->cur_altsetting; + struct dt9812_private *devpriv = dev->private; + struct usb_endpoint_descriptor *ep; + int i; - if (iface_desc->desc.bNumEndpoints != 5) { - dev_err(&interface->dev, "Wrong number of endpoints.\n"); - retval = -ENODEV; - goto error; + if (host->desc.bNumEndpoints != 5) { + dev_err(dev->class_dev, "Wrong number of endpoints\n"); + return -ENODEV; } - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - int direction = -1; - endpoint = &iface_desc->endpoint[i].desc; + for (i = 0; i < host->desc.bNumEndpoints; ++i) { + int dir = -1; + ep = &host->endpoint[i].desc; switch (i) { case 0: - direction = USB_DIR_IN; - dev->message_pipe.addr = endpoint->bEndpointAddress; - dev->message_pipe.size = - le16_to_cpu(endpoint->wMaxPacketSize); - + /* unused message pipe */ + dir = USB_DIR_IN; break; case 1: - direction = USB_DIR_OUT; - dev->command_write.addr = endpoint->bEndpointAddress; - dev->command_write.size = - le16_to_cpu(endpoint->wMaxPacketSize); + dir = USB_DIR_OUT; + devpriv->cmd_wr.addr = ep->bEndpointAddress; + devpriv->cmd_wr.size = le16_to_cpu(ep->wMaxPacketSize); break; case 2: - direction = USB_DIR_IN; - dev->command_read.addr = endpoint->bEndpointAddress; - dev->command_read.size = - le16_to_cpu(endpoint->wMaxPacketSize); + dir = USB_DIR_IN; + devpriv->cmd_rd.addr = ep->bEndpointAddress; + devpriv->cmd_rd.size = le16_to_cpu(ep->wMaxPacketSize); break; case 3: - direction = USB_DIR_OUT; - dev->write_stream.addr = endpoint->bEndpointAddress; - dev->write_stream.size = - le16_to_cpu(endpoint->wMaxPacketSize); + /* unused write stream */ + dir = USB_DIR_OUT; break; case 4: - direction = USB_DIR_IN; - dev->read_stream.addr = endpoint->bEndpointAddress; - dev->read_stream.size = - le16_to_cpu(endpoint->wMaxPacketSize); + /* unused read stream */ + dir = USB_DIR_IN; break; } - if ((endpoint->bEndpointAddress & USB_DIR_IN) != direction) { - dev_err(&interface->dev, - "Endpoint has wrong direction.\n"); - retval = -ENODEV; - goto error; + if ((ep->bEndpointAddress & USB_DIR_IN) != dir) { + dev_err(dev->class_dev, + "Endpoint has wrong direction\n"); + return -ENODEV; } } - if (dt9812_read_info(dev, 0, &fw, sizeof(fw)) != 0) { + return 0; +} + +static int dt9812_reset_device(struct comedi_device *dev) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; + u32 serial; + u16 vendor; + u16 product; + u16 tmp16; + u8 tmp8; + int ret; + int i; + + ret = dt9812_read_info(dev, 0, &tmp8, sizeof(tmp8)); + if (ret) { /* * Seems like a configuration reset is necessary if driver is * reloaded while device is attached */ - usb_reset_configuration(dev->udev); + usb_reset_configuration(usb); for (i = 0; i < 10; i++) { - retval = dt9812_read_info(dev, 1, &fw, sizeof(fw)); - if (retval == 0) { - dev_info(&interface->dev, - "usb_reset_configuration succeeded " - "after %d iterations\n", i); + ret = dt9812_read_info(dev, 1, &tmp8, sizeof(tmp8)); + if (ret == 0) break; - } } - } - - if (dt9812_read_info(dev, 1, &dev->vendor, sizeof(dev->vendor)) != 0) { - dev_err(&interface->dev, "Failed to read vendor.\n"); - retval = -ENODEV; - goto error; - } - if (dt9812_read_info(dev, 3, &dev->product, sizeof(dev->product)) != 0) { - dev_err(&interface->dev, "Failed to read product.\n"); - retval = -ENODEV; - goto error; - } - if (dt9812_read_info(dev, 5, &dev->device, sizeof(dev->device)) != 0) { - dev_err(&interface->dev, "Failed to read device.\n"); - retval = -ENODEV; - goto error; - } - if (dt9812_read_info(dev, 7, &dev->serial, sizeof(dev->serial)) != 0) { - dev_err(&interface->dev, "Failed to read serial.\n"); - retval = -ENODEV; - goto error; - } - - dev->vendor = le16_to_cpu(dev->vendor); - dev->product = le16_to_cpu(dev->product); - dev->device = le16_to_cpu(dev->device); - dev->serial = le32_to_cpu(dev->serial); - switch (dev->device) { - case DT9812_DEVID_DT9812_10: - dev->analog_out_shadow[0] = 0x0800; - dev->analog_out_shadow[1] = 0x800; - break; - case DT9812_DEVID_DT9812_2PT5: - dev->analog_out_shadow[0] = 0x0000; - dev->analog_out_shadow[1] = 0x0000; - break; - } - dev->digital_out_shadow = 0; - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n", - dev->vendor, dev->product, dev->device, dev->serial); - - down(&dt9812_mutex); - { - /* Find a slot for the USB device */ - struct slot_dt9812 *first = NULL; - struct slot_dt9812 *best = NULL; - - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - if (!first && !dt9812[i].usb && dt9812[i].serial == 0) - first = &dt9812[i]; - if (!best && dt9812[i].serial == dev->serial) - best = &dt9812[i]; - } - - if (!best) - best = first; - - if (best) { - down(&best->mutex); - best->usb = dev; - dev->slot = best; - up(&best->mutex); + if (ret) { + dev_err(dev->class_dev, + "unable to reset configuration\n"); + return ret; } } - up(&dt9812_mutex); - - return 0; -error: - if (dev) - kref_put(&dev->kref, dt9812_delete); - return retval; -} - -static void dt9812_disconnect(struct usb_interface *interface) -{ - struct usb_dt9812 *dev; - int minor = interface->minor; - - down(&dt9812_mutex); - dev = usb_get_intfdata(interface); - if (dev->slot) { - down(&dev->slot->mutex); - dev->slot->usb = NULL; - up(&dev->slot->mutex); - dev->slot = NULL; + ret = dt9812_read_info(dev, 1, &vendor, sizeof(vendor)); + if (ret) { + dev_err(dev->class_dev, "failed to read vendor id\n"); + return ret; } - usb_set_intfdata(interface, NULL); - up(&dt9812_mutex); - - /* queue final destruction */ - kref_put(&dev->kref, dt9812_delete); - - dev_info(&interface->dev, "USB Dt9812 #%d now disconnected\n", minor); -} + vendor = le16_to_cpu(vendor); -static struct usb_driver dt9812_usb_driver = { - .name = "dt9812", - .probe = dt9812_probe, - .disconnect = dt9812_disconnect, - .id_table = dt9812_table, -}; - -/* - * Comedi functions - */ - -static int dt9812_comedi_open(struct comedi_device *dev) -{ - struct comedi_dt9812 *devpriv = dev->private; - int result = -ENODEV; - - down(&devpriv->slot->mutex); - if (devpriv->slot->usb) { - /* We have an attached device, fill in current range info */ - struct comedi_subdevice *s; - - s = &dev->subdevices[0]; - s->n_chan = 8; - s->maxdata = 1; - - s = &dev->subdevices[1]; - s->n_chan = 8; - s->maxdata = 1; - - s = &dev->subdevices[2]; - s->n_chan = 8; - switch (devpriv->slot->usb->device) { - case 0:{ - s->maxdata = 4095; - s->range_table = &range_bipolar10; - } - break; - case 1:{ - s->maxdata = 4095; - s->range_table = &range_unipolar2_5; - } - break; - } - - s = &dev->subdevices[3]; - s->n_chan = 2; - switch (devpriv->slot->usb->device) { - case 0:{ - s->maxdata = 4095; - s->range_table = &range_bipolar10; - } - break; - case 1:{ - s->maxdata = 4095; - s->range_table = &range_unipolar2_5; - } - break; - } - result = 0; + ret = dt9812_read_info(dev, 3, &product, sizeof(product)); + if (ret) { + dev_err(dev->class_dev, "failed to read product id\n"); + return ret; } - up(&devpriv->slot->mutex); - return result; -} - -static int dt9812_di_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct comedi_dt9812 *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); - int n; - u8 bits = 0; - - dt9812_digital_in(devpriv->slot, &bits); - for (n = 0; n < insn->n; n++) - data[n] = ((1 << channel) & bits) != 0; - return n; -} + product = le16_to_cpu(product); -static int dt9812_do_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct comedi_dt9812 *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); - int n; - u8 bits = 0; - - dt9812_digital_out_shadow(devpriv->slot, &bits); - for (n = 0; n < insn->n; n++) { - u8 mask = 1 << channel; - - bits &= ~mask; - if (data[n]) - bits |= mask; + ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16)); + if (ret) { + dev_err(dev->class_dev, "failed to read device id\n"); + return ret; } - dt9812_digital_out(devpriv->slot, bits); - return n; -} + devpriv->device = le16_to_cpu(tmp16); -static int dt9812_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct comedi_dt9812 *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); - int n; - - for (n = 0; n < insn->n; n++) { - u16 value = 0; - - dt9812_analog_in(devpriv->slot, channel, &value, DT9812_GAIN_1); - data[n] = value; + ret = dt9812_read_info(dev, 7, &serial, sizeof(serial)); + if (ret) { + dev_err(dev->class_dev, "failed to read serial number\n"); + return ret; } - return n; -} + serial = le32_to_cpu(serial); -static int dt9812_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct comedi_dt9812 *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); - int n; - u16 value; - - for (n = 0; n < insn->n; n++) { - value = 0; - dt9812_analog_out_shadow(devpriv->slot, channel, &value); - data[n] = value; - } - return n; -} + /* let the user know what node this device is now attached to */ + dev_info(dev->class_dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n", + vendor, product, devpriv->device, serial); -static int dt9812_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct comedi_dt9812 *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); - int n; + if (devpriv->device != DT9812_DEVID_DT9812_10 && + devpriv->device != DT9812_DEVID_DT9812_2PT5) { + dev_err(dev->class_dev, "Unsupported device!\n"); + return -EINVAL; + } - for (n = 0; n < insn->n; n++) - dt9812_analog_out(devpriv->slot, channel, data[n]); - return n; + return 0; } -static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int dt9812_auto_attach(struct comedi_device *dev, + unsigned long context) { - struct comedi_dt9812 *devpriv; - int i; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct dt9812_private *devpriv; struct comedi_subdevice *s; + bool is_unipolar; int ret; devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); @@ -1017,125 +786,107 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) return -ENOMEM; dev->private = devpriv; - /* - * Special open routine, since USB unit may be unattached at - * comedi_config time, hence range can not be determined - */ - dev->open = dt9812_comedi_open; + sema_init(&devpriv->sem, 1); + usb_set_intfdata(intf, devpriv); - devpriv->serial = it->options[0]; + ret = dt9812_find_endpoints(dev); + if (ret) + return ret; + + ret = dt9812_reset_device(dev); + if (ret) + return ret; + + is_unipolar = (devpriv->device == DT9812_DEVID_DT9812_2PT5); ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - /* digital input subdevice */ + /* Digital Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_read = &dt9812_di_rinsn; - - /* digital output subdevice */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = dt9812_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_write = &dt9812_do_winsn; - - /* analog input subdevice */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = dt9812_do_insn_bits; + + /* Analog Input subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = NULL; - s->insn_read = &dt9812_ai_rinsn; - - /* analog output subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; + s->insn_read = dt9812_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = NULL; - s->insn_write = &dt9812_ao_winsn; - s->insn_read = &dt9812_ao_rinsn; - - dev_info(dev->class_dev, "successfully attached to dt9812.\n"); - - down(&dt9812_mutex); - /* Find a slot for the comedi device */ - { - struct slot_dt9812 *first = NULL; - struct slot_dt9812 *best = NULL; - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - if (!first && !dt9812[i].comedi) { - /* First free slot from comedi side */ - first = &dt9812[i]; - } - if (!best && - dt9812[i].usb && - dt9812[i].usb->serial == devpriv->serial) { - /* We have an attaced device with matching ID */ - best = &dt9812[i]; - } - } - if (!best) - best = first; - if (best) { - down(&best->mutex); - best->comedi = devpriv; - best->serial = devpriv->serial; - devpriv->slot = best; - up(&best->mutex); - } - } - up(&dt9812_mutex); + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; + s->insn_write = dt9812_ao_insn_write; + s->insn_read = dt9812_ao_insn_read; + + devpriv->ao_shadow[0] = is_unipolar ? 0x0000 : 0x0800; + devpriv->ao_shadow[1] = is_unipolar ? 0x0000 : 0x0800; return 0; } static void dt9812_detach(struct comedi_device *dev) { - /* Nothing to cleanup */ -} + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct dt9812_private *devpriv = dev->private; -static struct comedi_driver dt9812_comedi_driver = { - .module = THIS_MODULE, - .driver_name = "dt9812", - .attach = dt9812_attach, - .detach = dt9812_detach, -}; + if (!devpriv) + return; -static int __init usb_dt9812_init(void) -{ - int i; + down(&devpriv->sem); - /* Initialize all driver slots */ - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - sema_init(&dt9812[i].mutex, 1); - dt9812[i].serial = 0; - dt9812[i].usb = NULL; - dt9812[i].comedi = NULL; - } - dt9812[12].serial = 0x0; + usb_set_intfdata(intf, NULL); - return comedi_usb_driver_register(&dt9812_comedi_driver, - &dt9812_usb_driver); + up(&devpriv->sem); } -static void __exit usb_dt9812_exit(void) +static struct comedi_driver dt9812_driver = { + .driver_name = "dt9812", + .module = THIS_MODULE, + .auto_attach = dt9812_auto_attach, + .detach = dt9812_detach, +}; + +static int dt9812_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) { - comedi_usb_driver_unregister(&dt9812_comedi_driver, &dt9812_usb_driver); + return comedi_usb_auto_config(intf, &dt9812_driver, id->driver_info); } -module_init(usb_dt9812_init); -module_exit(usb_dt9812_exit); +static const struct usb_device_id dt9812_usb_table[] = { + { USB_DEVICE(0x0867, 0x9812) }, + { } +}; +MODULE_DEVICE_TABLE(usb, dt9812_usb_table); + +static struct usb_driver dt9812_usb_driver = { + .name = "dt9812", + .id_table = dt9812_usb_table, + .probe = dt9812_usb_probe, + .disconnect = comedi_usb_auto_unconfig, +}; +module_comedi_usb_driver(dt9812_driver, dt9812_usb_driver); MODULE_AUTHOR("Anders Blomdell <anders.blomdell@control.lth.se>"); MODULE_DESCRIPTION("Comedi DT9812 driver"); diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index 93ec8e492ccc..e14dd3ae9ec6 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 0c061df0978c..2fceff93867b 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -18,12 +18,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ /* * Driver: gsc_hpdi diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 08ab9d6e7190..a11e015dc03d 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -13,11 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 90b303ab2300..94609f4aa4c9 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* * Driver: jr3_pci @@ -46,7 +41,6 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/ctype.h> -#include <linux/firmware.h> #include <linux/jiffies.h> #include <linux/slab.h> #include <linux/timer.h> @@ -97,37 +91,6 @@ struct jr3_pci_subdev_private { int retries; }; -/* Hotplug firmware loading stuff */ -static int comedi_load_firmware(struct comedi_device *dev, const char *name, - int (*cb)(struct comedi_device *dev, - const u8 *data, size_t size)) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - int result = 0; - const struct firmware *fw; - char *firmware_path; - static const char *prefix = "comedi/"; - - firmware_path = kmalloc(strlen(prefix) + strlen(name) + 1, GFP_KERNEL); - if (!firmware_path) { - result = -ENOMEM; - } else { - firmware_path[0] = '\0'; - strcat(firmware_path, prefix); - strcat(firmware_path, name); - result = request_firmware(&fw, firmware_path, &pcidev->dev); - if (result == 0) { - if (!cb) - result = -EINVAL; - else - result = cb(dev, fw->data, fw->size); - release_firmware(fw); - } - kfree(firmware_path); - } - return result; -} - static struct poll_delay_t poll_delay_min_max(int min, int max) { struct poll_delay_t result; @@ -362,8 +325,9 @@ static int read_idm_word(const u8 *data, size_t size, int *pos, return result; } -static int jr3_download_firmware(struct comedi_device *dev, const u8 *data, - size_t size) +static int jr3_download_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { /* * IDM file format is: @@ -768,7 +732,9 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, /* Reset DSP card */ writel(0, &devpriv->iobase->channel[0].reset); - result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware); + result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + "comedi/jr3pci.idm", + jr3_download_firmware, 0); dev_dbg(dev->class_dev, "Firmare load %d\n", result); if (result < 0) @@ -778,8 +744,9 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, * format: * model serial Fx Fy Fz Mx My Mz\n * - * comedi_load_firmware(dev, "jr3_offsets_table", - * jr3_download_firmware); + * comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + * "comedi/jr3_offsets_table", + * jr3_download_firmware, 1); */ /* diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index e0e64752e310..f10cf10e5fe3 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ke_counter diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 641e693d5d0e..c2308fd24d6a 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: me4000 diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 09f2a9feaf7c..7533ece3670e 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -37,7 +33,6 @@ #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/sched.h> -#include <linux/firmware.h> #include "../comedidev.h" @@ -391,7 +386,8 @@ static int me_ao_insn_read(struct comedi_device *dev, } static int me2600_xilinx_download(struct comedi_device *dev, - const u8 *data, size_t size) + const u8 *data, size_t size, + unsigned long context) { struct me_private_data *dev_private = dev->private; unsigned int value; @@ -460,22 +456,6 @@ static int me2600_xilinx_download(struct comedi_device *dev, return 0; } -static int me2600_upload_firmware(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, ME2600_FIRMWARE, &pcidev->dev); - if (ret) - return ret; - - ret = me2600_xilinx_download(dev, fw->data, fw->size); - release_firmware(fw); - - return ret; -} - static int me_reset(struct comedi_device *dev) { struct me_private_data *dev_private = dev->private; @@ -529,7 +509,9 @@ static int me_auto_attach(struct comedi_device *dev, /* Download firmware and reset card */ if (board->needs_firmware) { - ret = me2600_upload_firmware(dev); + ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + ME2600_FIRMWARE, + me2600_xilinx_download, 0); if (ret < 0) return ret; } diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index 523c6564ffca..12c34db61d63 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index 255b8ba9c917..d4487e888e64 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _MITE_H_ diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index 4717be4ad268..713842ad6ff6 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: mpc624 diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 7a8292086e18..5ecd1b1666fb 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: multiq3 diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index d10f777b7f17..903c2ef5dd9a 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_6527 diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 3f71f0f54d3c..42a78de47316 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_65xx @@ -286,15 +281,6 @@ static inline struct ni_65xx_subdevice_private *sprivate(struct comedi_subdevice return subdev->private; } -static struct ni_65xx_subdevice_private *ni_65xx_alloc_subdevice_private(void) -{ - struct ni_65xx_subdevice_private *subdev_private = - kzalloc(sizeof(struct ni_65xx_subdevice_private), GFP_KERNEL); - if (subdev_private == NULL) - return NULL; - return subdev_private; -} - static int ni_65xx_config_filter(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -589,6 +575,7 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct ni_65xx_board *board = NULL; struct ni_65xx_private *devpriv; + struct ni_65xx_subdevice_private *spriv; struct comedi_subdevice *s; unsigned i; int ret; @@ -637,10 +624,10 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->insn_config = ni_65xx_dio_insn_config; s->insn_bits = ni_65xx_dio_insn_bits; - s->private = ni_65xx_alloc_subdevice_private(); - if (s->private == NULL) + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) return -ENOMEM; - sprivate(s)->base_port = 0; + spriv->base_port = 0; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -654,10 +641,10 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->maxdata = 1; s->insn_bits = ni_65xx_dio_insn_bits; - s->private = ni_65xx_alloc_subdevice_private(); - if (s->private == NULL) + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) return -ENOMEM; - sprivate(s)->base_port = board->num_di_ports; + spriv->base_port = board->num_di_ports; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -672,10 +659,10 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->insn_config = ni_65xx_dio_insn_config; s->insn_bits = ni_65xx_dio_insn_bits; - s->private = ni_65xx_alloc_subdevice_private(); - if (s->private == NULL) + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) return -ENOMEM; - sprivate(s)->base_port = 0; + spriv->base_port = 0; for (i = 0; i < board->num_dio_ports; ++i) { /* configure all ports for input */ writeb(0x1, @@ -730,7 +717,6 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, static void ni_65xx_detach(struct comedi_device *dev) { struct ni_65xx_private *devpriv = dev->private; - int i; if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) { writeb(0x00, @@ -739,8 +725,6 @@ static void ni_65xx_detach(struct comedi_device *dev) } if (dev->irq) free_irq(dev->irq, dev); - for (i = 0; i < dev->n_subdevices; ++i) - comedi_spriv_free(dev, i); if (devpriv) { if (devpriv->mite) { mite_unsetup(devpriv->mite); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 5cdda7fe97a7..a9e000461ec7 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -11,10 +11,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 42ab6dbf9d39..1a185b9c529f 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_670x diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 2d375168f36d..7ea5aa32e9d2 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -15,12 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: ni_at_a2150 diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 7e5783a4f4e7..e080053c697b 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_at_ao diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index 4ced7ba119b0..713edd55a91b 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: ni_atmio diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index 6c97a0925aad..da7396f94297 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -12,11 +12,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_atmio16d @@ -767,7 +762,6 @@ static int atmio16d_attach(struct comedi_device *dev, static void atmio16d_detach(struct comedi_device *dev) { - comedi_spriv_free(dev, 3); reset_atmio16d(dev); comedi_legacy_detach(dev); } diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index d067ef70e194..3c50e31ecc60 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -15,11 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ /* @@ -40,7 +35,7 @@ port, bit 0; channel 8 corresponds to the input port, bit 0. Digital direction configuration: channels 0-7 output, 8-15 input (8225 device emu as port A output, port B input, port C N/A). -Analog: The input range is 0 to 4095 for -10 to +10 volts +Analog: The input range is 0 to 4095 for -10 to +10 volts IRQ is assigned but not used. Version 0.1 Original DIO only driver @@ -183,7 +178,7 @@ static int daq700_ai_rinsn(struct comedi_device *dev, */ static void daq700_ai_config(struct comedi_device *dev, struct comedi_subdevice *s) -{ +{ unsigned long iobase = dev->iobase; outb(0x80, iobase + CMD_R1); /* disable scanning, ADC to chan 0 */ diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 9b7805fda932..d3d4eb9356a7 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -18,12 +18,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: ni_daq_dio24 @@ -71,17 +65,11 @@ static int dio24_auto_attach(struct comedi_device *dev, return 0; } -static void dio24_detach(struct comedi_device *dev) -{ - comedi_spriv_free(dev, 0); - comedi_pcmcia_disable(dev); -} - static struct comedi_driver driver_dio24 = { .driver_name = "ni_daq_dio24", .module = THIS_MODULE, .auto_attach = dio24_auto_attach, - .detach = dio24_detach, + .detach = comedi_pcmcia_disable, }; static int dio24_cs_attach(struct pcmcia_device *link) diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 77a7bb632580..f161e70b3a0d 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -88,7 +84,7 @@ #define CMD1_REG 0x00 /* W: Command 1 reg */ #define CMD1_MA(x) (((x) & 0x7) << 0) #define CMD1_TWOSCMP (1 << 3) -#define CMD1_GAIN_MASK (7 << 4) +#define CMD1_GAIN(x) (((x) & 0x7) << 4) #define CMD1_SCANEN (1 << 7) #define CMD2_REG 0x01 /* W: Command 2 reg */ #define CMD2_PRETRIG (1 << 0) @@ -153,11 +149,6 @@ enum scan_mode { MODE_MULT_CHAN_DOWN, }; -static const int labpc_plus_ai_gain_bits[] = { - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, -}; - static const struct comedi_lrange range_labpc_plus_ai = { 16, { BIP_RANGE(5), @@ -179,13 +170,7 @@ static const struct comedi_lrange range_labpc_plus_ai = { } }; -const int labpc_1200_ai_gain_bits[] = { - 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, - 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, -}; -EXPORT_SYMBOL_GPL(labpc_1200_ai_gain_bits); - -const struct comedi_lrange range_labpc_1200_ai = { +static const struct comedi_lrange range_labpc_1200_ai = { 14, { BIP_RANGE(5), BIP_RANGE(2.5), @@ -203,7 +188,6 @@ const struct comedi_lrange range_labpc_1200_ai = { UNI_RANGE(0.1) } }; -EXPORT_SYMBOL_GPL(range_labpc_1200_ai); static const struct comedi_lrange range_labpc_ao = { 2, { @@ -239,25 +223,18 @@ static const struct labpc_boardinfo labpc_boards[] = { { .name = "lab-pc-1200", .ai_speed = 10000, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, .ai_scan_up = 1, + .has_ao = 1, + .is_labpc1200 = 1, }, { .name = "lab-pc-1200ai", .ai_speed = 10000, - .register_layout = labpc_1200_layout, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, .ai_scan_up = 1, + .is_labpc1200 = 1, }, { .name = "lab-pc+", .ai_speed = 12000, - .register_layout = labpc_plus_layout, .has_ao = 1, - .ai_range_table = &range_labpc_plus_ai, - .ai_range_code = labpc_plus_ai_gain_bits, }, }; #endif @@ -326,12 +303,21 @@ static void labpc_ai_set_chan_and_gain(struct comedi_device *dev, const struct labpc_boardinfo *board = comedi_board(dev); struct labpc_private *devpriv = dev->private; + if (board->is_labpc1200) { + /* + * The LabPC-1200 boards do not have a gain + * of '0x10'. Skip the range values that would + * result in this gain. + */ + range += (range > 0) + (range > 7); + } + /* munge channel bits for differential/scan disabled mode */ if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) && aref == AREF_DIFF) chan *= 2; devpriv->cmd1 = CMD1_MA(chan); - devpriv->cmd1 |= board->ai_range_code[range]; + devpriv->cmd1 |= CMD1_GAIN(range); devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG); } @@ -347,7 +333,7 @@ static void labpc_setup_cmd6_reg(struct comedi_device *dev, const struct labpc_boardinfo *board = comedi_board(dev); struct labpc_private *devpriv = dev->private; - if (board->register_layout != labpc_1200_layout) + if (!board->is_labpc1200) return; /* reference inputs to ground or common? */ @@ -759,7 +745,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); stop_mask = TRIG_COUNT | TRIG_NONE; - if (board->register_layout == labpc_1200_layout) + if (board->is_labpc1200) stop_mask |= TRIG_EXT; err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask); @@ -895,7 +881,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* pc-plus has no fifo-half full interrupt */ } else #endif - if (board->register_layout == labpc_1200_layout && + if (board->is_labpc1200 && /* wake-end-of-scan should interrupt on fifo not empty */ (cmd->flags & TRIG_WAKE_EOS) == 0 && /* make sure we are taking more than just a few points */ @@ -1175,7 +1161,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* read board status */ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); - if (board->register_layout == labpc_1200_layout) + if (board->is_labpc1200) devpriv->stat2 = devpriv->read_byte(dev->iobase + STAT2_REG); if ((devpriv->stat1 & (STAT1_GATA0 | STAT1_CNTINT | STAT1_OVERFLOW | @@ -1201,8 +1187,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) * has occurred */ if (devpriv->stat1 & STAT1_GATA0 || - (board->register_layout == labpc_1200_layout - && devpriv->stat2 & STAT2_OUTA1)) { + (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1)) { handle_isa_dma(dev); } } else @@ -1266,7 +1251,7 @@ static int labpc_ao_insn_write(struct comedi_device *dev, spin_unlock_irqrestore(&dev->spinlock, flags); /* set range */ - if (board->register_layout == labpc_1200_layout) { + if (board->is_labpc1200) { range = CR_RANGE(insn->chanspec); if (labpc_range_is_unipolar(s, range)) devpriv->cmd6 |= CMD6_DACUNI(channel); @@ -1603,7 +1588,7 @@ int labpc_common_attach(struct comedi_device *dev, devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG); devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG); devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG); - if (board->register_layout == labpc_1200_layout) { + if (board->is_labpc1200) { devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG); } @@ -1626,7 +1611,8 @@ int labpc_common_attach(struct comedi_device *dev, s->n_chan = 8; s->len_chanlist = 8; s->maxdata = 0x0fff; - s->range_table = board->ai_range_table; + s->range_table = board->is_labpc1200 + ? &range_labpc_1200_ai : &range_labpc_plus_ai; s->insn_read = labpc_ai_insn_read; if (dev->irq) { dev->read_subdev = s; @@ -1671,7 +1657,7 @@ int labpc_common_attach(struct comedi_device *dev, /* calibration subdevices for boards that have one */ s = &dev->subdevices[3]; - if (board->register_layout == labpc_1200_layout) { + if (board->is_labpc1200) { s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 16; @@ -1686,7 +1672,7 @@ int labpc_common_attach(struct comedi_device *dev, /* EEPROM */ s = &dev->subdevices[4]; - if (board->register_layout == labpc_1200_layout) { + if (board->is_labpc1200) { s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = EEPROM_SIZE; @@ -1703,12 +1689,6 @@ int labpc_common_attach(struct comedi_device *dev, } EXPORT_SYMBOL_GPL(labpc_common_attach); -void labpc_common_detach(struct comedi_device *dev) -{ - comedi_spriv_free(dev, 2); -} -EXPORT_SYMBOL_GPL(labpc_common_detach); - #if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA) static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -1761,8 +1741,6 @@ static void labpc_detach(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - labpc_common_detach(dev); - if (devpriv) { kfree(devpriv->dma_buffer); if (devpriv->dma_chan) diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h index 4b691f5a9965..486589fa6fd8 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.h +++ b/drivers/staging/comedi/drivers/ni_labpc.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _NI_LABPC_H @@ -27,27 +22,17 @@ #define EEPROM_SIZE 256 /* 256 byte eeprom */ #define NUM_AO_CHAN 2 /* boards have two analog output channels */ -enum labpc_register_layout { labpc_plus_layout, labpc_1200_layout }; enum transfer_type { fifo_not_empty_transfer, fifo_half_full_transfer, isa_dma_transfer }; struct labpc_boardinfo { const char *name; - int device_id; /* device id for pci and pcmcia boards */ - int ai_speed; /* maximum input speed in nanoseconds */ - - /* 1200 has extra registers compared to pc+ */ - enum labpc_register_layout register_layout; - int has_ao; /* has analog output true/false */ - const struct comedi_lrange *ai_range_table; - const int *ai_range_code; - - /* board can auto scan up in ai channels, not just down */ - unsigned ai_scan_up:1; - - /* uses memory mapped io instead of ioports */ - unsigned has_mmio:1; + int ai_speed; /* maximum input speed in ns */ + unsigned ai_scan_up:1; /* can auto scan up in ai channels */ + unsigned has_ao:1; /* has analog outputs */ + unsigned is_labpc1200:1; /* has extra regs compared to pc+ */ + unsigned has_mmio:1; /* uses memory mapped io */ }; struct labpc_private { @@ -101,9 +86,5 @@ struct labpc_private { int labpc_common_attach(struct comedi_device *dev, unsigned int irq, unsigned long isr_flags); -void labpc_common_detach(struct comedi_device *dev); - -extern const int labpc_1200_ai_gain_bits[]; -extern const struct comedi_lrange range_labpc_1200_ai; #endif /* _NI_LABPC_H */ diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index 9e3737c6918d..ce67f4bbb1f5 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -18,12 +18,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: ni_labpc_cs @@ -76,12 +70,9 @@ NI manuals: static const struct labpc_boardinfo labpc_cs_boards[] = { { .name = "daqcard-1200", - .device_id = 0x103, .ai_speed = 10000, - .register_layout = labpc_1200_layout, .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, + .is_labpc1200 = 1, }, }; @@ -113,17 +104,11 @@ static int labpc_auto_attach(struct comedi_device *dev, return labpc_common_attach(dev, link->irq, IRQF_SHARED); } -static void labpc_detach(struct comedi_device *dev) -{ - labpc_common_detach(dev); - comedi_pcmcia_disable(dev); -} - static struct comedi_driver driver_labpc_cs = { .driver_name = "ni_labpc_cs", .module = THIS_MODULE, .auto_attach = labpc_auto_attach, - .detach = labpc_detach, + .detach = comedi_pcmcia_disable, }; static int labpc_cs_attach(struct pcmcia_device *link) diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c index 8e916f86ccea..6c79237b2b5c 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_pci.c +++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -50,11 +46,9 @@ static const struct labpc_boardinfo labpc_pci_boards[] = { [BOARD_NI_PCI1200] = { .name = "ni_pci-1200", .ai_speed = 10000, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, .ai_scan_up = 1, + .has_ao = 1, + .is_labpc1200 = 1, .has_mmio = 1, }, }; @@ -98,8 +92,6 @@ static void labpc_pci_detach(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - labpc_common_detach(dev); - if (devpriv && devpriv->mite) { mite_unsetup(devpriv->mite); mite_free(devpriv->mite); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 8c5dee9b3b05..3e9f544e67fc 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -15,11 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* @@ -4077,7 +4072,6 @@ static void mio_common_detach(struct comedi_device *dev) ni_gpct_device_destroy(devpriv->counter_dev); } } - comedi_spriv_free(dev, NI_8255_DIO_SUBDEV); } static void init_ao_67xx(struct comedi_device *dev, struct comedi_subdevice *s) diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index 888be7b89d2d..f813f5763671 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_mio_cs diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index b5f340c186ec..5b2f72e102e1 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_pcidio @@ -58,7 +53,6 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/sched.h> -#include <linux/firmware.h> #include "../comedidev.h" @@ -971,11 +965,13 @@ static int ni_pcidio_change(struct comedi_device *dev, return 0; } -static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, - const u8 *data, size_t data_len) +static int pci_6534_load_fpga(struct comedi_device *dev, + const u8 *data, size_t data_len, + unsigned long context) { struct nidio96_private *devpriv = dev->private; static const int timeout = 1000; + int fpga_index = context; int i; size_t j; @@ -1033,7 +1029,7 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, static int pci_6534_reset_fpga(struct comedi_device *dev, int fpga_index) { - return pci_6534_load_fpga(dev, fpga_index, NULL, 0); + return pci_6534_load_fpga(dev, NULL, 0, fpga_index); } static int pci_6534_reset_fpgas(struct comedi_device *dev) @@ -1067,13 +1063,12 @@ static void pci_6534_init_main_fpga(struct comedi_device *dev) static int pci_6534_upload_firmware(struct comedi_device *dev) { struct nidio96_private *devpriv = dev->private; - int ret; - const struct firmware *fw; static const char *const fw_file[3] = { FW_PCI_6534_SCARAB_DI, /* loaded into scarab A for DI */ FW_PCI_6534_SCARAB_DO, /* loaded into scarab B for DO */ FW_PCI_6534_MAIN, /* loaded into main FPGA */ }; + int ret; int n; ret = pci_6534_reset_fpgas(dev); @@ -1081,14 +1076,11 @@ static int pci_6534_upload_firmware(struct comedi_device *dev) return ret; /* load main FPGA first, then the two scarabs */ for (n = 2; n >= 0; n--) { - ret = request_firmware(&fw, fw_file[n], - &devpriv->mite->pcidev->dev); - if (ret == 0) { - ret = pci_6534_load_fpga(dev, n, fw->data, fw->size); - if (ret == 0 && n == 2) - pci_6534_init_main_fpga(dev); - release_firmware(fw); - } + ret = comedi_load_firmware(dev, &devpriv->mite->pcidev->dev, + fw_file[n], + pci_6534_load_fpga, n); + if (ret == 0 && n == 2) + pci_6534_init_main_fpga(dev); if (ret < 0) break; } diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 634d02303aa0..35681ba1f369 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: ni_pcimio diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index 0a613c077608..11bf0aab82ea 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c index 225287769dc1..f2cf76d15d78 100644 --- a/drivers/staging/comedi/drivers/ni_tio.c +++ b/drivers/staging/comedi/drivers/ni_tio.c @@ -13,10 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h index 8572996539fa..7e13697b3254 100644 --- a/drivers/staging/comedi/drivers/ni_tio.h +++ b/drivers/staging/comedi/drivers/ni_tio.h @@ -13,11 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_NI_TIO_H diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h index 5e00212aa022..b009876754a8 100644 --- a/drivers/staging/comedi/drivers/ni_tio_internal.h +++ b/drivers/staging/comedi/drivers/ni_tio_internal.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_NI_TIO_INTERNAL_H diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 13747f324936..cff50bc45bcd 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -13,10 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index 8be2a4c503cc..7abf3f74144e 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: pcl711 diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c index 4f033d88eeca..cea657c7801d 100644 --- a/drivers/staging/comedi/drivers/pcl724.c +++ b/drivers/staging/comedi/drivers/pcl724.c @@ -1,42 +1,28 @@ /* - comedi/drivers/pcl724.c - - Michal Dobes <dobes@tesnet.cz> - - hardware driver for Advantech cards: - card: PCL-724, PCL-722, PCL-731 - driver: pcl724, pcl722, pcl731 - and ADLink cards: - card: ACL-7122, ACL-7124, PET-48DIO - driver: acl7122, acl7124, pet48dio - - Options for PCL-724, PCL-731, ACL-7124 and PET-48DIO: - [0] - IO Base - - Options for PCL-722 and ACL-7122: - [0] - IO Base - [1] - IRQ (0=disable IRQ) IRQ isn't supported at this time! - [2] -number of DIO: - 0, 144: 144 DIO configuration - 1, 96: 96 DIO configuration -*/ -/* -Driver: pcl724 -Description: Advantech PCL-724, PCL-722, PCL-731 ADLink ACL-7122, ACL-7124, - PET-48DIO -Author: Michal Dobes <dobes@tesnet.cz> -Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731), - [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio) -Status: untested - -This is driver for digital I/O boards PCL-722/724/731 with 144/24/48 DIO -and for digital I/O boards ACL-7122/7124/PET-48DIO with 144/24/48 DIO. -It need 8255.o for operations and only immediate mode is supported. -See the source for configuration details. -*/ + * pcl724.c + * Comedi driver for 8255 based ISA DIO boards + * + * Michal Dobes <dobes@tesnet.cz> + */ + /* - * check_driver overrides: - * struct comedi_insn + * Driver: pcl724 + * Description: Comedi driver for 8255 based ISA DIO boards + * Devices: (Advantech) PCL-724 [pcl724] + * (Advantech) PCL-722 [pcl722] + * (Advantech) PCL-731 [pcl731] + * (ADLink) ACL-7122 [acl7122] + * (ADLink) ACL-7124 [acl7124] + * (ADLink) PET-48DIO [pet48dio] + * Author: Michal Dobes <dobes@tesnet.cz> + * Status: untested + * + * Configuration options: + * [0] - IO Base + * [1] - IRQ (not supported) + * [2] - number of DIO (pcl722 and acl7122 boards) + * 0, 144: 144 DIO configuration + * 1, 96: 96 DIO configuration */ #include "../comedidev.h" @@ -46,40 +32,48 @@ See the source for configuration details. #include "8255.h" -#define PCL722_SIZE 32 -#define PCL722_96_SIZE 16 -#define PCL724_SIZE 4 -#define PCL731_SIZE 8 -#define PET48_SIZE 2 - #define SIZE_8255 4 -/* #define PCL724_IRQ 1 no IRQ support now */ - struct pcl724_board { - - const char *name; /* board name */ - int dio; /* num of DIO */ - int numofports; /* num of 8255 subdevices */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int io_range; /* len of IO space */ - char can_have96; - char is_pet48; + const char *name; + unsigned int io_range; + unsigned int can_have96:1; + unsigned int is_pet48:1; + int numofports; }; -static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) -{ - unsigned long iobase = arg; - - if (dir) { - outb(data, iobase + port); - return 0; - } else { - return inb(iobase + port); - } -} +static const struct pcl724_board boardtypes[] = { + { + .name = "pcl724", + .io_range = 0x04, + .numofports = 1, /* 24 DIO channels */ + }, { + .name = "pcl722", + .io_range = 0x20, + .can_have96 = 1, + .numofports = 6, /* 144 (or 96) DIO channels */ + }, { + .name = "pcl731", + .io_range = 0x08, + .numofports = 2, /* 48 DIO channels */ + }, { + .name = "acl7122", + .io_range = 0x20, + .can_have96 = 1, + .numofports = 6, /* 144 (or 96) DIO channels */ + }, { + .name = "acl7124", + .io_range = 0x04, + .numofports = 1, /* 24 DIO channels */ + }, { + .name = "pet48dio", + .io_range = 0x02, + .is_pet48 = 1, + .numofports = 2, /* 48 DIO channels */ + }, +}; -static int subdev_8255mapped_cb(int dir, int port, int data, +static int pcl724_8255mapped_io(int dir, int port, int data, unsigned long iobase) { int movport = SIZE_8255 * (iobase >> 12); @@ -96,57 +90,30 @@ static int subdev_8255mapped_cb(int dir, int port, int data, } } -static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcl724_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { const struct pcl724_board *board = comedi_board(dev); struct comedi_subdevice *s; + unsigned long iobase; unsigned int iorange; - int ret, i, n_subdevices; -#ifdef PCL724_IRQ - unsigned int irq; -#endif + int n_subdevices; + int ret; + int i; iorange = board->io_range; - if ((board->can_have96) && - ((it->options[1] == 1) || (it->options[1] == 96))) - iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */ - ret = comedi_request_region(dev, it->options[0], iorange); - if (ret) - return ret; + n_subdevices = board->numofports; -#ifdef PCL724_IRQ - irq = 0; - if (board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & board->IRQbits) == 0) { - printk(KERN_WARNING - ", IRQ %u is out of allowed range, " - "DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq(irq, interrupt_pcl724, 0, - dev->board_name, dev)) { - printk(KERN_WARNING - ", unable to allocate IRQ %u, " - "DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%u", irq); - } - } - } + /* Handle PCL-724 in 96 DIO configuration */ + if (board->can_have96 && + (it->options[2] == 1 || it->options[2] == 96)) { + iorange = 0x10; + n_subdevices = 4; } - dev->irq = irq; -#endif - - printk("\n"); - - n_subdevices = board->numofports; - if ((board->can_have96) && ((it->options[1] == 1) - || (it->options[1] == 96))) - n_subdevices = 4; /* PCL-724 in 96 DIO configuration */ + ret = comedi_request_region(dev, it->options[0], iorange); + if (ret) + return ret; ret = comedi_alloc_subdevices(dev, n_subdevices); if (ret) @@ -155,41 +122,25 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; if (board->is_pet48) { - subdev_8255_init(dev, s, subdev_8255mapped_cb, - (unsigned long)(dev->iobase + - i * 0x1000)); - } else - subdev_8255_init(dev, s, subdev_8255_cb, - (unsigned long)(dev->iobase + - SIZE_8255 * i)); + iobase = dev->iobase + (i * 0x1000); + ret = subdev_8255_init(dev, s, pcl724_8255mapped_io, + iobase); + } else { + iobase = dev->iobase + (i * SIZE_8255); + ret = subdev_8255_init(dev, s, NULL, iobase); + } + if (ret) + return ret; } return 0; } -static void pcl724_detach(struct comedi_device *dev) -{ - int i; - - for (i = 0; i < dev->n_subdevices; i++) - comedi_spriv_free(dev, i); - comedi_legacy_detach(dev); -} - -static const struct pcl724_board boardtypes[] = { - { "pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, }, - { "pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0, }, - { "pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0, }, - { "acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0, }, - { "acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, }, - { "pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1, }, -}; - static struct comedi_driver pcl724_driver = { .driver_name = "pcl724", .module = THIS_MODULE, .attach = pcl724_attach, - .detach = pcl724_detach, + .detach = comedi_legacy_detach, .board_name = &boardtypes[0].name, .num_names = ARRAY_SIZE(boardtypes), .offset = sizeof(struct pcl724_board), @@ -197,5 +148,5 @@ static struct comedi_driver pcl724_driver = { module_comedi_driver(pcl724_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for 8255 based ISA DIO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c deleted file mode 100644 index 6b02f0631b4c..000000000000 --- a/drivers/staging/comedi/drivers/pcl725.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * comedi/drivers/pcl725.c - * Driver for PCL725 and clones - * David A. Schleef - */ -/* -Driver: pcl725 -Description: Advantech PCL-725 (& compatibles) -Author: ds -Status: unknown -Devices: [Advantech] PCL-725 (pcl725) -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -#define PCL725_SIZE 2 - -#define PCL725_DO 0 -#define PCL725_DI 1 - -static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - outb(s->state, dev->iobase + PCL725_DO); - } - - data[1] = s->state; - - return insn->n; -} - -static int pcl725_di_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[1] = inb(dev->iobase + PCL725_DI); - - return insn->n; -} - -static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int ret; - - ret = comedi_request_region(dev, it->options[0], PCL725_SIZE); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 2); - if (ret) - return ret; - - s = &dev->subdevices[0]; - /* do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcl725_do_insn; - s->range_table = &range_digital; - - s = &dev->subdevices[1]; - /* di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcl725_di_insn; - s->range_table = &range_digital; - - printk(KERN_INFO "\n"); - - return 0; -} - -static struct comedi_driver pcl725_driver = { - .driver_name = "pcl725", - .module = THIS_MODULE, - .attach = pcl725_attach, - .detach = comedi_legacy_detach, -}; -module_comedi_driver(pcl725_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index 4aa994393fae..893f012a1b7a 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -20,11 +20,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: pcl726 diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index 2879db75da3e..862e75fd68fd 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -3,135 +3,299 @@ * Driver for Advantech PCL-730 and clones * José Luis Sánchez */ -/* -Driver: pcl730 -Description: Advantech PCL-730 (& compatibles) -Author: José Luis Sánchez (jsanchezv@teleline.es) -Status: untested -Devices: [Advantech] PCL-730 (pcl730), [ICP] ISO-730 (iso730), - [Adlink] ACL-7130 (acl7130) -Interrupts are not supported. -The ACL-7130 card have an 8254 timer/counter not supported by this driver. -*/ +/* + * Driver: pcl730 + * Description: Advantech PCL-730 (& compatibles) + * Devices: (Advantech) PCL-730 [pcl730] + * (ICP) ISO-730 [iso730] + * (Adlink) ACL-7130 [acl7130] + * (Advantech) PCM-3730 [pcm3730] + * (Advantech) PCL-725 [pcl725] + * (ICP) P8R8-DIO [p16r16dio] + * (Adlink) ACL-7225b [acl7225b] + * (ICP) P16R16-DIO [p16r16dio] + * (Advantech) PCL-733 [pcl733] + * (Advantech) PCL-734 [pcl734] + * Author: José Luis Sánchez (jsanchezv@teleline.es) + * Status: untested + * + * Configuration options: + * [0] - I/O port base + * + * Interrupts are not supported. + * The ACL-7130 card has an 8254 timer/counter not supported by this driver. + */ #include "../comedidev.h" #include <linux/ioport.h> -#define PCL730_SIZE 4 -#define ACL7130_SIZE 8 -#define PCL730_IDIO_LO 0 /* Isolated Digital I/O low byte (ID0-ID7) */ -#define PCL730_IDIO_HI 1 /* Isolated Digital I/O high byte (ID8-ID15) */ -#define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */ -#define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */ +/* + * Register map + * + * The register map varies slightly depending on the board type but + * all registers are 8-bit. + * + * The boardinfo 'io_range' is used to allow comedi to request the + * proper range required by the board. + * + * The comedi_subdevice 'private' data is used to pass the register + * offset to the (*insn_bits) functions to read/write the correct + * registers. + * + * The basic register mapping looks like this: + * + * BASE+0 Isolated outputs 0-7 (write) / inputs 0-7 (read) + * BASE+1 Isolated outputs 8-15 (write) / inputs 8-15 (read) + * BASE+2 TTL outputs 0-7 (write) / inputs 0-7 (read) + * BASE+3 TTL outputs 8-15 (write) / inputs 8-15 (read) + * + * The pcm3730 board does not have register BASE+1. + * + * The pcl725 and p8r8dio only have registers BASE+0 and BASE+1: + * + * BASE+0 Isolated outputs 0-7 (write) (read back on p8r8dio) + * BASE+1 Isolated inputs 0-7 (read) + * + * The acl7225b and p16r16dio boards have this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) (read back) + * BASE+1 Isolated outputs 8-15 (write) (read back) + * BASE+2 Isolated inputs 0-7 (read) + * BASE+3 Isolated inputs 8-15 (read) + * + * The pcl733 and pcl733 boards have this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) or inputs 0-7 (read) + * BASE+1 Isolated outputs 8-15 (write) or inputs 8-15 (read) + * BASE+2 Isolated outputs 16-23 (write) or inputs 16-23 (read) + * BASE+3 Isolated outputs 24-31 (write) or inputs 24-31 (read) + */ struct pcl730_board { + const char *name; + unsigned int io_range; + unsigned is_pcl725:1; + unsigned is_acl7225b:1; + unsigned has_readback:1; + unsigned has_ttl_io:1; + int n_subdevs; + int n_iso_out_chan; + int n_iso_in_chan; + int n_ttl_chan; +}; - const char *name; /* board name */ - unsigned int io_range; /* len of I/O space */ +static const struct pcl730_board pcl730_boards[] = { + { + .name = "pcl730", + .io_range = 0x04, + .has_ttl_io = 1, + .n_subdevs = 4, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + .n_ttl_chan = 16, + }, { + .name = "iso730", + .io_range = 0x04, + .n_subdevs = 4, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + .n_ttl_chan = 16, + }, { + .name = "acl7130", + .io_range = 0x08, + .has_ttl_io = 1, + .n_subdevs = 4, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + .n_ttl_chan = 16, + }, { + .name = "pcm3730", + .io_range = 0x04, + .has_ttl_io = 1, + .n_subdevs = 4, + .n_iso_out_chan = 8, + .n_iso_in_chan = 8, + .n_ttl_chan = 16, + }, { + .name = "pcl725", + .io_range = 0x02, + .is_pcl725 = 1, + .n_subdevs = 2, + .n_iso_out_chan = 8, + .n_iso_in_chan = 8, + }, { + .name = "p8r8dio", + .io_range = 0x02, + .is_pcl725 = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 8, + .n_iso_in_chan = 8, + }, { + .name = "acl7225b", + .io_range = 0x08, /* only 4 are used */ + .is_acl7225b = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + }, { + .name = "p16r16dio", + .io_range = 0x04, + .is_acl7225b = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + }, { + .name = "pcl733", + .io_range = 0x04, + .n_subdevs = 1, + .n_iso_in_chan = 32, + }, { + .name = "pcl734", + .io_range = 0x04, + .n_subdevs = 1, + .n_iso_out_chan = 32, + }, }; -static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcl730_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + unsigned long reg = (unsigned long)s->private; + unsigned int mask = data[0]; + unsigned int bits = data[1]; + + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + if (mask & 0x00ff) + outb(s->state & 0xff, dev->iobase + reg); + if ((mask & 0xff00) && (s->n_chan > 8)) + outb((s->state >> 8) & 0xff, dev->iobase + reg + 1); + if ((mask & 0xff0000) && (s->n_chan > 16)) + outb((s->state >> 16) & 0xff, dev->iobase + reg + 2); + if ((mask & 0xff000000) && (s->n_chan > 24)) + outb((s->state >> 24) & 0xff, dev->iobase + reg + 3); } - if (data[0] & 0x00ff) - outb(s->state & 0xff, - dev->iobase + ((unsigned long)s->private)); - if (data[0] & 0xff00) - outb((s->state >> 8), - dev->iobase + ((unsigned long)s->private) + 1); data[1] = s->state; return insn->n; } -static int pcl730_di_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static unsigned int pcl730_get_bits(struct comedi_device *dev, + struct comedi_subdevice *s) { - data[1] = inb(dev->iobase + ((unsigned long)s->private)) | - (inb(dev->iobase + ((unsigned long)s->private) + 1) << 8); + unsigned long reg = (unsigned long)s->private; + unsigned int val; + + val = inb(dev->iobase + reg); + if (s->n_chan > 8) + val |= (inb(dev->iobase + reg + 1) << 8); + if (s->n_chan > 16) + val |= (inb(dev->iobase + reg + 2) << 16); + if (s->n_chan > 24) + val |= (inb(dev->iobase + reg + 3) << 24); + + return val; +} + +static int pcl730_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = pcl730_get_bits(dev, s); return insn->n; } -static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcl730_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { const struct pcl730_board *board = comedi_board(dev); struct comedi_subdevice *s; + int subdev; int ret; ret = comedi_request_region(dev, it->options[0], board->io_range); if (ret) return ret; - ret = comedi_alloc_subdevices(dev, 4); + ret = comedi_alloc_subdevices(dev, board->n_subdevs); if (ret) return ret; - s = &dev->subdevices[0]; - /* Isolated do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_do_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_IDIO_LO; - - s = &dev->subdevices[1]; - /* Isolated di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_di_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_IDIO_LO; - - s = &dev->subdevices[2]; - /* TTL do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_do_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_DIO_LO; - - s = &dev->subdevices[3]; - /* TTL di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_di_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_DIO_LO; - - printk(KERN_INFO "\n"); + subdev = 0; + + if (board->n_iso_out_chan) { + /* Isolated Digital Outputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_iso_out_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_do_insn_bits; + s->private = (void *)0; + + /* get the initial state if supported */ + if (board->has_readback) + s->state = pcl730_get_bits(dev, s); + } + + if (board->n_iso_in_chan) { + /* Isolated Digital Inputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = board->n_iso_in_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_di_insn_bits; + s->private = board->is_acl7225b ? (void *)2 : + board->is_pcl725 ? (void *)1 : (void *)0; + } + + if (board->has_ttl_io) { + /* TTL Digital Outputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_ttl_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_do_insn_bits; + s->private = (void *)2; + + /* TTL Digital Inputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = board->n_ttl_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_di_insn_bits; + s->private = (void *)2; + } return 0; } -static const struct pcl730_board boardtypes[] = { - { "pcl730", PCL730_SIZE, }, - { "iso730", PCL730_SIZE, }, - { "acl7130", ACL7130_SIZE, }, -}; - static struct comedi_driver pcl730_driver = { .driver_name = "pcl730", .module = THIS_MODULE, .attach = pcl730_attach, .detach = comedi_legacy_detach, - .board_name = &boardtypes[0].name, - .num_names = ARRAY_SIZE(boardtypes), + .board_name = &pcl730_boards[0].name, + .num_names = ARRAY_SIZE(pcl730_boards), .offset = sizeof(struct pcl730_board), }; module_comedi_driver(pcl730_driver); diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index 4ef0df30b07a..5a9cd38e15f2 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -250,20 +250,11 @@ static int pcm3724_attach(struct comedi_device *dev, return 0; } -static void pcm3724_detach(struct comedi_device *dev) -{ - int i; - - for (i = 0; i < dev->n_subdevices; i++) - comedi_spriv_free(dev, i); - comedi_legacy_detach(dev); -} - static struct comedi_driver pcm3724_driver = { .driver_name = "pcm3724", .module = THIS_MODULE, .attach = pcm3724_attach, - .detach = pcm3724_detach, + .detach = comedi_legacy_detach, }; module_comedi_driver(pcm3724_driver); diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c deleted file mode 100644 index 3a3ce2c769a2..000000000000 --- a/drivers/staging/comedi/drivers/pcm3730.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * comedi/drivers/pcm3730.c - * Driver for PCM3730 and clones - * Blaine Lee - * from pcl725 by David S. - */ -/* -Driver: pcm3730 -Description: PCM3730 -Author: Blaine Lee -Devices: [Advantech] PCM-3730 (pcm3730) -Status: unknown - -Configuration options: - [0] - I/O port base -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -#define PCM3730_SIZE 4 /* consecutive io port addresses */ - -#define PCM3730_DOA 0 /* offsets for each port */ -#define PCM3730_DOB 2 -#define PCM3730_DOC 3 -#define PCM3730_DIA 0 -#define PCM3730_DIB 2 -#define PCM3730_DIC 3 - -static int pcm3730_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - outb(s->state, dev->iobase + (unsigned long)(s->private)); - } - data[1] = s->state; - - return insn->n; -} - -static int pcm3730_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[1] = inb(dev->iobase + (unsigned long)(s->private)); - return insn->n; -} - -static int pcm3730_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int ret; - - ret = comedi_request_region(dev, it->options[0], PCM3730_SIZE); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 6); - if (ret) - return ret; - - s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_do_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DOA; - - s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_do_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DOB; - - s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_do_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DOC; - - s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DIA; - - s = &dev->subdevices[4]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DIB; - - s = &dev->subdevices[5]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DIC; - - printk(KERN_INFO "\n"); - - return 0; -} - -static struct comedi_driver pcm3730_driver = { - .driver_name = "pcm3730", - .module = THIS_MODULE, - .attach = pcm3730_attach, - .detach = comedi_legacy_detach, -}; -module_comedi_driver(pcm3730_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index b7c932e152e0..d5c728dc6192 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -1,52 +1,44 @@ /* - comedi/drivers/pcmad.c - Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * pcmad.c + * Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -*/ /* -Driver: pcmad -Description: Winsystems PCM-A/D12, PCM-A/D16 -Author: ds -Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16) -Status: untested - -This driver was written on a bet that I couldn't write a driver -in less than 2 hours. I won the bet, but never got paid. =( - -Configuration options: - [0] - I/O port base - [1] - unused - [2] - Analog input reference - 0 = single ended - 1 = differential - [3] - Analog input encoding (must match jumpers) - 0 = straight binary - 1 = two's complement -*/ - -#include <linux/interrupt.h> -#include "../comedidev.h" - -#include <linux/ioport.h> + * Driver: pcmad + * Description: Winsystems PCM-A/D12, PCM-A/D16 + * Devices: (Winsystems) PCM-A/D12 [pcmad12] + * (Winsystems) PCM-A/D16 [pcmad16] + * Author: ds + * Status: untested + * + * This driver was written on a bet that I couldn't write a driver + * in less than 2 hours. I won the bet, but never got paid. =( + * + * Configuration options: + * [0] - I/O port base + * [1] - IRQ (unused) + * [2] - Analog input reference (must match jumpers) + * 0 = single-ended (16 channels) + * 1 = differential (8 channels) + * [3] - Analog input encoding (must match jumpers) + * 0 = straight binary (0-5V input range) + * 1 = two's complement (+-10V input range) + */ -#define PCMAD_SIZE 4 +#include "../comedidev.h" #define PCMAD_STATUS 0 #define PCMAD_LSB 1 @@ -55,60 +47,82 @@ Configuration options: struct pcmad_board_struct { const char *name; - int n_ai_bits; + unsigned int ai_maxdata; }; -struct pcmad_priv_struct { - int differential; - int twos_comp; +static const struct pcmad_board_struct pcmad_boards[] = { + { + .name = "pcmad12", + .ai_maxdata = 0x0fff, + }, { + .name = "pcmad16", + .ai_maxdata = 0xffff, + }, }; #define TIMEOUT 100 +static int pcmad_ai_wait_for_eoc(struct comedi_device *dev, + int timeout) +{ + int i; + + for (i = 0; i < timeout; i++) { + if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) + return 0; + } + return -ETIME; +} + +static bool pcmad_range_is_bipolar(struct comedi_subdevice *s, + unsigned int range) +{ + return s->range_table->range[range].min < 0; +} + static int pcmad_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - const struct pcmad_board_struct *board = comedi_board(dev); - struct pcmad_priv_struct *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int ret; int i; - int chan; - int n; - chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + PCMAD_CONVERT); - for (i = 0; i < TIMEOUT; i++) { - if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) - break; + ret = pcmad_ai_wait_for_eoc(dev, TIMEOUT); + if (ret) + return ret; + + val = inb(dev->iobase + PCMAD_LSB) | + (inb(dev->iobase + PCMAD_MSB) << 8); + + /* data is shifted on the pcmad12, fix it */ + if (s->maxdata == 0x0fff) + val >>= 4; + + if (pcmad_range_is_bipolar(s, range)) { + /* munge the two's complement value */ + val ^= ((s->maxdata + 1) >> 1); } - data[n] = inb(dev->iobase + PCMAD_LSB); - data[n] |= (inb(dev->iobase + PCMAD_MSB) << 8); - if (devpriv->twos_comp) - data[n] ^= (1 << (board->n_ai_bits - 1)); + data[i] = val; } - return n; + return insn->n; } -/* - * options: - * 0 i/o base - * 1 unused - * 2 0=single ended 1=differential - * 3 0=straight binary 1=two's comp - */ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcmad_board_struct *board = comedi_board(dev); - struct pcmad_priv_struct *devpriv; struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], PCMAD_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x04); if (ret) return ret; @@ -116,32 +130,25 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | AREF_GROUND; - s->n_chan = 16; /* XXX */ - s->len_chanlist = 1; - s->insn_read = pcmad_ai_insn_read; - s->maxdata = (1 << board->n_ai_bits) - 1; - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_AI; + if (it->options[1]) { + /* 8 differential channels */ + s->subdev_flags = SDF_READABLE | AREF_DIFF; + s->n_chan = 8; + } else { + /* 16 single-ended channels */ + s->subdev_flags = SDF_READABLE | AREF_GROUND; + s->n_chan = 16; + } + s->len_chanlist = 1; + s->maxdata = board->ai_maxdata; + s->range_table = it->options[2] ? &range_bipolar10 : &range_unipolar5; + s->insn_read = pcmad_ai_insn_read; return 0; } -static const struct pcmad_board_struct pcmad_boards[] = { - { - .name = "pcmad12", - .n_ai_bits = 12, - }, { - .name = "pcmad16", - .n_ai_bits = 16, - }, -}; static struct comedi_driver pcmad_driver = { .driver_name = "pcmad", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 61e7fd14a1e8..774a63dfe040 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -1,152 +1,130 @@ /* - comedi/drivers/pcmda12.c - Driver for Winsystems PC-104 based PCM-D/A-12 8-channel AO board. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * pcmda12.c + * Driver for Winsystems PC-104 based PCM-D/A-12 8-channel AO board. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* -Driver: pcmda12 -Description: A driver for the Winsystems PCM-D/A-12 -Devices: [Winsystems] PCM-D/A-12 (pcmda12) -Author: Calin Culianu <calin@ajvar.org> -Updated: Fri, 13 Jan 2006 12:01:01 -0500 -Status: works - -A driver for the relatively straightforward-to-program PCM-D/A-12. -This board doesn't support commands, and the only way to set its -analog output range is to jumper the board. As such, -comedi_data_write() ignores the range value specified. - -The board uses 16 consecutive I/O addresses starting at the I/O port -base address. Each address corresponds to the LSB then MSB of a -particular channel from 0-7. - -Note that the board is not ISA-PNP capable and thus -needs the I/O port comedi_config parameter. - -Note that passing a nonzero value as the second config option will -enable "simultaneous xfer" mode for this board, in which AO writes -will not take effect until a subsequent read of any AO channel. This -is so that one can speed up programming by preloading all AO registers -with values before simultaneously setting them to take effect with one -read command. - -Configuration Options: - [0] - I/O port base address - [1] - Do Simultaneous Xfer (see description) -*/ + * Driver: pcmda12 + * Description: A driver for the Winsystems PCM-D/A-12 + * Devices: (Winsystems) PCM-D/A-12 [pcmda12] + * Author: Calin Culianu <calin@ajvar.org> + * Updated: Fri, 13 Jan 2006 12:01:01 -0500 + * Status: works + * + * A driver for the relatively straightforward-to-program PCM-D/A-12. + * This board doesn't support commands, and the only way to set its + * analog output range is to jumper the board. As such, + * comedi_data_write() ignores the range value specified. + * + * The board uses 16 consecutive I/O addresses starting at the I/O port + * base address. Each address corresponds to the LSB then MSB of a + * particular channel from 0-7. + * + * Note that the board is not ISA-PNP capable and thus needs the I/O + * port comedi_config parameter. + * + * Note that passing a nonzero value as the second config option will + * enable "simultaneous xfer" mode for this board, in which AO writes + * will not take effect until a subsequent read of any AO channel. This + * is so that one can speed up programming by preloading all AO registers + * with values before simultaneously setting them to take effect with one + * read command. + * + * Configuration Options: + * [0] - I/O port base address + * [1] - Do Simultaneous Xfer (see description) + */ #include "../comedidev.h" -#define CHANS 8 -#define IOSIZE 16 -#define LSB(x) ((unsigned char)((x) & 0xff)) -#define MSB(x) ((unsigned char)((((unsigned short)(x))>>8) & 0xff)) -#define LSB_PORT(chan) (dev->iobase + (chan)*2) -#define MSB_PORT(chan) (LSB_PORT(chan)+1) -#define BITS 12 - -/* note these have no effect and are merely here for reference.. - these are configured by jumpering the board! */ +/* AI range is not configurable, it's set by jumpers on the board */ static const struct comedi_lrange pcmda12_ranges = { - 3, - { - UNI_RANGE(5), UNI_RANGE(10), BIP_RANGE(5) - } + 3, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5) + } }; struct pcmda12_private { - - unsigned int ao_readback[CHANS]; + unsigned int ao_readback[8]; int simultaneous_xfer_mode; }; -static void zero_chans(struct comedi_device *dev) -{ /* sets up an - ASIC chip to defaults */ - int i; - for (i = 0; i < CHANS; ++i) { -/* /\* do this as one instruction?? *\/ */ -/* outw(0, LSB_PORT(chan)); */ - outb(0, LSB_PORT(i)); - outb(0, MSB_PORT(i)); - } - inb(LSB_PORT(0)); /* update chans. */ -} - -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmda12_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcmda12_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + unsigned long ioreg = dev->iobase + (chan * 2); int i; - int chan = CR_CHAN(insn->chanspec); - /* Writing a list of values to an AO channel is probably not - * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; ++i) { - -/* /\* do this as one instruction?? *\/ */ -/* outw(data[i], LSB_PORT(chan)); */ - - /* Need to do this as two instructions due to 8-bit bus?? */ - /* first, load the low byte */ - outb(LSB(data[i]), LSB_PORT(chan)); - /* next, write the high byte */ - outb(MSB(data[i]), MSB_PORT(chan)); - - /* save shadow register */ - devpriv->ao_readback[chan] = data[i]; - + val = data[i]; + outb(val & 0xff, ioreg); + outb((val >> 8) & 0xff, ioreg + 1); + + /* + * Initiate transfer if not in simultaneaous xfer + * mode by reading one of the AO registers. + */ if (!devpriv->simultaneous_xfer_mode) - inb(LSB_PORT(chan)); + inb(ioreg); } + devpriv->ao_readback[chan] = val; - /* return the number of samples written */ - return i; + return insn->n; } -/* AO subdevices should have a read insn as well as a write insn. - - Usually this means copying a value stored in devpriv->ao_readback. - However, since this driver supports simultaneous xfer then sometimes - this function actually accomplishes work. - - Simultaneaous xfer mode is accomplished by loading ALL the values - you want for AO in all the channels, then READing off one of the AO - registers to initiate the instantaneous simultaneous update of all - DAC outputs, which makes all AO channels update simultaneously. - This is useful for some control applications, I would imagine. -*/ -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmda12_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcmda12_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); - for (i = 0; i < insn->n; i++) { - if (devpriv->simultaneous_xfer_mode) - inb(LSB_PORT(chan)); - /* read back shadow register */ + /* + * Initiate simultaneaous xfer mode by reading one of the + * AO registers. All analog outputs will then be updated. + */ + if (devpriv->simultaneous_xfer_mode) + inb(dev->iobase); + + for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; - } - return i; + return insn->n; +} + +static void pcmda12_ao_reset(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + int i; + + for (i = 0; i < s->n_chan; ++i) { + outb(0, dev->iobase + (i * 2)); + outb(0, dev->iobase + (i * 2) + 1); + } + /* Initiate transfer by reading one of the AO registers. */ + inb(dev->iobase); } static int pcmda12_attach(struct comedi_device *dev, @@ -156,7 +134,7 @@ static int pcmda12_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], IOSIZE); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; @@ -172,18 +150,17 @@ static int pcmda12_attach(struct comedi_device *dev, return ret; s = &dev->subdevices[0]; - s->private = NULL; - s->maxdata = (0x1 << BITS) - 1; - s->range_table = &pcmda12_ranges; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = CHANS; - s->insn_write = &ao_winsn; - s->insn_read = &ao_rinsn; - - zero_chans(dev); /* clear out all the registers, basically */ - - return 1; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->range_table = &pcmda12_ranges; + s->insn_write = pcmda12_ao_insn_write; + s->insn_read = pcmda12_ao_insn_read; + + pcmda12_ao_reset(dev, s); + + return 0; } static struct comedi_driver pcmda12_driver = { diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 5a236cd5b33d..9f76b1f59983 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: pcmmio diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 0c98e26bbba1..c43b6334ceae 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -1,79 +1,77 @@ /* - comedi/drivers/pcmuio.c - Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * pcmuio.c + * Comedi driver for Winsystems PC-104 based 48/96-channel DIO boards. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* -Driver: pcmuio -Description: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems. -Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96) -Author: Calin Culianu <calin@ajvar.org> -Updated: Fri, 13 Jan 2006 12:01:01 -0500 -Status: works - -A driver for the relatively straightforward-to-program PCM-UIO48A and -PCM-UIO96A boards from Winsystems. These boards use either one or two -(in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). -This chip is interesting in that each I/O line is individually -programmable for INPUT or OUTPUT (thus comedi_dio_config can be done -on a per-channel basis). Also, each chip supports edge-triggered -interrupts for the first 24 I/O lines. Of course, since the -96-channel version of the board has two ASICs, it can detect polarity -changes on up to 48 I/O lines. Since this is essentially an (non-PnP) -ISA board, I/O Address and IRQ selection are done through jumpers on -the board. You need to pass that information to this driver as the -first and second comedi_config option, respectively. Note that the -48-channel version uses 16 bytes of IO memory and the 96-channel -version uses 32-bytes (in case you are worried about conflicts). The -48-channel board is split into two 24-channel comedi subdevices. -The 96-channel board is split into 4 24-channel DIO subdevices. - -Note that IRQ support has been added, but it is untested. - -To use edge-detection IRQ support, pass the IRQs of both ASICS -(for the 96 channel version) or just 1 ASIC (for 48-channel version). -Then, use use comedi_commands with TRIG_NOW. -Your callback will be called each time an edge is triggered, and the data -values will be two sample_t's, which should be concatenated to form one -32-bit unsigned int. This value is the mask of channels that had -edges detected from your channel list. Note that the bits positions -in the mask correspond to positions in your chanlist when you specified -the command and *not* channel id's! - -To set the polarity of the edge-detection interrupts pass a nonzero value for -either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both -CR_RANGE and CR_AREF if you want edge-down polarity. - -In the 48-channel version: - -On subdev 0, the first 24 channels channels are edge-detect channels. - -In the 96-channel board you have the collowing channels that can do edge detection: - -subdev 0, channels 0-24 (first 24 channels of 1st ASIC) -subdev 2, channels 0-24 (first 24 channels of 2nd ASIC) - -Configuration Options: - [0] - I/O port base address - [1] - IRQ (for first ASIC, or first 24 channels) - [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!) -*/ + * Driver: pcmuio + * Description: Winsystems PC-104 based 48/96-channel DIO boards. + * Devices: (Winsystems) PCM-UIO48A [pcmuio48] + * (Winsystems) PCM-UIO96A [pcmuio96] + * Author: Calin Culianu <calin@ajvar.org> + * Updated: Fri, 13 Jan 2006 12:01:01 -0500 + * Status: works + * + * A driver for the relatively straightforward-to-program PCM-UIO48A and + * PCM-UIO96A boards from Winsystems. These boards use either one or two + * (in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). This + * chip is interesting in that each I/O line is individually programmable + * for INPUT or OUTPUT (thus comedi_dio_config can be done on a per-channel + * basis). Also, each chip supports edge-triggered interrupts for the first + * 24 I/O lines. Of course, since the 96-channel version of the board has + * two ASICs, it can detect polarity changes on up to 48 I/O lines. Since + * this is essentially an (non-PnP) ISA board, I/O Address and IRQ selection + * are done through jumpers on the board. You need to pass that information + * to this driver as the first and second comedi_config option, respectively. + * Note that the 48-channel version uses 16 bytes of IO memory and the 96- + * channel version uses 32-bytes (in case you are worried about conflicts). + * The 48-channel board is split into two 24-channel comedi subdevices. The + * 96-channel board is split into 4 24-channel DIO subdevices. + * + * Note that IRQ support has been added, but it is untested. + * + * To use edge-detection IRQ support, pass the IRQs of both ASICS (for the + * 96 channel version) or just 1 ASIC (for 48-channel version). Then, use + * comedi_commands with TRIG_NOW. Your callback will be called each time an + * edge is triggered, and the data values will be two sample_t's, which + * should be concatenated to form one 32-bit unsigned int. This value is + * the mask of channels that had edges detected from your channel list. Note + * that the bits positions in the mask correspond to positions in your + * chanlist when you specified the command and *not* channel id's! + * + * To set the polarity of the edge-detection interrupts pass a nonzero value + * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for + * both CR_RANGE and CR_AREF if you want edge-down polarity. + * + * In the 48-channel version: + * + * On subdev 0, the first 24 channels channels are edge-detect channels. + * + * In the 96-channel board you have the following channels that can do edge + * detection: + * + * subdev 0, channels 0-24 (first 24 channels of 1st ASIC) + * subdev 2, channels 0-24 (first 24 channels of 2nd ASIC) + * + * Configuration Options: + * [0] - I/O port base address + * [1] - IRQ (for first ASIC, or first 24 channels) + * [2] - IRQ (for second ASIC, pcmuio96 only - IRQ for chans 48-72 + * can be the same as first irq!) + */ #include <linux/interrupt.h> #include <linux/slab.h> @@ -82,94 +80,62 @@ Configuration Options: #include "comedi_fc.h" -#define CHANS_PER_PORT 8 -#define PORTS_PER_ASIC 6 -#define INTR_PORTS_PER_ASIC 3 -#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */ -#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT) -#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC) -#define INTR_CHANS_PER_ASIC 24 -#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) -#define MAX_DIO_CHANS (PORTS_PER_ASIC*2*CHANS_PER_PORT) -#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) -#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) -/* IO Memory sizes */ -#define ASIC_IOSIZE (0x10) -#define PCMUIO48_IOSIZE ASIC_IOSIZE -#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2) - -/* Some offsets - these are all in the 16byte IO memory offset from - the base address. Note that there is a paging scheme to swap out - offsets 0x8-0xA using the PAGELOCK register. See the table below. - - Register(s) Pages R/W? Description - -------------------------------------------------------------- - REG_PORTx All R/W Read/Write/Configure IO - REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int. - REG_PAGELOCK All WriteOnly Select a page - REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity - REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int. - REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints. - */ -#define REG_PORT0 0x0 -#define REG_PORT1 0x1 -#define REG_PORT2 0x2 -#define REG_PORT3 0x3 -#define REG_PORT4 0x4 -#define REG_PORT5 0x5 -#define REG_INT_PENDING 0x6 -#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page - and bits 0-5 are used to 'lock down' a particular - port above to make it readonly. */ -#define REG_POL0 0x8 -#define REG_POL1 0x9 -#define REG_POL2 0xA -#define REG_ENAB0 0x8 -#define REG_ENAB1 0x9 -#define REG_ENAB2 0xA -#define REG_INT_ID0 0x8 -#define REG_INT_ID1 0x9 -#define REG_INT_ID2 0xA - -#define NUM_PAGED_REGS 3 -#define NUM_PAGES 4 -#define FIRST_PAGED_REG 0x8 -#define REG_PAGE_BITOFFSET 6 -#define REG_LOCK_BITOFFSET 0 -#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1)) -#define REG_LOCK_MASK ~(REG_PAGE_MASK) -#define PAGE_POL 1 -#define PAGE_ENAB 2 -#define PAGE_INT_ID 3 - /* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. + * Register I/O map + * + * Offset Page 0 Page 1 Page 2 Page 3 + * ------ ----------- ----------- ----------- ----------- + * 0x00 Port 0 I/O Port 0 I/O Port 0 I/O Port 0 I/O + * 0x01 Port 1 I/O Port 1 I/O Port 1 I/O Port 1 I/O + * 0x02 Port 2 I/O Port 2 I/O Port 2 I/O Port 2 I/O + * 0x03 Port 3 I/O Port 3 I/O Port 3 I/O Port 3 I/O + * 0x04 Port 4 I/O Port 4 I/O Port 4 I/O Port 4 I/O + * 0x05 Port 5 I/O Port 5 I/O Port 5 I/O Port 5 I/O + * 0x06 INT_PENDING INT_PENDING INT_PENDING INT_PENDING + * 0x07 Page/Lock Page/Lock Page/Lock Page/Lock + * 0x08 N/A POL_0 ENAB_0 INT_ID0 + * 0x09 N/A POL_1 ENAB_1 INT_ID1 + * 0x0a N/A POL_2 ENAB_2 INT_ID2 */ +#define PCMUIO_PORT_REG(x) (0x00 + (x)) +#define PCMUIO_INT_PENDING_REG 0x06 +#define PCMUIO_PAGE_LOCK_REG 0x07 +#define PCMUIO_LOCK_PORT(x) ((1 << (x)) & 0x3f) +#define PCMUIO_PAGE(x) (((x) & 0x3) << 6) +#define PCMUIO_PAGE_MASK PCMUIO_PAGE(3) +#define PCMUIO_PAGE_POL 1 +#define PCMUIO_PAGE_ENAB 2 +#define PCMUIO_PAGE_INT_ID 3 +#define PCMUIO_PAGE_REG(x) (0x08 + (x)) + +#define PCMUIO_ASIC_IOSIZE 0x10 +#define PCMUIO_MAX_ASICS 2 + struct pcmuio_board { const char *name; const int num_asics; - const int num_channels_per_port; - const int num_ports; }; -/* this structure is for data unique to this subdevice. */ -struct pcmuio_subdev_private { - /* mapping of halfwords (bytes) in port/chanarray to iobase */ - unsigned long iobases[PORTS_PER_SUBDEV]; +static const struct pcmuio_board pcmuio_boards[] = { + { + .name = "pcmuio48", + .num_asics = 1, + }, { + .name = "pcmuio96", + .num_asics = 2, + }, +}; +struct pcmuio_subdev_private { /* The below is only used for intr subdevices */ struct { - int asic; /* if non-negative, this subdev has an interrupt asic */ - int first_chan; /* if nonnegative, the first channel id for - interrupts. */ - int num_asic_chans; /* the number of asic channels in this subdev - that have interrutps */ - int asic_chan; /* if nonnegative, the first channel id with - respect to the asic that has interrupts */ - int enabled_mask; /* subdev-relative channel mask for channels - we are interested in */ + /* if non-negative, this subdev has an interrupt asic */ + int asic; + /* + * subdev-relative channel mask for channels + * we are interested in + */ + int enabled_mask; int active; int stop_count; int continuous; @@ -177,160 +143,112 @@ struct pcmuio_subdev_private { } intr; }; -/* this structure is for data unique to this hardware driver. If - several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device struct. */ struct pcmuio_private { struct { - unsigned char pagelock; /* current page and lock */ - unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */ - unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */ - int num; - unsigned long iobase; unsigned int irq; spinlock_t spinlock; - } asics[MAX_ASICS]; + } asics[PCMUIO_MAX_ASICS]; struct pcmuio_subdev_private *sprivs; }; -#define subpriv ((struct pcmuio_subdev_private *)s->private) +static void pcmuio_write(struct comedi_device *dev, unsigned int val, + int asic, int page, int port) +{ + unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); + + if (page == 0) { + /* Port registers are valid for any page */ + outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0)); + outb((val >> 8) & 0xff, iobase + PCMUIO_PORT_REG(port + 1)); + outb((val >> 16) & 0xff, iobase + PCMUIO_PORT_REG(port + 2)); + } else { + outb(PCMUIO_PAGE(page), iobase + PCMUIO_PAGE_LOCK_REG); + outb(val & 0xff, iobase + PCMUIO_PAGE_REG(0)); + outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1)); + outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2)); + } +} + +static unsigned int pcmuio_read(struct comedi_device *dev, + int asic, int page, int port) +{ + unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); + unsigned int val; + + if (page == 0) { + /* Port registers are valid for any page */ + val = inb(iobase + PCMUIO_PORT_REG(port + 0)); + val |= (inb(iobase + PCMUIO_PORT_REG(port + 1)) << 8); + val |= (inb(iobase + PCMUIO_PORT_REG(port + 2)) << 16); + } else { + outb(PCMUIO_PAGE(page), iobase + PCMUIO_PAGE_LOCK_REG); + val = inb(iobase + PCMUIO_PAGE_REG(0)); + val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8); + val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16); + } -/* DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ + return val; +} + +/* + * Each channel can be individually programmed for input or output. + * Writing a '0' to a channel causes the corresponding output pin + * to go to a high-z state (pulled high by an external 10K resistor). + * This allows it to be used as an input. When used in the input mode, + * a read reflects the inverted state of the I/O pin, such that a + * high on the pin will read as a '0' in the register. Writing a '1' + * to a bit position causes the pin to sink current (up to 12mA), + * effectively pulling it low. + */ static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int byte_no; - - /* NOTE: - reading a 0 means this channel was high - writine a 0 sets the channel high - reading a 1 means this channel was low - writing a 1 means set this channel low - - Therefore everything is always inverted. */ - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - dev_dbg(dev->class_dev, "write mask: %08x data: %08x\n", data[0], - data[1]); -#endif - - s->state = 0; - - for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { - /* address of 8-bit port */ - unsigned long ioaddr = subpriv->iobases[byte_no], - /* bit offset of port in 32-bit doubleword */ - offset = byte_no * 8; - /* this 8-bit port's data */ - unsigned char byte = 0, - /* The write mask for this port (if any) */ - write_mask_byte = (data[0] >> offset) & 0xff, - /* The data byte for this port */ - data_byte = (data[1] >> offset) & 0xff; - - byte = inb(ioaddr); /* read all 8-bits for this port */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk - ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", - byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, - offset, ioaddr, (unsigned)byte); -#endif - - if (write_mask_byte) { - /* this byte has some write_bits -- so set the output lines */ - byte &= ~write_mask_byte; /* clear bits for write mask */ - byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */ - /* Write out the new digital output state */ - outb(byte, ioaddr); - } -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - dev_dbg(dev->class_dev, "data_out_byte %02x\n", (unsigned)byte); -#endif - /* save the digital input lines for this byte.. */ - s->state |= ((unsigned int)byte) << offset; - } + unsigned int mask = data[0] & s->io_bits; /* outputs only */ + unsigned int bits = data[1]; + int asic = s->index / 2; + int port = (s->index % 2) ? 3 : 0; + unsigned int val; + + /* get inverted state of the channels from the port */ + val = pcmuio_read(dev, asic, 0, port); + + /* get the true state of the channels */ + s->state = val ^ ((0x1 << s->n_chan) - 1); - /* now return the DIO lines to data[1] - note they came inverted! */ - data[1] = ~s->state; + if (mask) { + s->state &= ~mask; + s->state |= (mask & bits); -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - dev_dbg(dev->class_dev, "s->state %08x data_out %08x\n", s->state, - data[1]); -#endif + /* invert the state and update the channels */ + val = s->state ^ ((0x1 << s->n_chan) - 1); + pcmuio_write(dev, val, asic, 0, port); + } + + data[1] = s->state; return insn->n; } -/* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = - chan % 8; - unsigned long ioaddr; - unsigned char byte; - - /* Compute ioaddr for this channel */ - ioaddr = subpriv->iobases[byte_no]; - - /* NOTE: - writing a 0 an IO channel's bit sets the channel to INPUT - and pulls the line high as well - - writing a 1 to an IO channel's bit pulls the line low - - All channels are implicitly always in OUTPUT mode -- but when - they are high they can be considered to be in INPUT mode.. - - Thus, we only force channels low if the config request was INPUT, - otherwise we do nothing to the hardware. */ + unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); + int asic = s->index / 2; + int port = (s->index % 2) ? 3 : 0; switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: - /* save to io_bits -- don't actually do anything since - all input channels are also output channels... */ - s->io_bits |= 1 << chan; + s->io_bits |= chan_mask; break; case INSN_CONFIG_DIO_INPUT: - /* write a 0 to the actual register representing the channel - to set it to 'input'. 0 means "float high". */ - byte = inb(ioaddr); - byte &= ~(1 << bit_no); - /**< set input channel to '0' */ - - /* write out byte -- this is the only time we actually affect the - hardware as all channels are implicitly output -- but input - channels are set to float-high */ - outb(byte, ioaddr); - - /* save to io_bits */ - s->io_bits &= ~(1 << chan); + s->io_bits &= ~chan_mask; + pcmuio_write(dev, s->io_bits, asic, 0, port); break; - case INSN_CONFIG_DIO_QUERY: - /* retrieve from shadow register */ - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; + data[1] = (s->io_bits & chan_mask) ? COMEDI_OUTPUT : COMEDI_INPUT; break; - default: return -EINVAL; break; @@ -339,263 +257,154 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev, return insn->n; } -static void switch_page(struct comedi_device *dev, int asic, int page) +static void pcmuio_reset(struct comedi_device *dev) { const struct pcmuio_board *board = comedi_board(dev); - struct pcmuio_private *devpriv = dev->private; - - if (asic < 0 || asic >= board->num_asics) - return; /* paranoia */ - if (page < 0 || page >= NUM_PAGES) - return; /* more paranoia */ + int asic; - devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; - devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; + for (asic = 0; asic < board->num_asics; ++asic) { + /* first, clear all the DIO port bits */ + pcmuio_write(dev, 0, asic, 0, 0); + pcmuio_write(dev, 0, asic, 0, 3); - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); + /* Next, clear all the paged registers for each page */ + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_POL, 0); + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0); + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0); + } } -static void init_asics(struct comedi_device *dev) -{ /* sets up an - ASIC chip to defaults */ - const struct pcmuio_board *board = comedi_board(dev); +static void pcmuio_stop_intr(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcmuio_subdev_private *subpriv = s->private; int asic; - for (asic = 0; asic < board->num_asics; ++asic) { - int port, page; - unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE; + asic = subpriv->intr.asic; + if (asic < 0) + return; /* not an interrupt subdev */ - switch_page(dev, asic, 0); /* switch back to page 0 */ + subpriv->intr.enabled_mask = 0; + subpriv->intr.active = 0; + s->async->inttrig = NULL; - /* first, clear all the DIO port bits */ - for (port = 0; port < PORTS_PER_ASIC; ++port) - outb(0, baseaddr + REG_PORT0 + port); + /* disable all intrs for this subdev.. */ + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0); +} - /* Next, clear all the paged registers for each page */ - for (page = 1; page < NUM_PAGES; ++page) { - int reg; - /* now clear all the paged registers */ - switch_page(dev, asic, page); - for (reg = FIRST_PAGED_REG; - reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg) - outb(0, baseaddr + reg); - } +static void pcmuio_handle_intr_subdev(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned triggered) +{ + struct pcmuio_subdev_private *subpriv = s->private; + unsigned int len = s->async->cmd.chanlist_len; + unsigned oldevents = s->async->events; + unsigned int val = 0; + unsigned long flags; + unsigned mytrig; + unsigned int i; - /* DEBUG set rising edge interrupts on port0 of both asics */ - /*switch_page(dev, asic, PAGE_POL); - outb(0xff, baseaddr + REG_POL0); - switch_page(dev, asic, PAGE_ENAB); - outb(0xff, baseaddr + REG_ENAB0); */ - /* END DEBUG */ + spin_lock_irqsave(&subpriv->intr.spinlock, flags); - switch_page(dev, asic, 0); /* switch back to default page 0 */ + if (!subpriv->intr.active) + goto done; + mytrig = triggered; + mytrig &= ((0x1 << s->n_chan) - 1); + + if (!(mytrig & subpriv->intr.enabled_mask)) + goto done; + + for (i = 0; i < len; i++) { + unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]); + if (mytrig & (1U << chan)) + val |= (1U << i); } -} -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port) -{ - const struct pcmuio_board *board = comedi_board(dev); - struct pcmuio_private *devpriv = dev->private; + /* Write the scan to the buffer. */ + if (comedi_buf_put(s->async, ((short *)&val)[0]) && + comedi_buf_put(s->async, ((short *)&val)[1])) { + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + } else { + /* Overflow! Stop acquisition!! */ + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmuio_stop_intr(dev, s); + } - if (asic < 0 || asic >= board->num_asics) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ + /* Check for end of acquisition. */ + if (!subpriv->intr.continuous) { + /* stop_src == TRIG_COUNT */ + if (subpriv->intr.stop_count > 0) { + subpriv->intr.stop_count--; + if (subpriv->intr.stop_count == 0) { + s->async->events |= COMEDI_CB_EOA; + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmuio_stop_intr(dev, s); + } + } + } + +done: + spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); - devpriv->asics[asic].pagelock |= 0x1 << port; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); + if (oldevents != s->async->events) + comedi_event(dev, s); } -static void unlock_port(struct comedi_device *dev, int asic, int port) +static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) { - const struct pcmuio_board *board = comedi_board(dev); struct pcmuio_private *devpriv = dev->private; + struct pcmuio_subdev_private *subpriv; + unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); + unsigned int triggered = 0; + int got1 = 0; + unsigned long flags; + unsigned char int_pend; + int i; - if (asic < 0 || asic >= board->num_asics) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ - devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); -} -#endif /* notused */ + spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags); -static void pcmuio_stop_intr(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - int nports, firstport, asic, port; - struct pcmuio_private *devpriv = dev->private; + int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07; + if (int_pend) { + triggered = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0); + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0); - asic = subpriv->intr.asic; - if (asic < 0) - return; /* not an interrupt subdev */ + ++got1; + } - subpriv->intr.enabled_mask = 0; - subpriv->intr.active = 0; - s->async->inttrig = NULL; - nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - /* disable all intrs for this subdev.. */ - outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); + spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags); + + if (triggered) { + struct comedi_subdevice *s; + /* TODO here: dispatch io lines to subdevs with commands.. */ + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + subpriv = s->private; + if (subpriv->intr.asic == asic) { + /* + * This is an interrupt subdev, and it + * matches this asic! + */ + pcmuio_handle_intr_subdev(dev, s, + triggered); + } + } } + return got1; } -static irqreturn_t interrupt_pcmuio(int irq, void *d) +static irqreturn_t pcmuio_interrupt(int irq, void *d) { - int asic, got1 = 0; - struct comedi_device *dev = (struct comedi_device *)d; + struct comedi_device *dev = d; struct pcmuio_private *devpriv = dev->private; - int i; + int got1 = 0; + int asic; - for (asic = 0; asic < MAX_ASICS; ++asic) { + for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic) { if (irq == devpriv->asics[asic].irq) { - unsigned long flags; - unsigned triggered = 0; - unsigned long iobase = devpriv->asics[asic].iobase; /* it is an interrupt for ASIC #asic */ - unsigned char int_pend; - - spin_lock_irqsave(&devpriv->asics[asic].spinlock, - flags); - - int_pend = inb(iobase + REG_INT_PENDING) & 0x07; - - if (int_pend) { - int port; - for (port = 0; port < INTR_PORTS_PER_ASIC; - ++port) { - if (int_pend & (0x1 << port)) { - unsigned char - io_lines_with_edges = 0; - switch_page(dev, asic, - PAGE_INT_ID); - io_lines_with_edges = - inb(iobase + - REG_INT_ID0 + port); - - if (io_lines_with_edges) - /* clear pending interrupt */ - outb(0, iobase + - REG_INT_ID0 + - port); - - triggered |= - io_lines_with_edges << - port * 8; - } - } - - ++got1; - } - - spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, - flags); - - if (triggered) { - struct comedi_subdevice *s; - /* TODO here: dispatch io lines to subdevs with commands.. */ - printk - ("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", - irq, asic, triggered); - for (i = 0; i < dev->n_subdevices; i++) { - s = &dev->subdevices[i]; - if (subpriv->intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */ - unsigned long flags; - unsigned oldevents; - - spin_lock_irqsave(&subpriv-> - intr.spinlock, - flags); - - oldevents = s->async->events; - - if (subpriv->intr.active) { - unsigned mytrig = - ((triggered >> - subpriv->intr.asic_chan) - & - ((0x1 << subpriv-> - intr. - num_asic_chans) - - 1)) << subpriv-> - intr.first_chan; - if (mytrig & - subpriv->intr.enabled_mask) - { - unsigned int val - = 0; - unsigned int n, - ch, len; - - len = - s-> - async->cmd.chanlist_len; - for (n = 0; - n < len; - n++) { - ch = CR_CHAN(s->async->cmd.chanlist[n]); - if (mytrig & (1U << ch)) { - val |= (1U << n); - } - } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *)&val)[0]) - && - comedi_buf_put - (s->async, - ((short *) - &val)[1])) - { - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - } else { - /* Overflow! Stop acquisition!! */ - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmuio_stop_intr - (dev, - s); - } - - /* Check for end of acquisition. */ - if (!subpriv->intr.continuous) { - /* stop_src == TRIG_COUNT */ - if (subpriv->intr.stop_count > 0) { - subpriv->intr.stop_count--; - if (subpriv->intr.stop_count == 0) { - s->async->events |= COMEDI_CB_EOA; - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmuio_stop_intr - (dev, - s); - } - } - } - } - } - - spin_unlock_irqrestore - (&subpriv->intr.spinlock, - flags); - - if (oldevents != - s->async->events) { - comedi_event(dev, s); - } - - } - - } - } - + if (pcmuio_handle_asic_interrupt(dev, asic)) + got1++; } } if (!got1) @@ -606,7 +415,7 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d) static int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pcmuio_private *devpriv = dev->private; + struct pcmuio_subdev_private *subpriv = s->private; if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) { /* An empty acquisition! */ @@ -615,7 +424,7 @@ static int pcmuio_start_intr(struct comedi_device *dev, return 1; } else { unsigned bits = 0, pol_bits = 0, n; - int nports, firstport, asic, port; + int asic; struct comedi_cmd *cmd = &s->async->cmd; asic = subpriv->intr.asic; @@ -624,8 +433,6 @@ static int pcmuio_start_intr(struct comedi_device *dev, subdev */ subpriv->intr.enabled_mask = 0; subpriv->intr.active = 1; - nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; if (cmd->chanlist) { for (n = 0; n < cmd->chanlist_len; n++) { bits |= (1U << CR_CHAN(cmd->chanlist[n])); @@ -635,31 +442,19 @@ static int pcmuio_start_intr(struct comedi_device *dev, << CR_CHAN(cmd->chanlist[n]); } } - bits &= ((0x1 << subpriv->intr.num_asic_chans) - - 1) << subpriv->intr.first_chan; + bits &= ((0x1 << s->n_chan) - 1); subpriv->intr.enabled_mask = bits; - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - unsigned enab = - bits >> (subpriv->intr.first_chan + (port - - firstport) * - 8) & 0xff, pol = - pol_bits >> (subpriv->intr.first_chan + - (port - firstport) * 8) & 0xff; - /* set enab intrs for this subdev.. */ - outb(enab, - devpriv->asics[asic].iobase + REG_ENAB0 + port); - switch_page(dev, asic, PAGE_POL); - outb(pol, - devpriv->asics[asic].iobase + REG_ENAB0 + port); - } + /* set pol and enab intrs for this subdev.. */ + pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0); + pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0); } return 0; } static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmuio_subdev_private *subpriv = s->private; unsigned long flags; spin_lock_irqsave(&subpriv->intr.spinlock, flags); @@ -677,6 +472,7 @@ static int pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { + struct pcmuio_subdev_private *subpriv = s->private; unsigned long flags; int event = 0; @@ -701,6 +497,7 @@ pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, */ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmuio_subdev_private *subpriv = s->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; @@ -797,17 +594,18 @@ static int pcmuio_cmdtest(struct comedi_device *dev, static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcmuio_board *board = comedi_board(dev); - struct pcmuio_private *devpriv; struct comedi_subdevice *s; - int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0; - unsigned int irq[MAX_ASICS]; + struct pcmuio_private *devpriv; + struct pcmuio_subdev_private *subpriv; + int sdev_no, n_subdevs, asic; + unsigned int irq[PCMUIO_MAX_ASICS]; int ret; irq[0] = it->options[1]; irq[1] = it->options[2]; ret = comedi_request_region(dev, it->options[0], - board->num_asics * ASIC_IOSIZE); + board->num_asics * PCMUIO_ASIC_IOSIZE); if (ret) return ret; @@ -816,20 +614,11 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) return -ENOMEM; dev->private = devpriv; - for (asic = 0; asic < MAX_ASICS; ++asic) { - devpriv->asics[asic].num = asic; - devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE; - devpriv->asics[asic].irq = 0; /* this gets actually set at the end of - this function when we - request_irqs */ + for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic) spin_lock_init(&devpriv->asics[asic].spinlock); - } - chans_left = CHANS_PER_ASIC * board->num_asics; - n_subdevs = CALC_N_SUBDEVS(chans_left); - devpriv->sprivs = kcalloc(n_subdevs, - sizeof(struct pcmuio_subdev_private), - GFP_KERNEL); + n_subdevs = board->num_asics * 2; + devpriv->sprivs = kcalloc(n_subdevs, sizeof(*subpriv), GFP_KERNEL); if (!devpriv->sprivs) return -ENOMEM; @@ -837,74 +626,40 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - port = 0; - asic = 0; for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { - int byte_no; - s = &dev->subdevices[sdev_no]; - s->private = &devpriv->sprivs[sdev_no]; + subpriv = &devpriv->sprivs[sdev_no]; + s->private = subpriv; s->maxdata = 1; s->range_table = &range_digital; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->type = COMEDI_SUBD_DIO; s->insn_bits = pcmuio_dio_insn_bits; s->insn_config = pcmuio_dio_insn_config; - s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); - subpriv->intr.asic = -1; - subpriv->intr.first_chan = -1; - subpriv->intr.asic_chan = -1; - subpriv->intr.num_asic_chans = -1; - subpriv->intr.active = 0; - s->len_chanlist = 1; - - /* save the ioport address for each 'port' of 8 channels in the - subdevice */ - for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { - if (port >= PORTS_PER_ASIC) { - port = 0; - ++asic; - thisasic_chanct = 0; - } - subpriv->iobases[byte_no] = - devpriv->asics[asic].iobase + port; - - if (thisasic_chanct < - CHANS_PER_PORT * INTR_PORTS_PER_ASIC - && subpriv->intr.asic < 0) { - /* this is an interrupt subdevice, so setup the struct */ - subpriv->intr.asic = asic; - subpriv->intr.active = 0; - subpriv->intr.stop_count = 0; - subpriv->intr.first_chan = byte_no * 8; - subpriv->intr.asic_chan = thisasic_chanct; - subpriv->intr.num_asic_chans = - s->n_chan - subpriv->intr.first_chan; - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = pcmuio_cancel; - s->do_cmd = pcmuio_cmd; - s->do_cmdtest = pcmuio_cmdtest; - s->len_chanlist = subpriv->intr.num_asic_chans; - } - thisasic_chanct += CHANS_PER_PORT; + s->n_chan = 24; + + /* subdevices 0 and 2 suppport interrupts */ + if ((sdev_no % 2) == 0) { + /* setup the interrupt subdevice */ + subpriv->intr.asic = sdev_no / 2; + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->cancel = pcmuio_cancel; + s->do_cmd = pcmuio_cmd; + s->do_cmdtest = pcmuio_cmdtest; + s->len_chanlist = s->n_chan; + } else { + subpriv->intr.asic = -1; + s->len_chanlist = 1; } spin_lock_init(&subpriv->intr.spinlock); - - chans_left -= s->n_chan; - - if (!chans_left) { - asic = 0; /* reset the asic to our first asic, to do intr subdevs */ - port = 0; - } - } - init_asics(dev); /* clear out all the registers, basically */ + pcmuio_reset(dev); - for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { + for (asic = 0; irq[0] && asic < PCMUIO_MAX_ASICS; ++asic) { if (irq[asic] - && request_irq(irq[asic], interrupt_pcmuio, + && request_irq(irq[asic], pcmuio_interrupt, IRQF_SHARED, board->name, dev)) { int i; /* unroll the allocated irqs.. */ @@ -917,17 +672,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->asics[asic].irq = irq[asic]; } - if (irq[0]) { - dev_dbg(dev->class_dev, "irq: %u\n", irq[0]); - if (irq[1] && board->num_asics == 2) - dev_dbg(dev->class_dev, "second ASIC irq: %u\n", - irq[1]); - } else { - dev_dbg(dev->class_dev, "(IRQ mode disabled)\n"); - } - - - return 1; + return 0; } static void pcmuio_detach(struct comedi_device *dev) @@ -935,7 +680,7 @@ static void pcmuio_detach(struct comedi_device *dev) struct pcmuio_private *devpriv = dev->private; int i; - for (i = 0; i < MAX_ASICS; ++i) { + for (i = 0; i < PCMUIO_MAX_ASICS; ++i) { if (devpriv->asics[i].irq) free_irq(devpriv->asics[i].irq, dev); } @@ -944,18 +689,6 @@ static void pcmuio_detach(struct comedi_device *dev) comedi_legacy_detach(dev); } -static const struct pcmuio_board pcmuio_boards[] = { - { - .name = "pcmuio48", - .num_asics = 1, - .num_ports = 6, - }, { - .name = "pcmuio96", - .num_asics = 2, - .num_ports = 12, - }, -}; - static struct comedi_driver pcmuio_driver = { .driver_name = "pcmuio", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/plx9052.h b/drivers/staging/comedi/drivers/plx9052.h index ff76fbb4b3ef..fbcf25069807 100644 --- a/drivers/staging/comedi/drivers/plx9052.h +++ b/drivers/staging/comedi/drivers/plx9052.h @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _PLX9052_H_ diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c index b55a16baeb14..005fbefae295 100644 --- a/drivers/staging/comedi/drivers/poc.c +++ b/drivers/staging/comedi/drivers/poc.c @@ -13,25 +13,18 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: poc Description: Generic driver for very simple devices Author: ds -Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733), - PCL-734 (pcl734) +Devices: [Keithley Metrabyte] DAC-02 (dac02) Updated: Sat, 16 Mar 2002 17:34:48 -0800 Status: unknown This driver is indended to support very simple ISA-based devices, including: dac02 - Keithley DAC-02 analog output board - pcl733 - Advantech PCL-733 - pcl734 - Advantech PCL-734 Configuration options: [0] - I/O port base @@ -101,39 +94,6 @@ static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, return 1; } -static int pcl733_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[1] = inb(dev->iobase + 0); - data[1] |= (inb(dev->iobase + 1) << 8); - data[1] |= (inb(dev->iobase + 2) << 16); - data[1] |= (inb(dev->iobase + 3) << 24); - - return insn->n; -} - -static int pcl734_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - if ((data[0] >> 0) & 0xff) - outb((s->state >> 0) & 0xff, dev->iobase + 0); - if ((data[0] >> 8) & 0xff) - outb((s->state >> 8) & 0xff, dev->iobase + 1); - if ((data[0] >> 16) & 0xff) - outb((s->state >> 16) & 0xff, dev->iobase + 2); - if ((data[0] >> 24) & 0xff) - outb((s->state >> 24) & 0xff, dev->iobase + 3); - } - data[1] = s->state; - - return insn->n; -} - static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct boarddef_struct *board = comedi_board(dev); @@ -180,22 +140,6 @@ static const struct boarddef_struct boards[] = { .winsn = dac02_ao_winsn, .rinsn = readback_insn, .range = &range_unknown, - }, { - .name = "pcl733", - .iosize = 4, - .type = COMEDI_SUBD_DI, - .n_chan = 32, - .n_bits = 1, - .insnbits = pcl733_insn_bits, - .range = &range_digital, - }, { - .name = "pcl734", - .iosize = 4, - .type = COMEDI_SUBD_DO, - .n_chan = 32, - .n_bits = 1, - .insnbits = pcl734_insn_bits, - .range = &range_digital, }, }; diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 30a17284fac9..9b93a1fc4a59 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index f4163fd35a00..f698c7fc5726 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index 46dbbe6cdd76..9e7445055482 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: rti802 diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index d240ce87bd68..e1587e58a732 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: s526 diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 0cf4b3d1279a..48c4b70b736a 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h index 99cd57b092ea..d2756b83b62d 100644 --- a/drivers/staging/comedi/drivers/s626.h +++ b/drivers/staging/comedi/drivers/s626.h @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index 8900086374db..b4f5fe35b0fa 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index dbc8c54d6da7..06aee302bbc2 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: skel diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index a76df092a57b..45c661cbdbb9 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -15,11 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ssv_dnp diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c index 0c243477cbe5..c9201d821fbc 100644 --- a/drivers/staging/comedi/drivers/unioxx5.c +++ b/drivers/staging/comedi/drivers/unioxx5.c @@ -18,10 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * * ***************************************************************************/ /* @@ -375,15 +371,13 @@ static int __unioxx5_subdev_init(struct comedi_device *dev, int i, to, ndef_flag = 0; int ret; - usp = kzalloc(sizeof(*usp), GFP_KERNEL); - if (usp == NULL) + usp = comedi_alloc_spriv(s, sizeof(*usp)); + if (!usp) return -ENOMEM; ret = __comedi_request_region(dev, iobase, UNIOXX5_SIZE); - if (ret) { - kfree(usp); + if (ret) return ret; - } usp->usp_iobase = iobase; /* defining modules types */ @@ -417,7 +411,6 @@ static int __unioxx5_subdev_init(struct comedi_device *dev, /* initial subdevice for digital or analog i/o */ s->type = COMEDI_SUBD_DIO; - s->private = usp; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = UNIOXX5_NUM_OF_CHANS; s->maxdata = 0xFFF; @@ -478,15 +471,15 @@ static int unioxx5_attach(struct comedi_device *dev, static void unioxx5_detach(struct comedi_device *dev) { + struct comedi_subdevice *s; + struct unioxx5_subd_priv *spriv; int i; - struct comedi_subdevice *subdev; - struct unioxx5_subd_priv *usp; for (i = 0; i < dev->n_subdevices; i++) { - subdev = &dev->subdevices[i]; - usp = subdev->private; - release_region(usp->usp_iobase, UNIOXX5_SIZE); - kfree(subdev->private); + s = &dev->subdevices[i]; + spriv = s->private; + if (spriv && spriv->usp_iobase) + release_region(spriv->usp_iobase, UNIOXX5_SIZE); } } diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 6f5da67e26cb..279e5bd493fa 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -11,11 +11,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: usbdux @@ -94,7 +89,6 @@ sampling rate. If you sample two channels you get 4kHz and so on. #include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> -#include <linux/firmware.h> #include "../comedidev.h" @@ -727,154 +721,82 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) } } -static int usbduxsub_start(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - uint8_t *local_transfer_buffer; - - local_transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to zero */ - *local_transfer_buffer = 0; - errcode = usb_control_msg(usbduxsub->usbdev, - /* create a pipe for a control transfer */ - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, - /* address of the transfer buffer */ - local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (start)\n"); - - kfree(local_transfer_buffer); - return errcode; -} - -static int usbduxsub_stop(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - uint8_t *local_transfer_buffer; - - local_transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to one */ - *local_transfer_buffer = 1; - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (stop)\n"); - - kfree(local_transfer_buffer); - return errcode; -} - -static int usbduxsub_upload(struct usbduxsub *usbduxsub, - uint8_t *local_transfer_buffer, - unsigned int start_addr, unsigned int len) -{ - int errcode; - - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* brequest, firmware */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* value */ - start_addr, - /* index */ - 0x0000, - /* our local safe buffer */ - local_transfer_buffer, - /* length */ - len, - /* timeout */ - BULK_TIMEOUT); - dev_dbg(&usbduxsub->interface->dev, "comedi_: result=%d\n", errcode); - if (errcode < 0) { - dev_err(&usbduxsub->interface->dev, "comedi_: upload failed\n"); - return errcode; - } - return 0; -} - #define FIRMWARE_MAX_LEN 0x2000 -static int firmware_upload(struct usbduxsub *usbduxsub, - const u8 *firmware_binary, int size_firmware) +static int usbdux_firmware_upload(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { + struct usbduxsub *usbduxsub = dev->private; + struct usb_device *usb = usbduxsub->usbdev; + uint8_t *buf; + uint8_t *tmp; int ret; - uint8_t *fw_buf; - if (!firmware_binary) + if (!data) return 0; - if (size_firmware > FIRMWARE_MAX_LEN) { + if (size > FIRMWARE_MAX_LEN) { dev_err(&usbduxsub->interface->dev, "usbdux firmware binary it too large for FX2.\n"); return -ENOMEM; } /* we generate a local buffer for the firmware */ - fw_buf = kmemdup(firmware_binary, size_firmware, GFP_KERNEL); - if (!fw_buf) { - dev_err(&usbduxsub->interface->dev, - "comedi_: mem alloc for firmware failed\n"); + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* we need a malloc'ed buffer for usb_control_msg() */ + tmp = kmalloc(1, GFP_KERNEL); + if (!tmp) { + kfree(buf); return -ENOMEM; } - ret = usbduxsub_stop(usbduxsub); + /* stop the current firmware on the device */ + *tmp = 1; /* 7f92 to one */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXSUB_CPUCS, 0x0000, + tmp, 1, + BULK_TIMEOUT); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: can not stop firmware\n"); - kfree(fw_buf); - return ret; + goto done; } - ret = usbduxsub_upload(usbduxsub, fw_buf, 0, size_firmware); + /* upload the new firmware to the device */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + 0, 0x0000, + buf, size, + BULK_TIMEOUT); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: firmware upload failed\n"); - kfree(fw_buf); - return ret; + goto done; } - ret = usbduxsub_start(usbduxsub); - if (ret < 0) { + + /* start the new firmware on the device */ + *tmp = 0; /* 7f92 to zero */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXSUB_CPUCS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) dev_err(&usbduxsub->interface->dev, "comedi_: can not start firmware\n"); - kfree(fw_buf); - return ret; - } - kfree(fw_buf); - return 0; + +done: + kfree(tmp); + kfree(buf); + return ret; } static int usbduxsub_submit_inurbs(struct usbduxsub *usbduxsub) @@ -2328,13 +2250,21 @@ static int usbdux_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct usb_interface *uinterf = comedi_to_usb_interface(dev); + struct usbduxsub *this_usbduxsub = usb_get_intfdata(uinterf); + struct usb_device *usb = usbduxsub->usbdev; int ret; - struct usbduxsub *this_usbduxsub; + + dev->private = this_usbduxsub; /* This is temporary... */ + ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, + usbdux_firmware_upload, 0); + if (ret < 0) { + dev->private = NULL; + return ret; + } dev->private = NULL; down(&start_stop_sem); - this_usbduxsub = usb_get_intfdata(uinterf); if (!this_usbduxsub || !this_usbduxsub->probed) { dev_err(dev->class_dev, "usbdux: error: auto_attach failed, not connected\n"); @@ -2369,35 +2299,6 @@ static struct comedi_driver usbdux_driver = { .detach = usbdux_detach, }; -static void usbdux_firmware_request_complete_handler(const struct firmware *fw, - void *context) -{ - struct usbduxsub *usbduxsub_tmp = context; - struct usb_interface *uinterf = usbduxsub_tmp->interface; - int ret; - - if (fw == NULL) { - dev_err(&uinterf->dev, - "Firmware complete handler without firmware!\n"); - return; - } - - /* - * we need to upload the firmware here because fw will be - * freed once we've left this function - */ - ret = firmware_upload(usbduxsub_tmp, fw->data, fw->size); - - if (ret) { - dev_err(&uinterf->dev, - "Could not upload firmware (err=%d)\n", ret); - goto out; - } - comedi_usb_auto_config(uinterf, &usbdux_driver, 0); - out: - release_firmware(fw); -} - static int usbdux_usb_probe(struct usb_interface *uinterf, const struct usb_device_id *id) { @@ -2405,7 +2306,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, struct device *dev = &uinterf->dev; int i; int index; - int ret; dev_dbg(dev, "comedi_: usbdux_: " "finding a free structure for the usb-device\n"); @@ -2622,23 +2522,7 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, usbduxsub[index].probed = 1; up(&start_stop_sem); - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, - FIRMWARE, - &udev->dev, - GFP_KERNEL, - usbduxsub + index, - usbdux_firmware_request_complete_handler); - - if (ret) { - dev_err(dev, "Could not load firmware (err=%d)\n", ret); - return ret; - } - - dev_info(dev, "comedi_: usbdux%d " - "has been successfully initialised.\n", index); - /* success */ - return 0; + return comedi_usb_auto_config(uinterf, &usbdux_driver, 0); } static void usbdux_usb_disconnect(struct usb_interface *intf) diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 7f95af33085d..27898c44e543 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -40,7 +36,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> -#include <linux/firmware.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -60,6 +55,7 @@ * constants for "firmware" upload and download */ #define FIRMWARE "usbduxfast_firmware.bin" +#define FIRMWARE_MAX_LEN 0x2000 #define USBDUXFASTSUB_FIRMWARE 0xA0 #define VENDOR_DIR_IN 0xC0 #define VENDOR_DIR_OUT 0x40 @@ -112,7 +108,7 @@ /* * size of the buffer for the dux commands in bytes */ -#define SIZEOFDUXBUFFER 256 +#define SIZEOFDUXBUF 256 /* * number of in-URBs which receive the data: min=5 @@ -120,16 +116,6 @@ #define NUMOFINBUFFERSHIGH 10 /* - * total number of usbduxfast devices - */ -#define NUMUSBDUXFAST 16 - -/* - * analogue in subdevice - */ -#define SUBDEV_AD 0 - -/* * min delay steps for more than one channel * basically when the mux gives up ;-) * @@ -161,143 +147,83 @@ static const struct comedi_lrange range_usbduxfast_ai_range = { * this is the structure which holds all the data of this driver * one sub device just now: A/D */ -struct usbduxfastsub_s { - int attached; /* is attached? */ - int probed; /* is it associated with a subdevice? */ - struct usb_device *usbdev; /* pointer to the usb-device */ - struct urb *urbIn; /* BULK-transfer handling: urb */ - int8_t *transfer_buffer; - int16_t *insnBuffer; /* input buffer for single insn */ - int ifnum; /* interface number */ - struct usb_interface *interface; /* interface structure */ - /* comedi device for the interrupt context */ - struct comedi_device *comedidev; +struct usbduxfast_private { + struct urb *urb; /* BULK-transfer handling: urb */ + uint8_t *duxbuf; + int8_t *inbuf; short int ai_cmd_running; /* asynchronous command is running */ short int ai_continous; /* continous acquisition */ long int ai_sample_count; /* number of samples to acquire */ - uint8_t *dux_commands; /* commands */ int ignore; /* counter which ignores the first buffers */ struct semaphore sem; }; /* - * The pointer to the private usb-data of the driver - * is also the private data for the comedi-device. - * This has to be global as the usb subsystem needs - * global variables. The other reason is that this - * structure must be there _before_ any comedi - * command is issued. The usb subsystem must be - * initialised before comedi can access it. - */ -static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST]; - -static DEFINE_SEMAPHORE(start_stop_sem); - -/* * bulk transfers to usbduxfast */ #define SENDADCOMMANDS 0 #define SENDINITEP6 1 -static int send_dux_commands(struct usbduxfastsub_s *udfs, int cmd_type) +static int usbduxfast_send_cmd(struct comedi_device *dev, int cmd_type) { - int tmp, nsent; - - udfs->dux_commands[0] = cmd_type; - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: dux_commands: ", - udfs->comedidev->minor); - for (tmp = 0; tmp < SIZEOFDUXBUFFER; tmp++) - printk(" %02x", udfs->dux_commands[tmp]); - printk("\n"); -#endif - - tmp = usb_bulk_msg(udfs->usbdev, - usb_sndbulkpipe(udfs->usbdev, CHANNELLISTEP), - udfs->dux_commands, SIZEOFDUXBUFFER, &nsent, 10000); - if (tmp < 0) - dev_err(&udfs->interface->dev, - "could not transmit dux_commands to the usb-device, err=%d\n", - tmp); - return tmp; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; + int nsent; + int ret; + + devpriv->duxbuf[0] = cmd_type; + + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, CHANNELLISTEP), + devpriv->duxbuf, SIZEOFDUXBUF, + &nsent, 10000); + if (ret < 0) + dev_err(dev->class_dev, + "could not transmit command to the usb-device, err=%d\n", + ret); + return ret; } -/* - * Stops the data acquision. - * It should be safe to call this function from any context. - */ -static int usbduxfastsub_unlink_InURBs(struct usbduxfastsub_s *udfs) +static void usbduxfast_cmd_data(struct comedi_device *dev, int index, + uint8_t len, uint8_t op, uint8_t out, + uint8_t log) { - int j = 0; - int err = 0; + struct usbduxfast_private *devpriv = dev->private; - if (udfs && udfs->urbIn) { - udfs->ai_cmd_running = 0; - /* waits until a running transfer is over */ - usb_kill_urb(udfs->urbIn); - j = 0; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast: unlinked InURB: res=%d\n", j); -#endif - return err; + /* Set the GPIF bytes, the first byte is the command byte */ + devpriv->duxbuf[1 + 0x00 + index] = len; + devpriv->duxbuf[1 + 0x08 + index] = op; + devpriv->duxbuf[1 + 0x10 + index] = out; + devpriv->duxbuf[1 + 0x18 + index] = log; } -/* - * This will stop a running acquisition operation. - * Is called from within this driver from both the - * interrupt context and from comedi. - */ -static int usbduxfast_ai_stop(struct usbduxfastsub_s *udfs, int do_unlink) +static int usbduxfast_ai_stop(struct comedi_device *dev, int do_unlink) { - int ret = 0; + struct usbduxfast_private *devpriv = dev->private; - if (!udfs) { - pr_err("%s: udfs=NULL!\n", __func__); - return -EFAULT; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast_ai_stop\n"); -#endif + /* stop aquistion */ + devpriv->ai_cmd_running = 0; - udfs->ai_cmd_running = 0; - - if (do_unlink) - /* stop aquistion */ - ret = usbduxfastsub_unlink_InURBs(udfs); + if (do_unlink && devpriv->urb) { + /* kill the running transfer */ + usb_kill_urb(devpriv->urb); + } - return ret; + return 0; } -/* - * This will cancel a running acquisition operation. - * This is called by comedi but never from inside the driver. - */ static int usbduxfast_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxfastsub_s *udfs; + struct usbduxfast_private *devpriv = dev->private; int ret; - /* force unlink of all urbs */ -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast_ai_cancel\n"); -#endif - udfs = dev->private; - if (!udfs) { - dev_err(dev->class_dev, "%s: udfs=NULL\n", __func__); + if (!devpriv) return -EFAULT; - } - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } - /* unlink */ - ret = usbduxfast_ai_stop(udfs, 1); - up(&udfs->sem); + + down(&devpriv->sem); + ret = usbduxfast_ai_stop(dev, 1); + up(&devpriv->sem); return ret; } @@ -306,32 +232,17 @@ static int usbduxfast_ai_cancel(struct comedi_device *dev, * analogue IN * interrupt service routine */ -static void usbduxfastsub_ai_Irq(struct urb *urb) +static void usbduxfast_ai_interrupt(struct urb *urb) { + struct comedi_device *dev = urb->context; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; int n, err; - struct usbduxfastsub_s *udfs; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - /* sanity checks - is the urb there? */ - if (!urb) { - pr_err("ao int-handler called with urb=NULL!\n"); - return; - } - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - if (!this_comedidev) { - pr_err("urb context is a NULL pointer!\n"); - return; - } - /* the private structure of the subdevice is usbduxfastsub_s */ - udfs = this_comedidev->private; - if (!udfs) { - pr_err("private of comedi subdev is a NULL pointer!\n"); - return; - } /* are we running a command? */ - if (unlikely(!udfs->ai_cmd_running)) { + if (unlikely(!devpriv->ai_cmd_running)) { /* * not running a command * do not continue execution if no asynchronous command @@ -340,13 +251,6 @@ static void usbduxfastsub_ai_Irq(struct urb *urb) return; } - if (unlikely(!udfs->attached)) { - /* no comedi device there */ - return; - } - /* subdevice which is the AD converter */ - s = &this_comedidev->subdevices[SUBDEV_AD]; - /* first we test if something unusual has just happened */ switch (urb->status) { case 0: @@ -361,189 +265,93 @@ static void usbduxfastsub_ai_Irq(struct urb *urb) case -ESHUTDOWN: case -ECONNABORTED: /* tell this comedi */ - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(udfs->comedidev, s); + async->events |= COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; + comedi_event(dev, s); /* stop the transfer w/o unlink */ - usbduxfast_ai_stop(udfs, 0); + usbduxfast_ai_stop(dev, 0); return; default: pr_err("non-zero urb status received in ai intr context: %d\n", urb->status); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(udfs->comedidev, s); - usbduxfast_ai_stop(udfs, 0); + async->events |= COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; + comedi_event(dev, s); + usbduxfast_ai_stop(dev, 0); return; } - if (!udfs->ignore) { - if (!udfs->ai_continous) { + if (!devpriv->ignore) { + if (!devpriv->ai_continous) { /* not continuous, fixed number of samples */ n = urb->actual_length / sizeof(uint16_t); - if (unlikely(udfs->ai_sample_count < n)) { - /* - * we have send only a fraction of the bytes - * received - */ + if (unlikely(devpriv->ai_sample_count < n)) { + unsigned int num_bytes; + + /* partial sample received */ + num_bytes = devpriv->ai_sample_count * + sizeof(uint16_t); cfc_write_array_to_buffer(s, urb->transfer_buffer, - udfs->ai_sample_count - * sizeof(uint16_t)); - usbduxfast_ai_stop(udfs, 0); + num_bytes); + usbduxfast_ai_stop(dev, 0); /* tell comedi that the acquistion is over */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(udfs->comedidev, s); + async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); return; } - udfs->ai_sample_count -= n; + devpriv->ai_sample_count -= n; } /* write the full buffer to comedi */ err = cfc_write_array_to_buffer(s, urb->transfer_buffer, urb->actual_length); if (unlikely(err == 0)) { /* buffer overflow */ - usbduxfast_ai_stop(udfs, 0); + usbduxfast_ai_stop(dev, 0); return; } /* tell comedi that data is there */ - comedi_event(udfs->comedidev, s); - + comedi_event(dev, s); } else { /* ignore this packet */ - udfs->ignore--; + devpriv->ignore--; } /* * command is still running * resubmit urb for BULK transfer */ - urb->dev = udfs->usbdev; + urb->dev = usb; urb->status = 0; err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - dev_err(&urb->dev->dev, + dev_err(dev->class_dev, "urb resubm failed: %d", err); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(udfs->comedidev, s); - usbduxfast_ai_stop(udfs, 0); - } -} - -static int usbduxfastsub_start(struct usbduxfastsub_s *udfs) -{ - int ret; - unsigned char *local_transfer_buffer; - - local_transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to zero */ - *local_transfer_buffer = 0; - /* bRequest, "Firmware" */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), - USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - USBDUXFASTSUB_CPUCS, /* Value */ - 0x0000, /* Index */ - /* address of the transfer buffer */ - local_transfer_buffer, - 1, /* Length */ - EZTIMEOUT); /* Timeout */ - if (ret < 0) - dev_err(&udfs->interface->dev, - "control msg failed (start)\n"); - - kfree(local_transfer_buffer); - return ret; -} - -static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs) -{ - int ret; - unsigned char *local_transfer_buffer; - - local_transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to one */ - *local_transfer_buffer = 1; - /* bRequest, "Firmware" */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), - USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - USBDUXFASTSUB_CPUCS, /* Value */ - 0x0000, /* Index */ - local_transfer_buffer, 1, /* Length */ - EZTIMEOUT); /* Timeout */ - if (ret < 0) - dev_err(&udfs->interface->dev, - "control msg failed (stop)\n"); - - kfree(local_transfer_buffer); - return ret; -} - -static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs, - unsigned char *local_transfer_buffer, - unsigned int startAddr, unsigned int len) -{ - int ret; - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast: uploading %d bytes", len); - printk(KERN_DEBUG " to addr %d, first byte=%d.\n", - startAddr, local_transfer_buffer[0]); -#endif - /* brequest, firmware */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), - USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - startAddr, /* value */ - 0x0000, /* index */ - /* our local safe buffer */ - local_transfer_buffer, - len, /* length */ - EZTIMEOUT); /* timeout */ - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret); -#endif - - if (ret < 0) { - dev_err(&udfs->interface->dev, "uppload failed\n"); - return ret; + async->events |= COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; + comedi_event(dev, s); + usbduxfast_ai_stop(dev, 0); } - - return 0; } -static int usbduxfastsub_submit_InURBs(struct usbduxfastsub_s *udfs) +static int usbduxfast_submit_urb(struct comedi_device *dev) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; int ret; - if (!udfs) + if (!devpriv) return -EFAULT; - usb_fill_bulk_urb(udfs->urbIn, udfs->usbdev, - usb_rcvbulkpipe(udfs->usbdev, BULKINEP), - udfs->transfer_buffer, - SIZEINBUF, usbduxfastsub_ai_Irq, udfs->comedidev); - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: " - "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context, - udfs->urbIn->dev); -#endif - ret = usb_submit_urb(udfs->urbIn, GFP_ATOMIC); + usb_fill_bulk_urb(devpriv->urb, usb, usb_rcvbulkpipe(usb, BULKINEP), + devpriv->inbuf, SIZEINBUF, + usbduxfast_ai_interrupt, dev); + + ret = usb_submit_urb(devpriv->urb, GFP_ATOMIC); if (ret) { - dev_err(&udfs->interface->dev, - "ai: usb_submit_urb error %d\n", ret); + dev_err(dev->class_dev, "usb_submit_urb error %d\n", ret); return ret; } return 0; @@ -553,13 +361,9 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - struct usbduxfastsub_s *udfs = dev->private; int err = 0; long int steps, tmp; - int minSamplPer; - - if (!udfs->probed) - return -ENODEV; + int min_sample_period; /* Step 1 : check if triggers are trivially valid */ @@ -601,14 +405,14 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->chanlist_len == 1) - minSamplPer = 1; + min_sample_period = 1; else - minSamplPer = MIN_SAMPLING_PERIOD; + min_sample_period = MIN_SAMPLING_PERIOD; if (cmd->convert_src == TRIG_TIMER) { steps = cmd->convert_arg * 30; - if (steps < (minSamplPer * 1000)) - steps = minSamplPer * 1000; + if (steps < (min_sample_period * 1000)) + steps = min_sample_period * 1000; if (steps > (MAX_SAMPLING_PERIOD * 1000)) steps = MAX_SAMPLING_PERIOD * 1000; @@ -650,80 +454,53 @@ static int usbduxfast_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { + struct usbduxfast_private *devpriv = dev->private; int ret; - struct usbduxfastsub_s *udfs = dev->private; - if (!udfs) + if (!devpriv) return -EFAULT; - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast_ai_inttrig\n", dev->minor); -#endif + down(&devpriv->sem); if (trignum != 0) { - dev_err(dev->class_dev, "%s: invalid trignum\n", __func__); - up(&udfs->sem); + dev_err(dev->class_dev, "invalid trignum\n"); + up(&devpriv->sem); return -EINVAL; } - if (!udfs->ai_cmd_running) { - udfs->ai_cmd_running = 1; - ret = usbduxfastsub_submit_InURBs(udfs); + if (!devpriv->ai_cmd_running) { + devpriv->ai_cmd_running = 1; + ret = usbduxfast_submit_urb(dev); if (ret < 0) { - dev_err(dev->class_dev, - "%s: urbSubmit: err=%d\n", __func__, ret); - udfs->ai_cmd_running = 0; - up(&udfs->sem); + dev_err(dev->class_dev, "urbSubmit: err=%d\n", ret); + devpriv->ai_cmd_running = 0; + up(&devpriv->sem); return ret; } s->async->inttrig = NULL; } else { - dev_err(dev->class_dev, - "ai_inttrig but acqu is already running\n"); + dev_err(dev->class_dev, "ai is already running\n"); } - up(&udfs->sem); + up(&devpriv->sem); return 1; } -/* - * offsets for the GPIF bytes - * the first byte is the command byte - */ -#define LENBASE (1+0x00) -#define OPBASE (1+0x08) -#define OUTBASE (1+0x10) -#define LOGBASE (1+0x18) - static int usbduxfast_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct usbduxfast_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int chan, gain, rngmask = 0xff; int i, j, ret; - struct usbduxfastsub_s *udfs; int result; long steps, steps_tmp; -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast_ai_cmd\n", dev->minor); -#endif - udfs = dev->private; - if (!udfs) + if (!devpriv) return -EFAULT; - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } - if (udfs->ai_cmd_running) { - dev_err(dev->class_dev, - "ai_cmd not possible. Another ai_cmd is running.\n"); - up(&udfs->sem); + down(&devpriv->sem); + if (devpriv->ai_cmd_running) { + dev_err(dev->class_dev, "ai_cmd not possible\n"); + up(&devpriv->sem); return -EBUSY; } /* set current channel of the running acquisition to zero */ @@ -733,7 +510,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, * ignore the first buffers from the device if there * is an error condition */ - udfs->ignore = PACKETS_TO_IGNORE; + devpriv->ignore = PACKETS_TO_IGNORE; if (cmd->chanlist_len > 0) { gain = CR_RANGE(cmd->chanlist[0]); @@ -741,20 +518,19 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, chan = CR_CHAN(cmd->chanlist[i]); if (chan != i) { dev_err(dev->class_dev, - "cmd is accepting only consecutive channels.\n"); - up(&udfs->sem); + "channels are not consecutive\n"); + up(&devpriv->sem); return -EINVAL; } if ((gain != CR_RANGE(cmd->chanlist[i])) && (cmd->chanlist_len > 3)) { dev_err(dev->class_dev, - "the gain must be the same for all channels.\n"); - up(&udfs->sem); + "gain must be the same for all channels\n"); + up(&devpriv->sem); return -EINVAL; } if (i >= NUMCHANNELS) { - dev_err(dev->class_dev, - "channel list too long\n"); + dev_err(dev->class_dev, "chanlist too long\n"); break; } } @@ -762,8 +538,8 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, steps = 0; if (cmd->scan_begin_src == TRIG_TIMER) { dev_err(dev->class_dev, - "scan_begin_src==TRIG_TIMER not valid.\n"); - up(&udfs->sem); + "scan_begin_src==TRIG_TIMER not valid\n"); + up(&devpriv->sem); return -EINVAL; } if (cmd->convert_src == TRIG_TIMER) @@ -771,27 +547,23 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, if ((steps < MIN_SAMPLING_PERIOD) && (cmd->chanlist_len != 1)) { dev_err(dev->class_dev, - "ai_cmd: steps=%ld, scan_begin_arg=%d. Not properly tested by cmdtest?\n", + "steps=%ld, scan_begin_arg=%d. Not properly tested by cmdtest?\n", steps, cmd->scan_begin_arg); - up(&udfs->sem); + up(&devpriv->sem); return -EINVAL; } if (steps > MAX_SAMPLING_PERIOD) { - dev_err(dev->class_dev, "ai_cmd: sampling rate too low.\n"); - up(&udfs->sem); + dev_err(dev->class_dev, "sampling rate too low\n"); + up(&devpriv->sem); return -EINVAL; } if ((cmd->start_src == TRIG_EXT) && (cmd->chanlist_len != 1) && (cmd->chanlist_len != 16)) { dev_err(dev->class_dev, - "ai_cmd: TRIG_EXT only with 1 or 16 channels possible.\n"); - up(&udfs->sem); + "TRIG_EXT only with 1 or 16 channels possible\n"); + up(&devpriv->sem); return -EINVAL; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: steps=%ld, convert_arg=%u\n", - dev->minor, steps, cmd->convert_arg); -#endif switch (cmd->chanlist_len) { case 1: @@ -812,17 +584,11 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, /* we loop here until ready has been set */ if (cmd->start_src == TRIG_EXT) { /* branch back to state 0 */ - udfs->dux_commands[LENBASE + 0] = 0x01; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 0] = 0x01; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; /* RDY0 = 0 */ - udfs->dux_commands[LOGBASE + 0] = 0x00; + usbduxfast_cmd_data(dev, 0, 0x01, 0x01, rngmask, 0x00); } else { /* we just proceed to state 1 */ - udfs->dux_commands[LENBASE + 0] = 1; - udfs->dux_commands[OPBASE + 0] = 0; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0x01, 0x00, rngmask, 0x00); } if (steps < MIN_SAMPLING_PERIOD) { @@ -835,33 +601,25 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 1] = 0x89; /* deceision state with data */ - udfs->dux_commands[OPBASE + 1] = 0x03; - udfs->dux_commands[OUTBASE + 1] = - 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 1] = 0xFF; + usbduxfast_cmd_data(dev, 1, + 0x89, 0x03, rngmask, 0xff); } else { /* * we loop through two states: data and delay * max rate is 15MHz */ - udfs->dux_commands[LENBASE + 1] = steps - 1; /* data */ - udfs->dux_commands[OPBASE + 1] = 0x02; - udfs->dux_commands[OUTBASE + 1] = - 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, steps - 1, + 0x02, rngmask, 0x00); + /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 2] = 0x09; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 2] = 0x01; - udfs->dux_commands[OUTBASE + 2] = - 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 2] = 0xFF; + usbduxfast_cmd_data(dev, 2, + 0x09, 0x01, rngmask, 0xff); } } else { /* @@ -873,26 +631,20 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, steps = steps - 1; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 1] = steps / 2; - udfs->dux_commands[OPBASE + 1] = 0; - udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, + steps / 2, 0x00, rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 2] = steps - steps / 2; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; + usbduxfast_cmd_data(dev, 2, steps - steps / 2, + 0x00, rngmask, 0x00); /* get the data and branch back */ /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 3] = 0x09; /* deceision state w data */ - udfs->dux_commands[OPBASE + 3] = 0x03; - udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 3] = 0xFF; + usbduxfast_cmd_data(dev, 3, + 0x09, 0x03, rngmask, 0xff); } break; @@ -907,11 +659,8 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, else rngmask = 0xff; - udfs->dux_commands[LENBASE + 0] = 1; /* data */ - udfs->dux_commands[OPBASE + 0] = 0x02; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0x01, 0x02, rngmask, 0x00); /* we have 1 state with duration 1: state 0 */ steps_tmp = steps - 1; @@ -922,23 +671,16 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 1] = steps_tmp / 2; - udfs->dux_commands[OPBASE + 1] = 0; /* count */ - udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, steps_tmp / 2, + 0x00, 0xfe & rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 2] = steps_tmp - steps_tmp / 2; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; + usbduxfast_cmd_data(dev, 2, steps_tmp - steps_tmp / 2, + 0x00, rngmask, 0x00); - udfs->dux_commands[LENBASE + 3] = 1; /* data */ - udfs->dux_commands[OPBASE + 3] = 0x02; - udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 3] = 0; + usbduxfast_cmd_data(dev, 3, 0x01, 0x02, rngmask, 0x00); /* * we have 2 states with duration 1: step 6 and @@ -952,22 +694,15 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 4] = steps_tmp / 2; - udfs->dux_commands[OPBASE + 4] = 0; /* reset */ - udfs->dux_commands[OUTBASE + 4] = (0xFF - 0x02) & rngmask; - udfs->dux_commands[LOGBASE + 4] = 0; + usbduxfast_cmd_data(dev, 4, steps_tmp / 2, + 0x00, (0xff - 0x02) & rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2; - udfs->dux_commands[OPBASE + 5] = 0; - udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 5] = 0; - - udfs->dux_commands[LENBASE + 6] = 1; - udfs->dux_commands[OPBASE + 6] = 0; - udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 6] = 0; + usbduxfast_cmd_data(dev, 5, steps_tmp - steps_tmp / 2, + 0x00, rngmask, 0x00); + + usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00); break; case 3: @@ -975,6 +710,8 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, * three channels */ for (j = 0; j < 1; j++) { + int index = j * 2; + if (CR_RANGE(cmd->chanlist[j]) > 0) rngmask = 0xff - 0x04; else @@ -983,12 +720,10 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, * commit data to the FIFO and do the first part * of the delay */ - udfs->dux_commands[LENBASE + j * 2] = steps / 2; /* data */ - udfs->dux_commands[OPBASE + j * 2] = 0x02; /* no change */ - udfs->dux_commands[OUTBASE + j * 2] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + j * 2] = 0; + usbduxfast_cmd_data(dev, index, steps / 2, + 0x02, rngmask, 0x00); if (CR_RANGE(cmd->chanlist[j + 1]) > 0) rngmask = 0xff - 0x04; @@ -996,25 +731,19 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the second part of the delay */ - udfs->dux_commands[LENBASE + j * 2 + 1] = - steps - steps / 2; /* no data */ - udfs->dux_commands[OPBASE + j * 2 + 1] = 0; /* count */ - udfs->dux_commands[OUTBASE + j * 2 + 1] = - 0xFE & rngmask; - udfs->dux_commands[LOGBASE + j * 2 + 1] = 0; + usbduxfast_cmd_data(dev, index + 1, steps - steps / 2, + 0x00, 0xfe & rngmask, 0x00); } /* 2 steps with duration 1: the idele step and step 6: */ steps_tmp = steps - 2; /* commit data to the FIFO and do the first part of the delay */ - udfs->dux_commands[LENBASE + 4] = steps_tmp / 2; /* data */ - udfs->dux_commands[OPBASE + 4] = 0x02; - udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 4] = 0; + usbduxfast_cmd_data(dev, 4, steps_tmp / 2, + 0x02, rngmask, 0x00); if (CR_RANGE(cmd->chanlist[0]) > 0) rngmask = 0xff - 0x04; @@ -1022,17 +751,12 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the second part of the delay */ - udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2; /* no data */ - udfs->dux_commands[OPBASE + 5] = 0; /* reset */ - udfs->dux_commands[OUTBASE + 5] = (0xFF - 0x02) & rngmask; - udfs->dux_commands[LOGBASE + 5] = 0; + usbduxfast_cmd_data(dev, 5, steps_tmp - steps_tmp / 2, + 0x00, (0xff - 0x02) & rngmask, 0x00); - udfs->dux_commands[LENBASE + 6] = 1; - udfs->dux_commands[OPBASE + 6] = 0; - udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 6] = 0; + usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00); case 16: if (CR_RANGE(cmd->chanlist[0]) > 0) @@ -1046,101 +770,79 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ /* branch back to state 0 */ - udfs->dux_commands[LENBASE + 0] = 0x01; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 0] = 0x01; /* reset */ - udfs->dux_commands[OUTBASE + 0] = - (0xFF - 0x02) & rngmask; /* RDY0 = 0 */ - udfs->dux_commands[LOGBASE + 0] = 0x00; + usbduxfast_cmd_data(dev, 0, 0x01, 0x01, + (0xff - 0x02) & rngmask, 0x00); } else { /* * we just proceed to state 1 */ /* 30us reset pulse */ - udfs->dux_commands[LENBASE + 0] = 255; - udfs->dux_commands[OPBASE + 0] = 0; /* reset */ - udfs->dux_commands[OUTBASE + 0] = - (0xFF - 0x02) & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0xff, 0x00, + (0xff - 0x02) & rngmask, 0x00); } /* commit data to the FIFO */ - udfs->dux_commands[LENBASE + 1] = 1; /* data */ - udfs->dux_commands[OPBASE + 1] = 0x02; - udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, 0x01, 0x02, rngmask, 0x00); /* we have 2 states with duration 1 */ steps = steps - 2; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 2] = steps / 2; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; + usbduxfast_cmd_data(dev, 2, steps / 2, + 0x00, 0xfe & rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 3] = steps - steps / 2; - udfs->dux_commands[OPBASE + 3] = 0; - udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 3] = 0; + usbduxfast_cmd_data(dev, 3, steps - steps / 2, + 0x00, rngmask, 0x00); /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 4] = 0x09; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 4] = 0x01; - udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 4] = 0xFF; + usbduxfast_cmd_data(dev, 4, 0x09, 0x01, rngmask, 0xff); break; default: dev_err(dev->class_dev, "unsupported combination of channels\n"); - up(&udfs->sem); + up(&devpriv->sem); return -EFAULT; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n", - dev->minor); -#endif /* 0 means that the AD commands are sent */ - result = send_dux_commands(udfs, SENDADCOMMANDS); + result = usbduxfast_send_cmd(dev, SENDADCOMMANDS); if (result < 0) { - dev_err(dev->class_dev, - "adc command could not be submitted. Aborting...\n"); - up(&udfs->sem); + up(&devpriv->sem); return result; } if (cmd->stop_src == TRIG_COUNT) { - udfs->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg; - if (udfs->ai_sample_count < 1) { + devpriv->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg; + if (devpriv->ai_sample_count < 1) { dev_err(dev->class_dev, - "(cmd->stop_arg)*(cmd->scan_end_arg)<1, aborting.\n"); - up(&udfs->sem); + "(cmd->stop_arg)*(cmd->scan_end_arg)<1, aborting\n"); + up(&devpriv->sem); return -EFAULT; } - udfs->ai_continous = 0; + devpriv->ai_continous = 0; } else { /* continous acquisition */ - udfs->ai_continous = 1; - udfs->ai_sample_count = 0; + devpriv->ai_continous = 1; + devpriv->ai_sample_count = 0; } if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) { /* enable this acquisition operation */ - udfs->ai_cmd_running = 1; - ret = usbduxfastsub_submit_InURBs(udfs); + devpriv->ai_cmd_running = 1; + ret = usbduxfast_submit_urb(dev); if (ret < 0) { - udfs->ai_cmd_running = 0; + devpriv->ai_cmd_running = 0; /* fixme: unlink here?? */ - up(&udfs->sem); + up(&devpriv->sem); return ret; } s->async->inttrig = NULL; @@ -1152,7 +854,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ s->async->inttrig = usbduxfast_ai_inttrig; } - up(&udfs->sem); + up(&devpriv->sem); return 0; } @@ -1162,490 +864,283 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ static int usbduxfast_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + uint8_t rngmask = range ? (0xff - 0x04) : 0xff; int i, j, n, actual_length; - int chan, range, rngmask; - int err; - struct usbduxfastsub_s *udfs; + int ret; - udfs = dev->private; - if (!udfs) { - dev_err(dev->class_dev, "%s: no usb dev.\n", __func__); - return -ENODEV; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: ai_insn_read, insn->n=%d, " - "insn->subdev=%d\n", dev->minor, insn->n, insn->subdev); -#endif - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } - if (udfs->ai_cmd_running) { + down(&devpriv->sem); + + if (devpriv->ai_cmd_running) { dev_err(dev->class_dev, - "ai_insn_read not possible. Async Command is running.\n"); - up(&udfs->sem); + "ai_insn_read not possible, async cmd is running\n"); + up(&devpriv->sem); return -EBUSY; } - /* sample one channel */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - /* set command for the first channel */ - if (range > 0) - rngmask = 0xff - 0x04; - else - rngmask = 0xff; + /* set command for the first channel */ /* commit data to the FIFO */ - udfs->dux_commands[LENBASE + 0] = 1; /* data */ - udfs->dux_commands[OPBASE + 0] = 0x02; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0x01, 0x02, rngmask, 0x00); /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 1] = 12; - udfs->dux_commands[OPBASE + 1] = 0; - udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; - - udfs->dux_commands[LENBASE + 2] = 1; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; - - udfs->dux_commands[LENBASE + 3] = 1; - udfs->dux_commands[OPBASE + 3] = 0; - udfs->dux_commands[OUTBASE + 3] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 3] = 0; - - udfs->dux_commands[LENBASE + 4] = 1; - udfs->dux_commands[OPBASE + 4] = 0; - udfs->dux_commands[OUTBASE + 4] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 4] = 0; + usbduxfast_cmd_data(dev, 1, 0x0c, 0x00, 0xfe & rngmask, 0x00); + usbduxfast_cmd_data(dev, 2, 0x01, 0x00, 0xfe & rngmask, 0x00); + usbduxfast_cmd_data(dev, 3, 0x01, 0x00, 0xfe & rngmask, 0x00); + usbduxfast_cmd_data(dev, 4, 0x01, 0x00, 0xfe & rngmask, 0x00); /* second part */ - udfs->dux_commands[LENBASE + 5] = 12; - udfs->dux_commands[OPBASE + 5] = 0; - udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 5] = 0; - - udfs->dux_commands[LENBASE + 6] = 1; - udfs->dux_commands[OPBASE + 6] = 0; - udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n", - dev->minor); -#endif - /* 0 means that the AD commands are sent */ - err = send_dux_commands(udfs, SENDADCOMMANDS); - if (err < 0) { - dev_err(dev->class_dev, - "adc command could not be submitted. Aborting...\n"); - up(&udfs->sem); - return err; + usbduxfast_cmd_data(dev, 5, 0x0c, 0x00, rngmask, 0x00); + usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00); + + ret = usbduxfast_send_cmd(dev, SENDADCOMMANDS); + if (ret < 0) { + up(&devpriv->sem); + return ret; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: " - "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context, - udfs->urbIn->dev); -#endif + for (i = 0; i < PACKETS_TO_IGNORE; i++) { - err = usb_bulk_msg(udfs->usbdev, - usb_rcvbulkpipe(udfs->usbdev, BULKINEP), - udfs->transfer_buffer, SIZEINBUF, + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, BULKINEP), + devpriv->inbuf, SIZEINBUF, &actual_length, 10000); - if (err < 0) { - dev_err(dev->class_dev, "insn timeout. No data.\n"); - up(&udfs->sem); - return err; + if (ret < 0) { + dev_err(dev->class_dev, "insn timeout, no data\n"); + up(&devpriv->sem); + return ret; } } - /* data points */ + for (i = 0; i < insn->n;) { - err = usb_bulk_msg(udfs->usbdev, - usb_rcvbulkpipe(udfs->usbdev, BULKINEP), - udfs->transfer_buffer, SIZEINBUF, + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, BULKINEP), + devpriv->inbuf, SIZEINBUF, &actual_length, 10000); - if (err < 0) { - dev_err(dev->class_dev, "insn data error: %d\n", err); - up(&udfs->sem); - return err; + if (ret < 0) { + dev_err(dev->class_dev, "insn data error: %d\n", ret); + up(&devpriv->sem); + return ret; } n = actual_length / sizeof(uint16_t); if ((n % 16) != 0) { - dev_err(dev->class_dev, "insn data packet corrupted.\n"); - up(&udfs->sem); + dev_err(dev->class_dev, "insn data packet corrupted\n"); + up(&devpriv->sem); return -EINVAL; } for (j = chan; (j < n) && (i < insn->n); j = j + 16) { - data[i] = ((uint16_t *) (udfs->transfer_buffer))[j]; + data[i] = ((uint16_t *) (devpriv->inbuf))[j]; i++; } } - up(&udfs->sem); - return i; -} - -#define FIRMWARE_MAX_LEN 0x2000 - -static int firmwareUpload(struct usbduxfastsub_s *usbduxfastsub, - const u8 *firmwareBinary, int sizeFirmware) -{ - int ret; - uint8_t *fwBuf; - - if (!firmwareBinary) - return 0; - - if (sizeFirmware > FIRMWARE_MAX_LEN) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: usbduxfast firmware binary it too large for FX2.\n"); - return -ENOMEM; - } - - /* we generate a local buffer for the firmware */ - fwBuf = kmemdup(firmwareBinary, sizeFirmware, GFP_KERNEL); - if (!fwBuf) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: mem alloc for firmware failed\n"); - return -ENOMEM; - } - - ret = usbduxfastsub_stop(usbduxfastsub); - if (ret < 0) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: can not stop firmware\n"); - kfree(fwBuf); - return ret; - } - - ret = usbduxfastsub_upload(usbduxfastsub, fwBuf, 0, sizeFirmware); - if (ret < 0) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: firmware upload failed\n"); - kfree(fwBuf); - return ret; - } - ret = usbduxfastsub_start(usbduxfastsub); - if (ret < 0) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: can not start firmware\n"); - kfree(fwBuf); - return ret; - } - kfree(fwBuf); - return 0; -} - -static void tidy_up(struct usbduxfastsub_s *udfs) -{ -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: tiding up\n"); -#endif - - if (!udfs) - return; - /* shows the usb subsystem that the driver is down */ - if (udfs->interface) - usb_set_intfdata(udfs->interface, NULL); + up(&devpriv->sem); - udfs->probed = 0; - - if (udfs->urbIn) { - /* waits until a running transfer is over */ - usb_kill_urb(udfs->urbIn); - - kfree(udfs->transfer_buffer); - udfs->transfer_buffer = NULL; - - usb_free_urb(udfs->urbIn); - udfs->urbIn = NULL; - } - - kfree(udfs->insnBuffer); - udfs->insnBuffer = NULL; - - kfree(udfs->dux_commands); - udfs->dux_commands = NULL; - - udfs->ai_cmd_running = 0; + return insn->n; } -static int usbduxfast_attach_common(struct comedi_device *dev, - struct usbduxfastsub_s *udfs) +static int usbduxfast_attach_common(struct comedi_device *dev) { - int ret; + struct usbduxfast_private *devpriv = dev->private; struct comedi_subdevice *s; + int ret; - down(&udfs->sem); - /* pointer back to the corresponding comedi device */ - udfs->comedidev = dev; + down(&devpriv->sem); ret = comedi_alloc_subdevices(dev, 1); if (ret) { - up(&udfs->sem); + up(&devpriv->sem); return ret; } - /* private structure is also simply the usb-structure */ - dev->private = udfs; - /* the first subdevice is the A/D converter */ - s = &dev->subdevices[SUBDEV_AD]; - /* - * the URBs get the comedi subdevice which is responsible for reading - * this is the subdevice which reads data - */ + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; dev->read_subdev = s; - /* the subdevice receives as private structure the usb-structure */ - s->private = NULL; - /* analog input */ - s->type = COMEDI_SUBD_AI; - /* readable and ref is to ground */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - /* 16 channels */ - s->n_chan = 16; - /* length of the channellist */ - s->len_chanlist = 16; - /* callback functions */ - s->insn_read = usbduxfast_ai_insn_read; - s->do_cmdtest = usbduxfast_ai_cmdtest; - s->do_cmd = usbduxfast_ai_cmd; - s->cancel = usbduxfast_ai_cancel; - /* max value from the A/D converter (12bit+1 bit for overflow) */ - s->maxdata = 0x1000; - /* range table to convert to physical units */ - s->range_table = &range_usbduxfast_ai_range; - /* finally decide that it's attached */ - udfs->attached = 1; - up(&udfs->sem); - dev_info(dev->class_dev, "successfully attached to usbduxfast.\n"); + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->n_chan = 16; + s->len_chanlist = 16; + s->insn_read = usbduxfast_ai_insn_read; + s->do_cmdtest = usbduxfast_ai_cmdtest; + s->do_cmd = usbduxfast_ai_cmd; + s->cancel = usbduxfast_ai_cancel; + s->maxdata = 0x1000; + s->range_table = &range_usbduxfast_ai_range; + + up(&devpriv->sem); + return 0; } -static int usbduxfast_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int usbduxfast_upload_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { - struct usb_interface *uinterf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + uint8_t *buf; + unsigned char *tmp; int ret; - struct usbduxfastsub_s *udfs; - dev->private = NULL; - down(&start_stop_sem); - udfs = usb_get_intfdata(uinterf); - if (!udfs || !udfs->probed) { - dev_err(dev->class_dev, - "usbduxfast: error: auto_attach failed, not connected\n"); - ret = -ENODEV; - } else if (udfs->attached) { - dev_err(dev->class_dev, - "usbduxfast: error: auto_attach failed, already attached\n"); - ret = -ENODEV; - } else - ret = usbduxfast_attach_common(dev, udfs); - up(&start_stop_sem); - return ret; -} + if (!data) + return 0; -static void usbduxfast_detach(struct comedi_device *dev) -{ - struct usbduxfastsub_s *usb = dev->private; - - if (usb) { - down(&usb->sem); - down(&start_stop_sem); - dev->private = NULL; - usb->attached = 0; - usb->comedidev = NULL; - up(&start_stop_sem); - up(&usb->sem); + if (size > FIRMWARE_MAX_LEN) { + dev_err(dev->class_dev, "firmware binary too large for FX2\n"); + return -ENOMEM; } -} - -static struct comedi_driver usbduxfast_driver = { - .driver_name = "usbduxfast", - .module = THIS_MODULE, - .auto_attach = usbduxfast_auto_attach, - .detach = usbduxfast_detach, -}; -static void usbduxfast_firmware_request_complete_handler(const struct firmware - *fw, void *context) -{ - struct usbduxfastsub_s *usbduxfastsub_tmp = context; - struct usb_interface *uinterf = usbduxfastsub_tmp->interface; - int ret; + /* we generate a local buffer for the firmware */ + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (fw == NULL) - return; + /* we need a malloc'ed buffer for usb_control_msg() */ + tmp = kmalloc(1, GFP_KERNEL); + if (!tmp) { + kfree(buf); + return -ENOMEM; + } - /* - * we need to upload the firmware here because fw will be - * freed once we've left this function - */ - ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size); + /* stop the current firmware on the device */ + *tmp = 1; /* 7f92 to one */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXFASTSUB_CPUCS, 0x0000, + tmp, 1, + EZTIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "can not stop firmware\n"); + goto done; + } - if (ret) { - dev_err(&uinterf->dev, - "Could not upload firmware (err=%d)\n", ret); - goto out; + /* upload the new firmware to the device */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, + 0, 0x0000, + buf, size, + EZTIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "firmware upload failed\n"); + goto done; } - comedi_usb_auto_config(uinterf, &usbduxfast_driver, 0); - out: - release_firmware(fw); + /* start the new firmware on the device */ + *tmp = 0; /* 7f92 to zero */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXFASTSUB_CPUCS, 0x0000, + tmp, 1, + EZTIMEOUT); + if (ret < 0) + dev_err(dev->class_dev, "can not start firmware\n"); + +done: + kfree(tmp); + kfree(buf); + return ret; } -static int usbduxfast_usb_probe(struct usb_interface *uinterf, - const struct usb_device_id *id) +static int usbduxfast_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - struct usb_device *udev = interface_to_usbdev(uinterf); - int i; - int index; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv; int ret; - if (udev->speed != USB_SPEED_HIGH) { - dev_err(&uinterf->dev, + if (usb->speed != USB_SPEED_HIGH) { + dev_err(dev->class_dev, "This driver needs USB 2.0 to operate. Aborting...\n"); return -ENODEV; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast_: finding a free structure for " - "the usb-device\n"); -#endif - down(&start_stop_sem); - /* look for a free place in the usbduxfast array */ - index = -1; - for (i = 0; i < NUMUSBDUXFAST; i++) { - if (!usbduxfastsub[i].probed) { - index = i; - break; - } - } - /* no more space */ - if (index == -1) { - dev_err(&uinterf->dev, - "Too many usbduxfast-devices connected.\n"); - up(&start_stop_sem); - return -EMFILE; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: usbduxfastsub[%d] is ready to " - "connect to comedi.\n", index); -#endif - - sema_init(&(usbduxfastsub[index].sem), 1); - /* save a pointer to the usb device */ - usbduxfastsub[index].usbdev = udev; - - /* save the interface itself */ - usbduxfastsub[index].interface = uinterf; - /* get the interface number from the interface */ - usbduxfastsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber; - /* - * hand the private data over to the usb subsystem - * will be needed for disconnect - */ - usb_set_intfdata(uinterf, &(usbduxfastsub[index])); - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: ifnum=%d\n", - usbduxfastsub[index].ifnum); -#endif - /* create space for the commands going to the usb device */ - usbduxfastsub[index].dux_commands = kmalloc(SIZEOFDUXBUFFER, - GFP_KERNEL); - if (!usbduxfastsub[index].dux_commands) { - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) return -ENOMEM; - } - /* create space of the instruction buffer */ - usbduxfastsub[index].insnBuffer = kmalloc(SIZEINSNBUF, GFP_KERNEL); - if (!usbduxfastsub[index].insnBuffer) { - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + dev->private = devpriv; + + sema_init(&devpriv->sem, 1); + usb_set_intfdata(intf, devpriv); + + devpriv->duxbuf = kmalloc(SIZEOFDUXBUF, GFP_KERNEL); + if (!devpriv->duxbuf) return -ENOMEM; - } - /* setting to alternate setting 1: enabling bulk ep */ - i = usb_set_interface(usbduxfastsub[index].usbdev, - usbduxfastsub[index].ifnum, 1); - if (i < 0) { - dev_err(&uinterf->dev, - "usbduxfast%d: could not switch to alternate setting 1.\n", - index); - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + + ret = usb_set_interface(usb, + intf->altsetting->desc.bInterfaceNumber, 1); + if (ret < 0) { + dev_err(dev->class_dev, + "could not switch to alternate setting 1\n"); return -ENODEV; } - usbduxfastsub[index].urbIn = usb_alloc_urb(0, GFP_KERNEL); - if (!usbduxfastsub[index].urbIn) { - dev_err(&uinterf->dev, - "usbduxfast%d: Could not alloc. urb\n", index); - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + + devpriv->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!devpriv->urb) { + dev_err(dev->class_dev, "Could not alloc. urb\n"); return -ENOMEM; } - usbduxfastsub[index].transfer_buffer = kmalloc(SIZEINBUF, GFP_KERNEL); - if (!usbduxfastsub[index].transfer_buffer) { - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + + devpriv->inbuf = kmalloc(SIZEINBUF, GFP_KERNEL); + if (!devpriv->inbuf) return -ENOMEM; - } - /* we've reached the bottom of the function */ - usbduxfastsub[index].probed = 1; - up(&start_stop_sem); - - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, - FIRMWARE, - &udev->dev, - GFP_KERNEL, - usbduxfastsub + index, - usbduxfast_firmware_request_complete_handler); - if (ret) { - dev_err(&uinterf->dev, "could not load firmware (err=%d)\n", ret); + ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, + usbduxfast_upload_firmware, 0); + if (ret) return ret; - } - dev_info(&uinterf->dev, - "usbduxfast%d has been successfully initialized.\n", index); - /* success */ - return 0; + return usbduxfast_attach_common(dev); } -static void usbduxfast_usb_disconnect(struct usb_interface *intf) +static void usbduxfast_detach(struct comedi_device *dev) { - struct usbduxfastsub_s *udfs = usb_get_intfdata(intf); - struct usb_device *udev = interface_to_usbdev(intf); + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usbduxfast_private *devpriv = dev->private; - if (!udfs) { - dev_err(&intf->dev, "disconnect called with null pointer.\n"); - return; - } - if (udfs->usbdev != udev) { - dev_err(&intf->dev, "BUG! called with wrong ptr!!!\n"); + if (!devpriv) return; + + down(&devpriv->sem); + + usb_set_intfdata(intf, NULL); + + if (devpriv->urb) { + /* waits until a running transfer is over */ + usb_kill_urb(devpriv->urb); + + kfree(devpriv->inbuf); + devpriv->inbuf = NULL; + + usb_free_urb(devpriv->urb); + devpriv->urb = NULL; } - comedi_usb_auto_unconfig(intf); + kfree(devpriv->duxbuf); + devpriv->duxbuf = NULL; - down(&start_stop_sem); - down(&udfs->sem); - tidy_up(udfs); - up(&udfs->sem); - up(&start_stop_sem); + devpriv->ai_cmd_running = 0; -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: disconnected from the usb\n"); -#endif + up(&devpriv->sem); +} + +static struct comedi_driver usbduxfast_driver = { + .driver_name = "usbduxfast", + .module = THIS_MODULE, + .auto_attach = usbduxfast_auto_attach, + .detach = usbduxfast_detach, +}; + +static int usbduxfast_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &usbduxfast_driver, 0); } static const struct usb_device_id usbduxfast_usb_table[] = { @@ -1657,12 +1152,9 @@ static const struct usb_device_id usbduxfast_usb_table[] = { MODULE_DEVICE_TABLE(usb, usbduxfast_usb_table); static struct usb_driver usbduxfast_usb_driver = { -#ifdef COMEDI_HAVE_USB_DRIVER_OWNER - .owner = THIS_MODULE, -#endif .name = "usbduxfast", .probe = usbduxfast_usb_probe, - .disconnect = usbduxfast_usb_disconnect, + .disconnect = comedi_usb_auto_unconfig, .id_table = usbduxfast_usb_table, }; module_comedi_usb_driver(usbduxfast_driver, usbduxfast_usb_driver); diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index d3bc1b9910a7..898c3c450406 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -1,30 +1,27 @@ /* - comedi/drivers/usbdux.c - Copyright (C) 2011 Bernd Porr, Bernd.Porr@f2s.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - + * usbduxsigma.c + * Copyright (C) 2011 Bernd Porr, Bernd.Porr@f2s.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: usbduxsigma -Description: University of Stirling USB DAQ & INCITE Technology Limited -Devices: [ITL] USB-DUX (usbduxsigma.o) -Author: Bernd Porr <BerndPorr@f2s.com> -Updated: 8 Nov 2011 -Status: testing -*/ + * Driver: usbduxsigma + * Description: University of Stirling USB DAQ & INCITE Technology Limited + * Devices: (ITL) USB-DUX [usbduxsigma] + * Author: Bernd Porr <BerndPorr@f2s.com> + * Updated: 8 Nov 2011 + * Status: testing + */ + /* * I must give credit here to Chris Baugher who * wrote the driver for AT-MIO-16d. I used some parts of this @@ -44,9 +41,6 @@ Status: testing * 0.6: corrected wrong input range */ -/* generates loads of debug info */ -/* #define NOISY_DUX_DEBUGBUG */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -55,7 +49,7 @@ Status: testing #include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> -#include <linux/firmware.h> + #include "comedi_fc.h" #include "../comedidev.h" @@ -63,38 +57,21 @@ Status: testing #define BULK_TIMEOUT 1000 /* constants for "firmware" upload and download */ -#define FIRMWARE "usbduxsigma_firmware.bin" -#define USBDUXSUB_FIRMWARE 0xA0 -#define VENDOR_DIR_IN 0xC0 -#define VENDOR_DIR_OUT 0x40 +#define FIRMWARE "usbduxsigma_firmware.bin" +#define FIRMWARE_MAX_LEN 0x4000 +#define USBDUXSUB_FIRMWARE 0xa0 +#define VENDOR_DIR_IN 0xc0 +#define VENDOR_DIR_OUT 0x40 /* internal addresses of the 8051 processor */ #define USBDUXSUB_CPUCS 0xE600 -/* - * the minor device number, major is 180 only for debugging purposes and to - * upload special firmware (programming the eeprom etc) which is not - * compatible with the comedi framwork - */ -#define USBDUXSUB_MINOR 32 - -/* max lenghth of the transfer-buffer for software upload */ -#define TB_LEN 0x2000 - -/* Input endpoint number: ISO/IRQ */ -#define ISOINEP 6 - -/* Output endpoint number: ISO/IRQ */ -#define ISOOUTEP 2 - -/* This EP sends DUX commands to USBDUX */ -#define COMMAND_OUT_EP 1 - -/* This EP receives the DUX commands from USBDUX */ -#define COMMAND_IN_EP 8 - -/* Output endpoint for PWM */ -#define PWM_EP 4 +/* USB endpoints */ +#define USBDUXSIGMA_CMD_OUT_EP 1 /* command output */ +#define USBDUXSIGMA_ISO_OUT_EP 2 /* analog output ISO/IRQ */ +#define USBDUXSIGMA_PWM_OUT_EP 4 /* pwm output */ +#define USBDUXSIGMA_ISO_IN_EP 6 /* analog input ISO/IRQ */ +#define USBDUXSIGMA_CMD_IN_EP 8 /* command input */ /* 300Hz max frequ under PWM */ #define MIN_PWM_PERIOD ((long)(1E9/300)) @@ -105,6 +82,8 @@ Status: testing /* Number of channels (16 AD and offset)*/ #define NUMCHANNELS 16 +#define USBDUXSIGMA_NUM_AO_CHAN 4 + /* Size of one A/D value */ #define SIZEADIN ((sizeof(int32_t))) @@ -150,84 +129,54 @@ Status: testing /* must have more buffers due to buggy USB ctr */ #define NUMOFOUTBUFFERSHIGH 10 -/* Total number of usbdux devices */ -#define NUMUSBDUX 16 - -/* Analogue in subdevice */ -#define SUBDEV_AD 0 - -/* Analogue out subdevice */ -#define SUBDEV_DA 1 - -/* Digital I/O */ -#define SUBDEV_DIO 2 - -/* timer aka pwm output */ -#define SUBDEV_PWM 3 - /* number of retries to get the right dux command */ #define RETRIES 10 -/**************************************************/ -/* comedi constants */ -static const struct comedi_lrange range_usbdux_ai_range = { 1, { - BIP_RANGE - (2.65/2.0) - } -}; +/* bulk transfer commands to usbduxsigma */ +#define USBBUXSIGMA_AD_CMD 0 +#define USBDUXSIGMA_DA_CMD 1 +#define USBDUXSIGMA_DIO_CFG_CMD 2 +#define USBDUXSIGMA_DIO_BITS_CMD 3 +#define USBDUXSIGMA_SINGLE_AD_CMD 4 +#define USBDUXSIGMA_PWM_ON_CMD 7 +#define USBDUXSIGMA_PWM_OFF_CMD 8 -/* - * private structure of one subdevice - */ +static const struct comedi_lrange usbduxsigma_ai_range = { + 1, { + BIP_RANGE(2.65 / 2.0) + } +}; -/* - * This is the structure which holds all the data of - * this driver one sub device just now: A/D - */ -struct usbduxsub { - /* attached? */ - int attached; - /* is it associated with a subdevice? */ - int probed; - /* pointer to the usb-device */ - struct usb_device *usbdev; +struct usbduxsigma_private { /* actual number of in-buffers */ - int numOfInBuffers; + int n_ai_urbs; /* actual number of out-buffers */ - int numOfOutBuffers; + int n_ao_urbs; /* ISO-transfer handling: buffers */ - struct urb **urbIn; - struct urb **urbOut; + struct urb **ai_urbs; + struct urb **ao_urbs; /* pwm-transfer handling */ - struct urb *urbPwm; + struct urb *pwm_urb; /* PWM period */ - unsigned int pwmPeriod; + unsigned int pwm_period; /* PWM internal delay for the GPIF in the FX2 */ - uint8_t pwmDelay; + uint8_t pwm_delay; /* size of the PWM buffer which holds the bit pattern */ - int sizePwmBuf; + int pwm_buf_sz; /* input buffer for the ISO-transfer */ - int32_t *inBuffer; + int32_t *in_buf; /* input buffer for single insn */ - int8_t *insnBuffer; - /* output buffer for single DA outputs */ - int16_t *outBuffer; - /* interface number */ - int ifnum; - /* interface structure in 2.6 */ - struct usb_interface *interface; - /* comedi device for the interrupt context */ - struct comedi_device *comedidev; - /* is it USB_SPEED_HIGH or not? */ - short int high_speed; - /* asynchronous command is running */ - short int ai_cmd_running; - short int ao_cmd_running; - /* pwm is running */ - short int pwm_cmd_running; - /* continuous acquisition */ - short int ai_continuous; - short int ao_continuous; + int8_t *insn_buf; + + unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN]; + + unsigned high_speed:1; + unsigned ai_cmd_running:1; + unsigned ai_continuous:1; + unsigned ao_cmd_running:1; + unsigned ao_continuous:1; + unsigned pwm_cmd_running:1; + /* number of samples to acquire */ int ai_sample_count; int ao_sample_count; @@ -246,126 +195,58 @@ struct usbduxsub { struct semaphore sem; }; -/* - * The pointer to the private usb-data of the driver is also the private data - * for the comedi-device. This has to be global as the usb subsystem needs - * global variables. The other reason is that this structure must be there - * _before_ any comedi command is issued. The usb subsystem must be initialised - * before comedi can access it. - */ -static struct usbduxsub usbduxsub[NUMUSBDUX]; - -static DEFINE_SEMAPHORE(start_stop_sem); - -/* - * Stops the data acquision - * It should be safe to call this function from any context - */ -static int usbduxsub_unlink_InURBs(struct usbduxsub *usbduxsub_tmp) +static void usbduxsigma_ai_stop(struct comedi_device *dev, int do_unlink) { - int i = 0; - int err = 0; - - if (usbduxsub_tmp && usbduxsub_tmp->urbIn) { - for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) { - if (usbduxsub_tmp->urbIn[i]) { - /* We wait here until all transfers have been - * cancelled. */ - usb_kill_urb(usbduxsub_tmp->urbIn[i]); - } - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: usbdux: unlinked InURB %d, err=%d\n", - i, err); - } - } - return err; -} - -/* - * This will stop a running acquisition operation - * Is called from within this driver from both the - * interrupt context and from comedi - */ -static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink) -{ - int ret = 0; - - if (!this_usbduxsub) { - pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n"); - return -EFAULT; - } - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n"); + struct usbduxsigma_private *devpriv = dev->private; if (do_unlink) { - /* stop aquistion */ - ret = usbduxsub_unlink_InURBs(this_usbduxsub); - } + int i; - this_usbduxsub->ai_cmd_running = 0; + for (i = 0; i < devpriv->n_ai_urbs; i++) { + if (devpriv->ai_urbs[i]) + usb_kill_urb(devpriv->ai_urbs[i]); + } + } - return ret; + devpriv->ai_cmd_running = 0; } -/* - * This will cancel a running acquisition operation. - * This is called by comedi but never from inside the driver. - */ -static int usbdux_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int usbduxsigma_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub; - int res = 0; - - /* force unlink of all urbs */ - this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; + struct usbduxsigma_private *devpriv = dev->private; - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_cancel\n"); + down(&devpriv->sem); + /* unlink only if it is really running */ + usbduxsigma_ai_stop(dev, devpriv->ai_cmd_running); + up(&devpriv->sem); - /* prevent other CPUs from submitting new commands just now */ - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - /* unlink only if the urb really has been submitted */ - res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running); - up(&this_usbduxsub->sem); - return res; + return 0; } -/* analogue IN - interrupt service routine */ -static void usbduxsub_ai_IsocIrq(struct urb *urb) +static void usbduxsigma_ai_urb_complete(struct urb *urb) { - int i, err, n; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - int32_t v; + struct comedi_device *dev = urb->context; + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; unsigned int dio_state; - - /* the context variable points to the comedi device */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - /* subdevice which is the AD converter */ - s = &this_comedidev->subdevices[SUBDEV_AD]; + int32_t val; + int ret; + int i; /* first we test if something unusual has just happened */ switch (urb->status) { case 0: /* copy the result in the transfer buffer */ - memcpy(this_usbduxsub->inBuffer, - urb->transfer_buffer, SIZEINBUF); + memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); break; case -EILSEQ: - /* error in the ISOchronous data */ - /* we don't copy the data into the transfer buffer */ - /* and recycle the last data byte */ - dev_dbg(&urb->dev->dev, - "comedi%d: usbdux: CRC error in ISO IN stream.\n", - this_usbduxsub->comedidev->minor); + /* + * error in the ISOchronous data + * we don't copy the data into the transfer buffer + * and recycle the last data byte + */ + dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); break; @@ -374,185 +255,127 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ - if (this_usbduxsub->ai_cmd_running) { - /* we are still running a command */ - /* tell this comedi */ - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); - /* stop the transfer w/o unlink */ - usbdux_ai_stop(this_usbduxsub, 0); + if (devpriv->ai_cmd_running) { + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + /* we are still running a command, tell comedi */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); } return; default: - /* a real error on the bus */ - /* pass error to comedi if we are really running a command */ - if (this_usbduxsub->ai_cmd_running) { - dev_err(&urb->dev->dev, - "Non-zero urb status received in ai intr " - "context: %d\n", urb->status); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); - /* don't do an unlink here */ - usbdux_ai_stop(this_usbduxsub, 0); + /* + * a real error on the bus + * pass error to comedi if we are really running a command + */ + if (devpriv->ai_cmd_running) { + dev_err(dev->class_dev, + "%s: non-zero urb status (%d)\n", + __func__, urb->status); + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); } return; } - /* - * at this point we are reasonably sure that nothing dodgy has happened - * are we running a command? - */ - if (unlikely((!(this_usbduxsub->ai_cmd_running)))) { - /* - * not running a command, do not continue execution if no - * asynchronous command is running in particular not resubmit - */ + if (unlikely(!devpriv->ai_cmd_running)) return; - } - urb->dev = this_usbduxsub->usbdev; - - /* resubmit the urb */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err < 0)) { - dev_err(&urb->dev->dev, - "comedi_: urb resubmit failed in int-context!" - "err=%d\n", - err); - if (err == -EL2NSYNC) - dev_err(&urb->dev->dev, - "buggy USB host controller or bug in IRQ " - "handler!\n"); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); - /* don't do an unlink here */ - usbdux_ai_stop(this_usbduxsub, 0); + urb->dev = comedi_to_usb_dev(dev); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(ret < 0)) { + dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", + __func__, ret); + if (ret == -EL2NSYNC) + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler\n"); + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); return; } /* get the state of the dio pins to allow external trigger */ - dio_state = be32_to_cpu(this_usbduxsub->inBuffer[0]); + dio_state = be32_to_cpu(devpriv->in_buf[0]); - this_usbduxsub->ai_counter--; - if (likely(this_usbduxsub->ai_counter > 0)) + devpriv->ai_counter--; + if (likely(devpriv->ai_counter > 0)) return; /* timer zero, transfer measurements to comedi */ - this_usbduxsub->ai_counter = this_usbduxsub->ai_timer; + devpriv->ai_counter = devpriv->ai_timer; - /* test, if we transmit only a fixed number of samples */ - if (!(this_usbduxsub->ai_continuous)) { + if (!devpriv->ai_continuous) { /* not continuous, fixed number of samples */ - this_usbduxsub->ai_sample_count--; - /* all samples received? */ - if (this_usbduxsub->ai_sample_count < 0) { - /* prevent a resubmit next time */ - usbdux_ai_stop(this_usbduxsub, 0); - /* say comedi that the acquistion is over */ + devpriv->ai_sample_count--; + if (devpriv->ai_sample_count < 0) { + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + /* acquistion is over, tell comedi */ s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); return; } } + /* get the data from the USB bus and hand it over to comedi */ - n = s->async->cmd.chanlist_len; - for (i = 0; i < n; i++) { + for (i = 0; i < s->async->cmd.chanlist_len; i++) { /* transfer data, note first byte is the DIO state */ - v = be32_to_cpu(this_usbduxsub->inBuffer[i+1]); - /* strip status byte */ - v = v & 0x00ffffff; - /* convert to unsigned */ - v = v ^ 0x00800000; - /* write the byte to the buffer */ - err = cfc_write_array_to_buffer(s, &v, sizeof(uint32_t)); - if (unlikely(err == 0)) { + val = be32_to_cpu(devpriv->in_buf[i+1]); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ + + ret = cfc_write_array_to_buffer(s, &val, sizeof(uint32_t)); + if (unlikely(ret == 0)) { /* buffer overflow */ - usbdux_ai_stop(this_usbduxsub, 0); + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ return; } } /* tell comedi that data is there */ - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(this_usbduxsub->comedidev, s); + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + comedi_event(dev, s); } -static int usbduxsub_unlink_OutURBs(struct usbduxsub *usbduxsub_tmp) +static void usbduxsigma_ao_stop(struct comedi_device *dev, int do_unlink) { - int i = 0; - int err = 0; + struct usbduxsigma_private *devpriv = dev->private; - if (usbduxsub_tmp && usbduxsub_tmp->urbOut) { - for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) { - if (usbduxsub_tmp->urbOut[i]) - usb_kill_urb(usbduxsub_tmp->urbOut[i]); + if (do_unlink) { + int i; - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: usbdux: unlinked OutURB %d: res=%d\n", - i, err); + for (i = 0; i < devpriv->n_ao_urbs; i++) { + if (devpriv->ao_urbs[i]) + usb_kill_urb(devpriv->ao_urbs[i]); } } - return err; -} -/* This will cancel a running acquisition operation - * in any context. - */ -static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink) -{ - int ret = 0; - - if (!this_usbduxsub) - return -EFAULT; - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n"); - - if (do_unlink) - ret = usbduxsub_unlink_OutURBs(this_usbduxsub); - - this_usbduxsub->ao_cmd_running = 0; - - return ret; + devpriv->ao_cmd_running = 0; } -/* force unlink, is called by comedi */ -static int usbdux_ao_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int usbduxsigma_ao_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub = dev->private; - int res = 0; + struct usbduxsigma_private *devpriv = dev->private; - if (!this_usbduxsub) - return -EFAULT; - - /* prevent other CPUs from submitting a command just now */ - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); /* unlink only if it is really running */ - res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running); - up(&this_usbduxsub->sem); - return res; + usbduxsigma_ao_stop(dev, devpriv->ao_cmd_running); + up(&devpriv->sem); + + return 0; } -static void usbduxsub_ao_IsocIrq(struct urb *urb) +static void usbduxsigma_ao_urb_complete(struct urb *urb) { - int i, ret; + struct comedi_device *dev = urb->context; + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->write_subdev; uint8_t *datap; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - - s = &this_comedidev->subdevices[SUBDEV_DA]; + int len; + int ret; + int i; switch (urb->status) { case 0: @@ -563,347 +386,141 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: - /* after an unlink command, unplug, ... etc */ - /* no unlink needed here. Already shutting down. */ - if (this_usbduxsub->ao_cmd_running) { + /* happens after an unlink command */ + if (devpriv->ao_cmd_running) { + usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); - usbdux_ao_stop(this_usbduxsub, 0); + comedi_event(dev, s); } return; default: /* a real error */ - if (this_usbduxsub->ao_cmd_running) { - dev_err(&urb->dev->dev, - "comedi_: Non-zero urb status received in ao " - "intr context: %d\n", urb->status); - s->async->events |= COMEDI_CB_ERROR; - s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); - /* we do an unlink if we are in the high speed mode */ - usbdux_ao_stop(this_usbduxsub, 0); + if (devpriv->ao_cmd_running) { + dev_err(dev->class_dev, + "%s: non-zero urb status (%d)\n", + __func__, urb->status); + usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ + s->async->events |= (COMEDI_CB_ERROR | COMEDI_CB_EOA); + comedi_event(dev, s); } return; } - /* are we actually running? */ - if (!(this_usbduxsub->ao_cmd_running)) + if (!devpriv->ao_cmd_running) return; - /* normal operation: executing a command in this subdevice */ - this_usbduxsub->ao_counter--; - if ((int)this_usbduxsub->ao_counter <= 0) { - /* timer zero */ - this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; - - /* handle non continuous acquisition */ - if (!(this_usbduxsub->ao_continuous)) { - /* fixed number of samples */ - this_usbduxsub->ao_sample_count--; - if (this_usbduxsub->ao_sample_count < 0) { - /* all samples transmitted */ - usbdux_ao_stop(this_usbduxsub, 0); + devpriv->ao_counter--; + if ((int)devpriv->ao_counter <= 0) { + /* timer zero, transfer from comedi */ + devpriv->ao_counter = devpriv->ao_timer; + + if (!devpriv->ao_continuous) { + /* not continuous, fixed number of samples */ + devpriv->ao_sample_count--; + if (devpriv->ao_sample_count < 0) { + usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ + /* acquistion is over, tell comedi */ s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); - /* no resubmit of the urb */ + comedi_event(dev, s); return; } } + /* transmit data to the USB bus */ - ((uint8_t *) (urb->transfer_buffer))[0] = - s->async->cmd.chanlist_len; - for (i = 0; i < s->async->cmd.chanlist_len; i++) { - short temp; - if (i >= NUMOUTCHANNELS) - break; - - /* pointer to the DA */ - datap = - (&(((uint8_t *) urb->transfer_buffer)[i * 2 + 1])); - /* get the data from comedi */ - ret = comedi_buf_get(s->async, &temp); - datap[0] = temp; - datap[1] = this_usbduxsub->dac_commands[i]; - /* printk("data[0]=%x, data[1]=%x, data[2]=%x\n", */ - /* datap[0],datap[1],datap[2]); */ + datap = urb->transfer_buffer; + len = s->async->cmd.chanlist_len; + *datap++ = len; + for (i = 0; i < len; i++) { + unsigned int chan = devpriv->dac_commands[i]; + short val; + + ret = comedi_buf_get(s->async, &val); if (ret < 0) { - dev_err(&urb->dev->dev, - "comedi: buffer underflow\n"); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_OVERFLOW; + dev_err(dev->class_dev, "buffer underflow\n"); + s->async->events |= (COMEDI_CB_EOA | + COMEDI_CB_OVERFLOW); } - /* transmit data to comedi */ + *datap++ = val; + *datap++ = chan; + devpriv->ao_readback[chan] = val; + s->async->events |= COMEDI_CB_BLOCK; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); } } + urb->transfer_buffer_length = SIZEOUTBUF; - urb->dev = this_usbduxsub->usbdev; + urb->dev = comedi_to_usb_dev(dev); urb->status = 0; - if (this_usbduxsub->ao_cmd_running) { - if (this_usbduxsub->high_speed) { - /* uframes */ - urb->interval = 8; - } else { - /* frames */ - urb->interval = 1; - } - urb->number_of_packets = 1; - urb->iso_frame_desc[0].offset = 0; - urb->iso_frame_desc[0].length = SIZEOUTBUF; - urb->iso_frame_desc[0].status = 0; - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - dev_err(&urb->dev->dev, - "comedi_: ao urb resubm failed in int-cont. " - "ret=%d", ret); - if (ret == EL2NSYNC) - dev_err(&urb->dev->dev, - "buggy USB host controller or bug in " - "IRQ handling!\n"); - - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); - /* don't do an unlink here */ - usbdux_ao_stop(this_usbduxsub, 0); - } - } -} - -static int usbduxsub_start(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - uint8_t *local_transfer_buffer; - - local_transfer_buffer = kmalloc(16, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to zero */ - local_transfer_buffer[0] = 0; - errcode = usb_control_msg(usbduxsub->usbdev, - /* create a pipe for a control transfer */ - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, - /* address of the transfer buffer */ - local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (start)\n"); - - kfree(local_transfer_buffer); - return errcode; -} - -static int usbduxsub_stop(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - uint8_t *local_transfer_buffer; - - local_transfer_buffer = kmalloc(16, GFP_KERNEL); - if (!local_transfer_buffer) - return -ENOMEM; - - /* 7f92 to one */ - local_transfer_buffer[0] = 1; - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (stop)\n"); - - kfree(local_transfer_buffer); - return errcode; -} - -static int usbduxsub_upload(struct usbduxsub *usbduxsub, - uint8_t *local_transfer_buffer, - unsigned int startAddr, unsigned int len) -{ - int errcode; - - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* brequest, firmware */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* value */ - startAddr, - /* index */ - 0x0000, - /* our local safe buffer */ - local_transfer_buffer, - /* length */ - len, - /* timeout */ - BULK_TIMEOUT); - dev_dbg(&usbduxsub->interface->dev, "comedi_: result=%d\n", errcode); - if (errcode < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: upload failed\n"); - return errcode; - } - return 0; -} - -/* the FX2LP has twice as much as the standard FX2 */ -#define FIRMWARE_MAX_LEN 0x4000 - -static int firmwareUpload(struct usbduxsub *usbduxsub, - const u8 *firmwareBinary, int sizeFirmware) -{ - int ret; - uint8_t *fwBuf; - - if (!firmwareBinary) - return 0; - - if (sizeFirmware > FIRMWARE_MAX_LEN) { - dev_err(&usbduxsub->interface->dev, - "usbduxsigma firmware binary it too large for FX2.\n"); - return -ENOMEM; - } - - /* we generate a local buffer for the firmware */ - fwBuf = kmemdup(firmwareBinary, sizeFirmware, GFP_KERNEL); - if (!fwBuf) { - dev_err(&usbduxsub->interface->dev, - "comedi_: mem alloc for firmware failed\n"); - return -ENOMEM; - } - - ret = usbduxsub_stop(usbduxsub); - if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: can not stop firmware\n"); - kfree(fwBuf); - return ret; - } - - ret = usbduxsub_upload(usbduxsub, fwBuf, 0, sizeFirmware); - if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: firmware upload failed\n"); - kfree(fwBuf); - return ret; - } - ret = usbduxsub_start(usbduxsub); + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ + urb->number_of_packets = 1; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEOUTBUF; + urb->iso_frame_desc[0].status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: can not start firmware\n"); - kfree(fwBuf); - return ret; + dev_err(dev->class_dev, + "%s: urb resubmit failed (%d)\n", + __func__, ret); + if (ret == EL2NSYNC) + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler\n"); + usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); } - kfree(fwBuf); - return 0; } -static int usbduxsub_submit_InURBs(struct usbduxsub *usbduxsub) +static int usbduxsigma_submit_urbs(struct comedi_device *dev, + struct urb **urbs, int num_urbs, + int input_urb) { - int i, errFlag; - - if (!usbduxsub) - return -EFAULT; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb; + int ret; + int i; /* Submit all URBs and start the transfer on the bus */ - for (i = 0; i < usbduxsub->numOfInBuffers; i++) { - /* in case of a resubmission after an unlink... */ - usbduxsub->urbIn[i]->interval = usbduxsub->ai_interval; - usbduxsub->urbIn[i]->context = usbduxsub->comedidev; - usbduxsub->urbIn[i]->dev = usbduxsub->usbdev; - usbduxsub->urbIn[i]->status = 0; - usbduxsub->urbIn[i]->transfer_flags = URB_ISO_ASAP; - dev_dbg(&usbduxsub->interface->dev, - "comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n", - usbduxsub->comedidev->minor, i, - (usbduxsub->urbIn[i]->context), - (usbduxsub->urbIn[i]->dev), - (usbduxsub->urbIn[i]->interval)); - errFlag = usb_submit_urb(usbduxsub->urbIn[i], GFP_ATOMIC); - if (errFlag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: ai: usb_submit_urb(%d) error %d\n", - i, errFlag); - return errFlag; - } - } - return 0; -} - -static int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub) -{ - int i, errFlag; - - if (!usbduxsub) - return -EFAULT; + for (i = 0; i < num_urbs; i++) { + urb = urbs[i]; - for (i = 0; i < usbduxsub->numOfOutBuffers; i++) { - dev_dbg(&usbduxsub->interface->dev, - "comedi_: submitting out-urb[%d]\n", i); /* in case of a resubmission after an unlink... */ - usbduxsub->urbOut[i]->context = usbduxsub->comedidev; - usbduxsub->urbOut[i]->dev = usbduxsub->usbdev; - usbduxsub->urbOut[i]->status = 0; - usbduxsub->urbOut[i]->transfer_flags = URB_ISO_ASAP; - errFlag = usb_submit_urb(usbduxsub->urbOut[i], GFP_ATOMIC); - if (errFlag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: ao: usb_submit_urb(%d) error %d\n", - i, errFlag); - return errFlag; - } + if (input_urb) + urb->interval = devpriv->ai_interval; + urb->context = dev; + urb->dev = usb; + urb->status = 0; + urb->transfer_flags = URB_ISO_ASAP; + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + return ret; } return 0; } -static int chanToInterval(int nChannels) +static int usbduxsigma_chans_to_interval(int num_chan) { - if (nChannels <= 2) - /* 4kHz */ - return 2; - if (nChannels <= 8) - /* 2kHz */ - return 4; - /* 1kHz */ - return 8; + if (num_chan <= 2) + return 2; /* 4kHz */ + if (num_chan <= 8) + return 4; /* 2kHz */ + return 8; /* 1kHz */ } -static int usbdux_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - struct usbduxsub *this_usbduxsub = dev->private; - int err = 0, i; - unsigned int tmpTimer; - - if (!(this_usbduxsub->probed)) - return -ENODEV; + struct usbduxsigma_private *devpriv = dev->private; + int high_speed = devpriv->high_speed; + int interval = usbduxsigma_chans_to_interval(cmd->chanlist_len); + int err = 0; /* Step 1 : check if triggers are trivially valid */ @@ -934,34 +551,28 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); if (cmd->scan_begin_src == TRIG_TIMER) { - if (this_usbduxsub->high_speed) { + unsigned int tmp; + + if (high_speed) { /* * In high speed mode microframes are possible. * However, during one microframe we can roughly * sample two channels. Thus, the more channels * are in the channel list the more time we need. */ - i = chanToInterval(cmd->chanlist_len); err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - (1000000 / 8 * i)); - /* now calc the real sampling rate with all the - * rounding errors */ - tmpTimer = - ((unsigned int)(cmd->scan_begin_arg / 125000)) * - 125000; + (1000000 / 8 * interval)); + + tmp = (cmd->scan_begin_arg / 125000) * 125000; } else { /* full speed */ /* 1kHz scans every USB frame */ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 1000000); - /* - * calc the real sampling rate with the rounding errors - */ - tmpTimer = ((unsigned int)(cmd->scan_begin_arg / - 1000000)) * 1000000; + + tmp = (cmd->scan_begin_arg / 1000000) * 1000000; } - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, - tmpTimer); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); } err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); @@ -976,6 +587,37 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, if (err) return 3; + /* Step 4: fix up any arguments */ + + if (high_speed) { + /* + * every 2 channels get a time window of 125us. Thus, if we + * sample all 16 channels we need 1ms. If we sample only one + * channel we need only 125us + */ + devpriv->ai_interval = interval; + devpriv->ai_timer = cmd->scan_begin_arg / (125000 * interval); + } else { + /* interval always 1ms */ + devpriv->ai_interval = 1; + devpriv->ai_timer = cmd->scan_begin_arg / 1000000; + } + if (devpriv->ai_timer < 1) + err |= -EINVAL; + + if (cmd->stop_src == TRIG_COUNT) { + /* data arrives as one packet */ + devpriv->ai_sample_count = cmd->stop_arg; + devpriv->ai_continuous = 0; + } else { + /* continuous acquisition */ + devpriv->ai_continuous = 1; + devpriv->ai_sample_count = 0; + } + + if (err) + return 4; + return 0; } @@ -993,536 +635,278 @@ static void create_adc_command(unsigned int chan, (*muxsg1) = (*muxsg1) | (1 << (chan-8)); } +static int usbbuxsigma_send_cmd(struct comedi_device *dev, int cmd_type) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + int nsent; -/* bulk transfers to usbdux */ - -#define SENDADCOMMANDS 0 -#define SENDDACOMMANDS 1 -#define SENDDIOCONFIGCOMMAND 2 -#define SENDDIOBITSCOMMAND 3 -#define SENDSINGLEAD 4 -#define SENDPWMON 7 -#define SENDPWMOFF 8 + devpriv->dux_commands[0] = cmd_type; -static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type) -{ - int result, nsent; - - this_usbduxsub->dux_commands[0] = cmd_type; -#ifdef NOISY_DUX_DEBUGBUG - printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ", - this_usbduxsub->comedidev->minor); - for (result = 0; result < SIZEOFDUXBUFFER; result++) - printk(" %02x", this_usbduxsub->dux_commands[result]); - printk("\n"); -#endif - result = usb_bulk_msg(this_usbduxsub->usbdev, - usb_sndbulkpipe(this_usbduxsub->usbdev, - COMMAND_OUT_EP), - this_usbduxsub->dux_commands, SIZEOFDUXBUFFER, - &nsent, BULK_TIMEOUT); - if (result < 0) - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "could not transmit dux_command to the usb-device, " - "err=%d\n", this_usbduxsub->comedidev->minor, result); - - return result; + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, USBDUXSIGMA_CMD_OUT_EP), + devpriv->dux_commands, SIZEOFDUXBUFFER, + &nsent, BULK_TIMEOUT); } -static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command) +static int usbduxsigma_receive_cmd(struct comedi_device *dev, int command) { - int result = (-EFAULT); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; int nrec; + int ret; int i; for (i = 0; i < RETRIES; i++) { - result = usb_bulk_msg(this_usbduxsub->usbdev, - usb_rcvbulkpipe(this_usbduxsub->usbdev, - COMMAND_IN_EP), - this_usbduxsub->insnBuffer, SIZEINSNBUF, - &nrec, BULK_TIMEOUT); - if (result < 0) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "insn: USB error %d " - "while receiving DUX command" - "\n", this_usbduxsub->comedidev->minor, - result); - return result; - } - if (this_usbduxsub->insnBuffer[0] == command) - return result; + ret = usb_bulk_msg(usb, + usb_rcvbulkpipe(usb, USBDUXSIGMA_CMD_IN_EP), + devpriv->insn_buf, SIZEINSNBUF, + &nrec, BULK_TIMEOUT); + if (ret < 0) + return ret; + + if (devpriv->insn_buf[0] == command) + return 0; } - /* this is only reached if the data has been requested a couple of - * times */ - dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: " - "wrong data returned from firmware: want %d, got %d.\n", - this_usbduxsub->comedidev->minor, command, - this_usbduxsub->insnBuffer[0]); + /* + * This is only reached if the data has been requested a + * couple of times and the command was not received. + */ return -EFAULT; } -static int usbdux_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) +static int usbduxsigma_ai_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trignum) { + struct usbduxsigma_private *devpriv = dev->private; int ret; - struct usbduxsub *this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig\n", dev->minor); - - if (trignum != 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig: invalid trignum\n", - dev->minor); - up(&this_usbduxsub->sem); + if (trignum != 0) return -EINVAL; - } - if (!(this_usbduxsub->ai_cmd_running)) { - this_usbduxsub->ai_cmd_running = 1; - ret = usbduxsub_submit_InURBs(this_usbduxsub); + + down(&devpriv->sem); + if (!devpriv->ai_cmd_running) { + ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig: " - "urbSubmit: err=%d\n", dev->minor, ret); - this_usbduxsub->ai_cmd_running = 0; - up(&this_usbduxsub->sem); + up(&devpriv->sem); return ret; } + devpriv->ai_cmd_running = 1; s->async->inttrig = NULL; - } else { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ai_inttrig but acqu is already running\n", - dev->minor); } - up(&this_usbduxsub->sem); + up(&devpriv->sem); + return 1; } -static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int usbduxsigma_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { + struct usbduxsigma_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int chan; - int i, ret; - struct usbduxsub *this_usbduxsub = dev->private; - int result; + unsigned int len = cmd->chanlist_len; uint8_t muxsg0 = 0; uint8_t muxsg1 = 0; uint8_t sysred = 0; + int ret; + int i; - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_cmd\n", dev->minor); - - /* block other CPUs from starting an ai_cmd */ - down(&this_usbduxsub->sem); + down(&devpriv->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ai_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "ai_cmd not possible. Another ai_cmd is running.\n", - dev->minor); - up(&this_usbduxsub->sem); - return -EBUSY; - } /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; + for (i = 0; i < len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); - /* first the number of channels per time step */ - this_usbduxsub->dux_commands[1] = cmd->chanlist_len; - - /* CONFIG0 */ - this_usbduxsub->dux_commands[2] = 0x12; - - /* CONFIG1: 23kHz sampling rate, delay = 0us, */ - this_usbduxsub->dux_commands[3] = 0x03; - - /* CONFIG3: differential channels off */ - this_usbduxsub->dux_commands[4] = 0x00; - - for (i = 0; i < cmd->chanlist_len; i++) { - chan = CR_CHAN(cmd->chanlist[i]); create_adc_command(chan, &muxsg0, &muxsg1); - if (i >= NUMCHANNELS) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: channel list too long\n", - dev->minor); - break; - } - } - this_usbduxsub->dux_commands[5] = muxsg0; - this_usbduxsub->dux_commands[6] = muxsg1; - this_usbduxsub->dux_commands[7] = sysred; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi %d: sending commands to the usb device: size=%u\n", - dev->minor, NUMCHANNELS); - - result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS); - if (result < 0) { - up(&this_usbduxsub->sem); - return result; } - if (this_usbduxsub->high_speed) { - /* - * every 2 channels get a time window of 125us. Thus, if we - * sample all 16 channels we need 1ms. If we sample only one - * channel we need only 125us - */ - this_usbduxsub->ai_interval = - chanToInterval(cmd->chanlist_len); - this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 * - (this_usbduxsub-> - ai_interval)); - } else { - /* interval always 1ms */ - this_usbduxsub->ai_interval = 1; - this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000; - } - if (this_usbduxsub->ai_timer < 1) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: " - "timer=%d, scan_begin_arg=%d. " - "Not properly tested by cmdtest?\n", dev->minor, - this_usbduxsub->ai_timer, cmd->scan_begin_arg); - up(&this_usbduxsub->sem); - return -EINVAL; - } - this_usbduxsub->ai_counter = this_usbduxsub->ai_timer; + devpriv->dux_commands[1] = len; /* num channels per time step */ + devpriv->dux_commands[2] = 0x12; /* CONFIG0 */ + devpriv->dux_commands[3] = 0x03; /* CONFIG1: 23kHz sample, delay 0us */ + devpriv->dux_commands[4] = 0x00; /* CONFIG3: diff. channels off */ + devpriv->dux_commands[5] = muxsg0; + devpriv->dux_commands[6] = muxsg1; + devpriv->dux_commands[7] = sysred; - if (cmd->stop_src == TRIG_COUNT) { - /* data arrives as one packet */ - this_usbduxsub->ai_sample_count = cmd->stop_arg; - this_usbduxsub->ai_continuous = 0; - } else { - /* continuous acquisition */ - this_usbduxsub->ai_continuous = 1; - this_usbduxsub->ai_sample_count = 0; + ret = usbbuxsigma_send_cmd(dev, USBBUXSIGMA_AD_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; } + devpriv->ai_counter = devpriv->ai_timer; + if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ - this_usbduxsub->ai_cmd_running = 1; - ret = usbduxsub_submit_InURBs(this_usbduxsub); + ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); if (ret < 0) { - this_usbduxsub->ai_cmd_running = 0; - /* fixme: unlink here?? */ - up(&this_usbduxsub->sem); + up(&devpriv->sem); return ret; } s->async->inttrig = NULL; - } else { - /* TRIG_INT */ - /* don't enable the acquision operation */ - /* wait for an internal signal */ - s->async->inttrig = usbdux_ai_inttrig; + devpriv->ai_cmd_running = 1; + } else { /* TRIG_INT */ + /* wait for an internal signal and submit the urbs later */ + s->async->inttrig = usbduxsigma_ai_inttrig; } - up(&this_usbduxsub->sem); + + up(&devpriv->sem); + return 0; } -/* Mode 0 is used to get a single conversion on demand */ -static int usbdux_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int usbduxsigma_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int i; - int32_t one = 0; - int chan; - int err; - struct usbduxsub *this_usbduxsub = dev->private; + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); uint8_t muxsg0 = 0; uint8_t muxsg1 = 0; uint8_t sysred = 0; + int ret; + int i; - if (!this_usbduxsub) - return 0; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n", - dev->minor, insn->n, insn->subdev); - - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ai_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ai_insn_read not possible. " - "Async Command is running.\n", dev->minor); - up(&this_usbduxsub->sem); - return 0; + down(&devpriv->sem); + if (devpriv->ai_cmd_running) { + up(&devpriv->sem); + return -EBUSY; } - /* sample one channel */ - /* CONFIG0: chopper on */ - this_usbduxsub->dux_commands[1] = 0x16; - - /* CONFIG1: 2kHz sampling rate */ - this_usbduxsub->dux_commands[2] = 0x80; - - /* CONFIG3: differential channels off */ - this_usbduxsub->dux_commands[3] = 0x00; - - chan = CR_CHAN(insn->chanspec); create_adc_command(chan, &muxsg0, &muxsg1); - this_usbduxsub->dux_commands[4] = muxsg0; - this_usbduxsub->dux_commands[5] = muxsg1; - this_usbduxsub->dux_commands[6] = sysred; + /* Mode 0 is used to get a single conversion on demand */ + devpriv->dux_commands[1] = 0x16; /* CONFIG0: chopper on */ + devpriv->dux_commands[2] = 0x80; /* CONFIG1: 2kHz sampling rate */ + devpriv->dux_commands[3] = 0x00; /* CONFIG3: diff. channels off */ + devpriv->dux_commands[4] = muxsg0; + devpriv->dux_commands[5] = muxsg1; + devpriv->dux_commands[6] = sysred; /* adc commands */ - err = send_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; } for (i = 0; i < insn->n; i++) { - err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) { - up(&this_usbduxsub->sem); - return 0; - } - /* 32 bits big endian from the A/D converter */ - one = be32_to_cpu(*((int32_t *) - ((this_usbduxsub->insnBuffer)+1))); - /* mask out the status byte */ - one = one & 0x00ffffff; - /* turn it into an unsigned integer */ - one = one ^ 0x00800000; - data[i] = one; - } - up(&this_usbduxsub->sem); - return i; -} - - - + int32_t val; -static int usbdux_getstatusinfo(struct comedi_device *dev, int chan) -{ - struct usbduxsub *this_usbduxsub = dev->private; - uint8_t sysred = 0; - uint32_t one; - int err; - - if (!this_usbduxsub) - return 0; + ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; + } - if (this_usbduxsub->ai_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: status read not possible. " - "Async Command is running.\n", dev->minor); - return 0; - } + /* 32 bits big endian from the A/D converter */ + val = be32_to_cpu(*((int32_t *)((devpriv->insn_buf) + 1))); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ - /* CONFIG0 */ - this_usbduxsub->dux_commands[1] = 0x12; - - /* CONFIG1: 2kHz sampling rate */ - this_usbduxsub->dux_commands[2] = 0x80; - - /* CONFIG3: differential channels off */ - this_usbduxsub->dux_commands[3] = 0x00; - - if (chan == 1) { - /* ADC offset */ - sysred = sysred | 1; - } else if (chan == 2) { - /* VCC */ - sysred = sysred | 4; - } else if (chan == 3) { - /* temperature */ - sysred = sysred | 8; - } else if (chan == 4) { - /* gain */ - sysred = sysred | 16; - } else if (chan == 5) { - /* ref */ - sysred = sysred | 32; + data[i] = val; } + up(&devpriv->sem); - this_usbduxsub->dux_commands[4] = 0; - this_usbduxsub->dux_commands[5] = 0; - this_usbduxsub->dux_commands[6] = sysred; - - /* adc commands */ - err = send_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) - return err; - - err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) - return err; - - /* 32 bits big endian from the A/D converter */ - one = be32_to_cpu(*((int32_t *)((this_usbduxsub->insnBuffer)+1))); - /* mask out the status byte */ - one = one & 0x00ffffff; - one = one ^ 0x00800000; - - return (int)one; + return insn->n; } - - - - - -/************************************/ -/* analog out */ - -static int usbdux_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int usbduxsigma_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); - struct usbduxsub *this_usbduxsub = dev->private; - - if (!this_usbduxsub) - return -EFAULT; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); for (i = 0; i < insn->n; i++) - data[i] = this_usbduxsub->outBuffer[chan]; + data[i] = devpriv->ao_readback[chan]; + up(&devpriv->sem); - up(&this_usbduxsub->sem); - return i; + return insn->n; } -static int usbdux_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int usbduxsigma_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int i, err; - int chan = CR_CHAN(insn->chanspec); - struct usbduxsub *this_usbduxsub = dev->private; - - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write\n", dev->minor); + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; + int i; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ao_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write: " - "ERROR: asynchronous ao_cmd is running\n", dev->minor); - up(&this_usbduxsub->sem); - return 0; + down(&devpriv->sem); + if (devpriv->ao_cmd_running) { + up(&devpriv->sem); + return -EBUSY; } for (i = 0; i < insn->n; i++) { - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n", - dev->minor, chan, i, data[i]); - - /* number of channels: 1 */ - this_usbduxsub->dux_commands[1] = 1; - /* channel number */ - this_usbduxsub->dux_commands[2] = data[i]; - this_usbduxsub->outBuffer[chan] = data[i]; - this_usbduxsub->dux_commands[3] = chan; - err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; + devpriv->dux_commands[1] = 1; /* num channels */ + devpriv->dux_commands[2] = data[i]; /* value */ + devpriv->dux_commands[3] = chan; /* channel number */ + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_DA_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; } + devpriv->ao_readback[chan] = data[i]; } - up(&this_usbduxsub->sem); + up(&devpriv->sem); - return i; + return insn->n; } -static int usbdux_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) +static int usbduxsigma_ao_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trignum) { + struct usbduxsigma_private *devpriv = dev->private; int ret; - struct usbduxsub *this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - - down(&this_usbduxsub->sem); + if (trignum != 0) + return -EINVAL; - if (!(this_usbduxsub->probed)) { - ret = -ENODEV; - goto out; - } - if (trignum != 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_inttrig: invalid trignum\n", - dev->minor); - ret = -EINVAL; - goto out; - } - if (!(this_usbduxsub->ao_cmd_running)) { - this_usbduxsub->ao_cmd_running = 1; - ret = usbduxsub_submit_OutURBs(this_usbduxsub); + down(&devpriv->sem); + if (!devpriv->ao_cmd_running) { + ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_inttrig: submitURB: " - "err=%d\n", dev->minor, ret); - this_usbduxsub->ao_cmd_running = 0; - goto out; + up(&devpriv->sem); + return ret; } + devpriv->ao_cmd_running = 1; s->async->inttrig = NULL; - } else { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ao_inttrig but acqu is already running.\n", - dev->minor); } - ret = 1; -out: - up(&this_usbduxsub->sem); - return ret; + up(&devpriv->sem); + + return 1; } -static int usbdux_ao_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbduxsigma_private *devpriv = dev->private; int err = 0; + int high_speed; unsigned int flags; - if (!this_usbduxsub) - return -EFAULT; - - if (!(this_usbduxsub->probed)) - return -ENODEV; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_cmdtest\n", dev->minor); + /* high speed conversions are not used yet */ + high_speed = 0; /* (devpriv->high_speed) */ /* Step 1 : check if triggers are trivially valid */ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - if (0) { /* (this_usbduxsub->high_speed) */ + if (high_speed) { /* * start immediately a new scan * the sampling rate is set by the coversion rate @@ -1538,8 +922,10 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - if (err) + if (err) { + up(&devpriv->sem); return 1; + } /* Step 2a : make sure trigger sources are unique */ @@ -1578,272 +964,186 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, if (err) return 3; - return 0; -} - -static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct comedi_cmd *cmd = &s->async->cmd; - unsigned int chan, gain; - int i, ret; - struct usbduxsub *this_usbduxsub = dev->private; - - if (!this_usbduxsub) - return -EFAULT; + /* Step 4: fix up any arguments */ - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s\n", dev->minor, __func__); - - /* set current channel of the running acquisition to zero */ - s->async->cur_chan = 0; - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - gain = CR_RANGE(cmd->chanlist[i]); - if (i >= NUMOUTCHANNELS) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: %s: channel list too long\n", - dev->minor, __func__); - break; - } - this_usbduxsub->dac_commands[i] = chan; - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: dac command for ch %d is %x\n", - dev->minor, i, this_usbduxsub->dac_commands[i]); - } - - /* we count in steps of 1ms (125us) */ - /* 125us mode not used yet */ - if (0) { /* (this_usbduxsub->high_speed) */ - /* 125us */ + /* we count in timer steps */ + if (high_speed) { /* timing of the conversion itself: every 125 us */ - this_usbduxsub->ao_timer = cmd->convert_arg / 125000; + devpriv->ao_timer = cmd->convert_arg / 125000; } else { - /* 1ms */ - /* timing of the scan: we get all channels at once */ - this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000; - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: scan_begin_src=%d, scan_begin_arg=%d, " - "convert_src=%d, convert_arg=%d\n", dev->minor, - cmd->scan_begin_src, cmd->scan_begin_arg, - cmd->convert_src, cmd->convert_arg); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_timer=%d (ms)\n", - dev->minor, this_usbduxsub->ao_timer); - if (this_usbduxsub->ao_timer < 1) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux: ao_timer=%d, " - "scan_begin_arg=%d. " - "Not properly tested by cmdtest?\n", - dev->minor, this_usbduxsub->ao_timer, - cmd->scan_begin_arg); - up(&this_usbduxsub->sem); - return -EINVAL; - } + /* + * timing of the scan: every 1ms + * we get all channels at once + */ + devpriv->ao_timer = cmd->scan_begin_arg / 1000000; } - this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; + if (devpriv->ao_timer < 1) + err |= -EINVAL; if (cmd->stop_src == TRIG_COUNT) { - /* not continuous */ - /* counter */ - /* high speed also scans everything at once */ - if (0) { /* (this_usbduxsub->high_speed) */ - this_usbduxsub->ao_sample_count = - (cmd->stop_arg) * (cmd->scan_end_arg); + /* not continuous, use counter */ + if (high_speed) { + /* high speed also scans everything at once */ + devpriv->ao_sample_count = cmd->stop_arg * + cmd->scan_end_arg; } else { - /* there's no scan as the scan has been */ - /* perf inside the FX2 */ - /* data arrives as one packet */ - this_usbduxsub->ao_sample_count = cmd->stop_arg; + /* + * There's no scan as the scan has been + * handled inside the FX2. Data arrives as + * one packet. + */ + devpriv->ao_sample_count = cmd->stop_arg; } - this_usbduxsub->ao_continuous = 0; + devpriv->ao_continuous = 0; } else { /* continuous acquisition */ - this_usbduxsub->ao_continuous = 1; - this_usbduxsub->ao_sample_count = 0; + devpriv->ao_continuous = 1; + devpriv->ao_sample_count = 0; } + if (err) + return 4; + + return 0; +} + +static int usbduxsigma_ao_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; + int i; + + down(&devpriv->sem); + + /* set current channel of the running acquisition to zero */ + s->async->cur_chan = 0; + for (i = 0; i < cmd->chanlist_len; ++i) + devpriv->dac_commands[i] = CR_CHAN(cmd->chanlist[i]); + + devpriv->ao_counter = devpriv->ao_timer; + if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ - this_usbduxsub->ao_cmd_running = 1; - ret = usbduxsub_submit_OutURBs(this_usbduxsub); + ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); if (ret < 0) { - this_usbduxsub->ao_cmd_running = 0; - /* fixme: unlink here?? */ - up(&this_usbduxsub->sem); + up(&devpriv->sem); return ret; } s->async->inttrig = NULL; - } else { - /* TRIG_INT */ - /* submit the urbs later */ - /* wait for an internal signal */ - s->async->inttrig = usbdux_ao_inttrig; + devpriv->ao_cmd_running = 1; + } else { /* TRIG_INT */ + /* wait for an internal signal and submit the urbs later */ + s->async->inttrig = usbduxsigma_ao_inttrig; } - up(&this_usbduxsub->sem); + up(&devpriv->sem); + return 0; } -static int usbdux_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int usbduxsigma_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); - - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask = 1 << chan; switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; /* 1 means Out */ + s->io_bits |= mask; break; case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); + s->io_bits &= ~mask; break; case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; + data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; break; default: return -EINVAL; break; } - /* we don't tell the firmware here as it would take 8 frames */ - /* to submit the information. We do it in the insn_bits. */ + + /* + * We don't tell the firmware here as it would take 8 frames + * to submit the information. We do it in the (*insn_bits). + */ return insn->n; } -static int usbdux_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int usbduxsigma_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct usbduxsigma_private *devpriv = dev->private; + unsigned int mask = data[0]; + unsigned int bits = data[1]; + int ret; - struct usbduxsub *this_usbduxsub = dev->private; - int err; + down(&devpriv->sem); - if (!this_usbduxsub) - return -EFAULT; + s->state &= ~mask; + s->state |= (bits & mask); - down(&this_usbduxsub->sem); + devpriv->dux_commands[1] = s->io_bits & 0xff; + devpriv->dux_commands[4] = s->state & 0xff; + devpriv->dux_commands[2] = (s->io_bits >> 8) & 0xff; + devpriv->dux_commands[5] = (s->state >> 8) & 0xff; + devpriv->dux_commands[3] = (s->io_bits >> 16) & 0xff; + devpriv->dux_commands[6] = (s->state >> 16) & 0xff; - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_DIO_BITS_CMD); + if (ret < 0) + goto done; + ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_DIO_BITS_CMD); + if (ret < 0) + goto done; - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* The commands are 8 bits wide */ - this_usbduxsub->dux_commands[1] = (s->io_bits) & 0x000000FF; - this_usbduxsub->dux_commands[4] = (s->state) & 0x000000FF; - this_usbduxsub->dux_commands[2] = ((s->io_bits) & 0x0000FF00) >> 8; - this_usbduxsub->dux_commands[5] = ((s->state) & 0x0000FF00) >> 8; - this_usbduxsub->dux_commands[3] = ((s->io_bits) & 0x00FF0000) >> 16; - this_usbduxsub->dux_commands[6] = ((s->state) & 0x00FF0000) >> 16; - - /* This command also tells the firmware to return */ - /* the digital input lines */ - err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } - err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } + s->state = devpriv->insn_buf[1] | + (devpriv->insn_buf[2] << 8) | + (devpriv->insn_buf[3] << 16); - data[1] = (((unsigned int)(this_usbduxsub->insnBuffer[1]))&0xff) | - ((((unsigned int)(this_usbduxsub->insnBuffer[2]))&0xff) << 8) | - ((((unsigned int)(this_usbduxsub->insnBuffer[3]))&0xff) << 16); + data[1] = s->state; + ret = insn->n; - s->state = data[1]; +done: + up(&devpriv->sem); - up(&this_usbduxsub->sem); - return insn->n; + return ret; } -/***********************************/ -/* PWM */ - -static int usbduxsub_unlink_PwmURBs(struct usbduxsub *usbduxsub_tmp) +static void usbduxsigma_pwm_stop(struct comedi_device *dev, int do_unlink) { - int err = 0; + struct usbduxsigma_private *devpriv = dev->private; - if (usbduxsub_tmp && usbduxsub_tmp->urbPwm) { - if (usbduxsub_tmp->urbPwm) - usb_kill_urb(usbduxsub_tmp->urbPwm); - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: unlinked PwmURB: res=%d\n", err); + if (do_unlink) { + if (devpriv->pwm_urb) + usb_kill_urb(devpriv->pwm_urb); } - return err; -} - -/* This cancels a running acquisition operation - * in any context. - */ -static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink) -{ - int ret = 0; - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__); - if (do_unlink) - ret = usbduxsub_unlink_PwmURBs(this_usbduxsub); - - this_usbduxsub->pwm_cmd_running = 0; - - return ret; + devpriv->pwm_cmd_running = 0; } -/* force unlink - is called by comedi */ -static int usbdux_pwm_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int usbduxsigma_pwm_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub = dev->private; - int res = 0; + struct usbduxsigma_private *devpriv = dev->private; /* unlink only if it is really running */ - res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running); + usbduxsigma_pwm_stop(dev, devpriv->pwm_cmd_running); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi %d: sending pwm off command to the usb device.\n", - dev->minor); - res = send_dux_commands(this_usbduxsub, SENDPWMOFF); - if (res < 0) - return res; - - return res; + return usbbuxsigma_send_cmd(dev, USBDUXSIGMA_PWM_OFF_CMD); } -static void usbduxsub_pwm_irq(struct urb *urb) +static void usbduxsigma_pwm_urb_complete(struct urb *urb) { + struct comedi_device *dev = urb->context; + struct usbduxsigma_private *devpriv = dev->private; int ret; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* printk(KERN_DEBUG "PWM: IRQ\n"); */ - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - - s = &this_comedidev->subdevices[SUBDEV_DA]; switch (urb->status) { case 0: @@ -1854,260 +1154,180 @@ static void usbduxsub_pwm_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: - /* - * after an unlink command, unplug, ... etc - * no unlink needed here. Already shutting down. - */ - if (this_usbduxsub->pwm_cmd_running) - usbdux_pwm_stop(this_usbduxsub, 0); - + /* happens after an unlink command */ + if (devpriv->pwm_cmd_running) + usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */ return; default: /* a real error */ - if (this_usbduxsub->pwm_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi_: Non-zero urb status received in " - "pwm intr context: %d\n", urb->status); - usbdux_pwm_stop(this_usbduxsub, 0); + if (devpriv->pwm_cmd_running) { + dev_err(dev->class_dev, + "%s: non-zero urb status (%d)\n", + __func__, urb->status); + usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */ } return; } - /* are we actually running? */ - if (!(this_usbduxsub->pwm_cmd_running)) + if (!devpriv->pwm_cmd_running) return; - urb->transfer_buffer_length = this_usbduxsub->sizePwmBuf; - urb->dev = this_usbduxsub->usbdev; + urb->transfer_buffer_length = devpriv->pwm_buf_sz; + urb->dev = comedi_to_usb_dev(dev); urb->status = 0; - if (this_usbduxsub->pwm_cmd_running) { - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi_: pwm urb resubm failed in int-cont. " - "ret=%d", ret); - if (ret == EL2NSYNC) - dev_err(&this_usbduxsub->interface->dev, - "buggy USB host controller or bug in " - "IRQ handling!\n"); - - /* don't do an unlink here */ - usbdux_pwm_stop(this_usbduxsub, 0); - } + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", + __func__, ret); + if (ret == EL2NSYNC) + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler\n"); + usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */ } } -static int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub) +static int usbduxsigma_submit_pwm_urb(struct comedi_device *dev) { - int errFlag; - - if (!usbduxsub) - return -EFAULT; - - dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n"); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb = devpriv->pwm_urb; /* in case of a resubmission after an unlink... */ - usb_fill_bulk_urb(usbduxsub->urbPwm, - usbduxsub->usbdev, - usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP), - usbduxsub->urbPwm->transfer_buffer, - usbduxsub->sizePwmBuf, usbduxsub_pwm_irq, - usbduxsub->comedidev); - - errFlag = usb_submit_urb(usbduxsub->urbPwm, GFP_ATOMIC); - if (errFlag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: usbduxsigma: pwm: usb_submit_urb error %d\n", - errFlag); - return errFlag; - } - return 0; + usb_fill_bulk_urb(urb, + usb, usb_sndbulkpipe(usb, USBDUXSIGMA_PWM_OUT_EP), + urb->transfer_buffer, devpriv->pwm_buf_sz, + usbduxsigma_pwm_urb_complete, dev); + + return usb_submit_urb(urb, GFP_ATOMIC); } -static int usbdux_pwm_period(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int period) +static int usbduxsigma_pwm_period(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int period) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbduxsigma_private *devpriv = dev->private; int fx2delay = 255; if (period < MIN_PWM_PERIOD) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: illegal period setting for pwm.\n", - dev->minor); return -EAGAIN; } else { - fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6; - if (fx2delay > 255) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: period %d for pwm is too low.\n", - dev->minor, period); + fx2delay = (period / (6 * 512 * 1000 / 33)) - 6; + if (fx2delay > 255) return -EAGAIN; - } } - this_usbduxsub->pwmDelay = fx2delay; - this_usbduxsub->pwmPeriod = period; - dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n", - __func__, period, fx2delay); + devpriv->pwm_delay = fx2delay; + devpriv->pwm_period = period; return 0; } -/* is called from insn so there's no need to do all the sanity checks */ -static int usbdux_pwm_start(struct comedi_device *dev, - struct comedi_subdevice *s) +static int usbduxsigma_pwm_start(struct comedi_device *dev, + struct comedi_subdevice *s) { - int ret, i; - struct usbduxsub *this_usbduxsub = dev->private; - - dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n", - dev->minor, __func__); + struct usbduxsigma_private *devpriv = dev->private; + int ret; - if (this_usbduxsub->pwm_cmd_running) { - /* already running */ + if (devpriv->pwm_cmd_running) return 0; - } - this_usbduxsub->dux_commands[1] = ((uint8_t) this_usbduxsub->pwmDelay); - ret = send_dux_commands(this_usbduxsub, SENDPWMON); + devpriv->dux_commands[1] = devpriv->pwm_delay; + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_PWM_ON_CMD); if (ret < 0) return ret; - /* initialise the buffer */ - for (i = 0; i < this_usbduxsub->sizePwmBuf; i++) - ((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0; + memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz); - this_usbduxsub->pwm_cmd_running = 1; - ret = usbduxsub_submit_PwmURBs(this_usbduxsub); - if (ret < 0) { - this_usbduxsub->pwm_cmd_running = 0; + ret = usbduxsigma_submit_pwm_urb(dev); + if (ret < 0) return ret; - } + devpriv->pwm_cmd_running = 1; + return 0; } -/* generates the bit pattern for PWM with the optional sign bit */ -static int usbdux_pwm_pattern(struct comedi_device *dev, - struct comedi_subdevice *s, int channel, - unsigned int value, unsigned int sign) +static int usbduxsigma_pwm_pattern(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int value, + unsigned int sign) { - struct usbduxsub *this_usbduxsub = dev->private; - int i, szbuf; - char *pBuf; - char pwm_mask; - char sgn_mask; - char c; - - if (!this_usbduxsub) - return -EFAULT; - - /* this is the DIO bit which carries the PWM data */ - pwm_mask = (1 << channel); - /* this is the DIO bit which carries the optional direction bit */ - sgn_mask = (16 << channel); - /* this is the buffer which will be filled with the with bit */ - /* pattern for one period */ - szbuf = this_usbduxsub->sizePwmBuf; - pBuf = (char *)(this_usbduxsub->urbPwm->transfer_buffer); + struct usbduxsigma_private *devpriv = dev->private; + char pwm_mask = (1 << chan); /* DIO bit for the PWM data */ + char sgn_mask = (16 << chan); /* DIO bit for the sign */ + char *buf = (char *)(devpriv->pwm_urb->transfer_buffer); + int szbuf = devpriv->pwm_buf_sz; + int i; + for (i = 0; i < szbuf; i++) { - c = *pBuf; - /* reset bits */ - c = c & (~pwm_mask); - /* set the bit as long as the index is lower than the value */ + char c = *buf; + + c &= ~pwm_mask; if (i < value) - c = c | pwm_mask; - /* set the optional sign bit for a relay */ - if (!sign) { - /* positive value */ - c = c & (~sgn_mask); - } else { - /* negative value */ - c = c | sgn_mask; - } - *(pBuf++) = c; + c |= pwm_mask; + if (!sign) + c &= ~sgn_mask; + else + c |= sgn_mask; + *buf++ = c; } return 1; } -static int usbdux_pwm_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int usbduxsigma_pwm_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); - if (!this_usbduxsub) - return -EFAULT; - - if ((insn->n) != 1) { - /* - * doesn't make sense to have more than one value here because - * it would just overwrite the PWM buffer a couple of times - */ + /* + * It doesn't make sense to support more than one value here + * because it would just overwrite the PWM buffer. + */ + if (insn->n != 1) return -EINVAL; - } /* - * the sign is set via a special INSN only, this gives us 8 bits for - * normal operation - * relay sign 0 by default + * The sign is set via a special INSN only, this gives us 8 bits + * for normal operation, sign is 0 by default. */ - return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0); + return usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0); } -static int usbdux_pwm_read(struct comedi_device *x1, - struct comedi_subdevice *x2, struct comedi_insn *x3, - unsigned int *x4) +static int usbduxsigma_pwm_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* not needed */ - return -EINVAL; -}; + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); -/* switches on/off PWM */ -static int usbdux_pwm_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct usbduxsub *this_usbduxsub = dev->private; switch (data[0]) { case INSN_CONFIG_ARM: - /* switch it on */ - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: pwm on\n", dev->minor, __func__); /* * if not zero the PWM is limited to a certain time which is * not supported here */ if (data[1] != 0) return -EINVAL; - return usbdux_pwm_start(dev, s); + return usbduxsigma_pwm_start(dev, s); case INSN_CONFIG_DISARM: - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: pwm off\n", dev->minor, __func__); - return usbdux_pwm_cancel(dev, s); + return usbduxsigma_pwm_cancel(dev, s); case INSN_CONFIG_GET_PWM_STATUS: - /* - * to check if the USB transmission has failed or in case PWM - * was limited to n cycles to check if it has terminated - */ - data[1] = this_usbduxsub->pwm_cmd_running; + data[1] = devpriv->pwm_cmd_running; return 0; case INSN_CONFIG_PWM_SET_PERIOD: - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: setting period\n", dev->minor, - __func__); - return usbdux_pwm_period(dev, s, data[1]); + return usbduxsigma_pwm_period(dev, s, data[1]); case INSN_CONFIG_PWM_GET_PERIOD: - data[1] = this_usbduxsub->pwmPeriod; + data[1] = devpriv->pwm_period; return 0; case INSN_CONFIG_PWM_SET_H_BRIDGE: - /* value in the first byte and the sign in the second for a - relay */ - return usbdux_pwm_pattern(dev, s, - /* the channel number */ - CR_CHAN(insn->chanspec), - /* actual PWM data */ - data[1], - /* just a sign */ - (data[2] != 0)); + /* + * data[1] = value + * data[2] = sign (for a relay) + */ + return usbduxsigma_pwm_pattern(dev, s, chan, + data[1], (data[2] != 0)); case INSN_CONFIG_PWM_GET_H_BRIDGE: /* values are not kept in this driver, nothing to return */ return -EINVAL; @@ -2115,542 +1335,412 @@ static int usbdux_pwm_config(struct comedi_device *dev, return -EINVAL; } -/* end of PWM */ -/*****************************************************************/ - -static void tidy_up(struct usbduxsub *usbduxsub_tmp) +static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) { - int i; + struct usbduxsigma_private *devpriv = dev->private; + uint8_t sysred; + uint32_t val; + int ret; - if (!usbduxsub_tmp) - return; - dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n"); + switch (chan) { + default: + case 0: + sysred = 0; /* ADC zero */ + break; + case 1: + sysred = 1; /* ADC offset */ + break; + case 2: + sysred = 4; /* VCC */ + break; + case 3: + sysred = 8; /* temperature */ + break; + case 4: + sysred = 16; /* gain */ + break; + case 5: + sysred = 32; /* ref */ + break; + } - /* shows the usb subsystem that the driver is down */ - if (usbduxsub_tmp->interface) - usb_set_intfdata(usbduxsub_tmp->interface, NULL); + devpriv->dux_commands[1] = 0x12; /* CONFIG0 */ + devpriv->dux_commands[2] = 0x80; /* CONFIG1: 2kHz sampling rate */ + devpriv->dux_commands[3] = 0x00; /* CONFIG3: diff. channels off */ + devpriv->dux_commands[4] = 0; + devpriv->dux_commands[5] = 0; + devpriv->dux_commands[6] = sysred; + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) + return ret; - usbduxsub_tmp->probed = 0; + ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) + return ret; - if (usbduxsub_tmp->urbIn) { - if (usbduxsub_tmp->ai_cmd_running) { - usbduxsub_tmp->ai_cmd_running = 0; - usbduxsub_unlink_InURBs(usbduxsub_tmp); - } - for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) { - kfree(usbduxsub_tmp->urbIn[i]->transfer_buffer); - usbduxsub_tmp->urbIn[i]->transfer_buffer = NULL; - usb_kill_urb(usbduxsub_tmp->urbIn[i]); - usb_free_urb(usbduxsub_tmp->urbIn[i]); - usbduxsub_tmp->urbIn[i] = NULL; - } - kfree(usbduxsub_tmp->urbIn); - usbduxsub_tmp->urbIn = NULL; - } - if (usbduxsub_tmp->urbOut) { - if (usbduxsub_tmp->ao_cmd_running) { - usbduxsub_tmp->ao_cmd_running = 0; - usbduxsub_unlink_OutURBs(usbduxsub_tmp); - } - for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) { - if (usbduxsub_tmp->urbOut[i]->transfer_buffer) { - kfree(usbduxsub_tmp-> - urbOut[i]->transfer_buffer); - usbduxsub_tmp->urbOut[i]->transfer_buffer = - NULL; - } - if (usbduxsub_tmp->urbOut[i]) { - usb_kill_urb(usbduxsub_tmp->urbOut[i]); - usb_free_urb(usbduxsub_tmp->urbOut[i]); - usbduxsub_tmp->urbOut[i] = NULL; - } - } - kfree(usbduxsub_tmp->urbOut); - usbduxsub_tmp->urbOut = NULL; - } - if (usbduxsub_tmp->urbPwm) { - if (usbduxsub_tmp->pwm_cmd_running) { - usbduxsub_tmp->pwm_cmd_running = 0; - usbduxsub_unlink_PwmURBs(usbduxsub_tmp); - } - kfree(usbduxsub_tmp->urbPwm->transfer_buffer); - usbduxsub_tmp->urbPwm->transfer_buffer = NULL; - usb_kill_urb(usbduxsub_tmp->urbPwm); - usb_free_urb(usbduxsub_tmp->urbPwm); - usbduxsub_tmp->urbPwm = NULL; - } - kfree(usbduxsub_tmp->inBuffer); - usbduxsub_tmp->inBuffer = NULL; - kfree(usbduxsub_tmp->insnBuffer); - usbduxsub_tmp->insnBuffer = NULL; - kfree(usbduxsub_tmp->outBuffer); - usbduxsub_tmp->outBuffer = NULL; - kfree(usbduxsub_tmp->dac_commands); - usbduxsub_tmp->dac_commands = NULL; - kfree(usbduxsub_tmp->dux_commands); - usbduxsub_tmp->dux_commands = NULL; - usbduxsub_tmp->ai_cmd_running = 0; - usbduxsub_tmp->ao_cmd_running = 0; - usbduxsub_tmp->pwm_cmd_running = 0; + /* 32 bits big endian from the A/D converter */ + val = be32_to_cpu(*((int32_t *)((devpriv->insn_buf)+1))); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ + + return (int)val; } -static int usbduxsigma_attach_common(struct comedi_device *dev, - struct usbduxsub *uds) +static int usbduxsigma_attach_common(struct comedi_device *dev) { - int ret; + struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s; int n_subdevs; int offset; + int ret; - down(&uds->sem); - /* pointer back to the corresponding comedi device */ - uds->comedidev = dev; + down(&devpriv->sem); - /* set number of subdevices */ - if (uds->high_speed) + if (devpriv->high_speed) n_subdevs = 4; /* with pwm */ else n_subdevs = 3; /* without pwm */ ret = comedi_alloc_subdevices(dev, n_subdevs); if (ret) { - up(&uds->sem); + up(&devpriv->sem); return ret; } - /* private structure is also simply the usb-structure */ - dev->private = uds; - /* the first subdevice is the A/D converter */ - s = &dev->subdevices[SUBDEV_AD]; - /* the URBs get the comedi subdevice */ - /* which is responsible for reading */ - /* this is the subdevice which reads data */ + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; dev->read_subdev = s; - /* the subdevice receives as private structure the */ - /* usb-structure */ - s->private = NULL; - /* analog input */ - s->type = COMEDI_SUBD_AI; - /* readable and ref is to ground, 32 bit wide data! */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | - SDF_CMD_READ | SDF_LSAMPL; - /* 16 A/D channels */ - s->n_chan = NUMCHANNELS; - /* length of the channellist */ - s->len_chanlist = NUMCHANNELS; - /* callback functions */ - s->insn_read = usbdux_ai_insn_read; - s->do_cmdtest = usbdux_ai_cmdtest; - s->do_cmd = usbdux_ai_cmd; - s->cancel = usbdux_ai_cancel; - /* max value from the A/D converter (24bit) */ - s->maxdata = 0x00FFFFFF; - /* range table to convert to physical units */ - s->range_table = (&range_usbdux_ai_range); - /* analog output subdevice */ - s = &dev->subdevices[SUBDEV_DA]; - /* analog out */ - s->type = COMEDI_SUBD_AO; - /* backward pointer */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL; + s->n_chan = NUMCHANNELS; + s->len_chanlist = NUMCHANNELS; + s->maxdata = 0x00ffffff; + s->range_table = &usbduxsigma_ai_range; + s->insn_read = usbduxsigma_ai_insn_read; + s->do_cmdtest = usbduxsigma_ai_cmdtest; + s->do_cmd = usbduxsigma_ai_cmd; + s->cancel = usbduxsigma_ai_cancel; + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; dev->write_subdev = s; - /* the subdevice receives as private structure the */ - /* usb-structure */ - s->private = NULL; - /* are writable */ - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; - /* 4 channels */ - s->n_chan = 4; - /* length of the channellist */ - s->len_chanlist = 4; - /* 8 bit resolution */ - s->maxdata = 0x00ff; - /* unipolar range */ - s->range_table = &range_unipolar2_5; - /* callback */ - s->do_cmdtest = usbdux_ao_cmdtest; - s->do_cmd = usbdux_ao_cmd; - s->cancel = usbdux_ao_cancel; - s->insn_read = usbdux_ao_insn_read; - s->insn_write = usbdux_ao_insn_write; - /* digital I/O subdevice */ - s = &dev->subdevices[SUBDEV_DIO]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - /* 8 external and 16 internal channels */ - s->n_chan = 24; - s->maxdata = 1; - s->range_table = (&range_digital); - s->insn_bits = usbdux_dio_insn_bits; - s->insn_config = usbdux_dio_insn_config; - /* we don't use it */ - s->private = NULL; - if (uds->high_speed) { - /* timer / pwm subdevice */ - s = &dev->subdevices[SUBDEV_PWM]; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; - s->n_chan = 8; - /* this defines the max duty cycle resolution */ - s->maxdata = uds->sizePwmBuf; - s->insn_write = usbdux_pwm_write; - s->insn_read = usbdux_pwm_read; - s->insn_config = usbdux_pwm_config; - usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD); - } - /* finally decide that it's attached */ - uds->attached = 1; - up(&uds->sem); - offset = usbdux_getstatusinfo(dev, 0); + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; + s->n_chan = USBDUXSIGMA_NUM_AO_CHAN; + s->len_chanlist = s->n_chan; + s->maxdata = 0x00ff; + s->range_table = &range_unipolar2_5; + s->insn_write = usbduxsigma_ao_insn_write; + s->insn_read = usbduxsigma_ao_insn_read; + s->do_cmdtest = usbduxsigma_ao_cmdtest; + s->do_cmd = usbduxsigma_ao_cmd; + s->cancel = usbduxsigma_ao_cancel; + + /* Digital I/O subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = usbduxsigma_dio_insn_bits; + s->insn_config = usbduxsigma_dio_insn_config; + + if (devpriv->high_speed) { + /* Timer / pwm subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; + s->n_chan = 8; + s->maxdata = devpriv->pwm_buf_sz; + s->insn_write = usbduxsigma_pwm_write; + s->insn_config = usbduxsigma_pwm_config; + + usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD); + } + + up(&devpriv->sem); + + offset = usbduxsigma_getstatusinfo(dev, 0); if (offset < 0) - dev_err(&uds->interface->dev, - "Communication to USBDUXSIGMA failed! Check firmware and cabling."); - dev_info(&uds->interface->dev, - "comedi%d: attached, ADC_zero = %x\n", dev->minor, offset); + dev_err(dev->class_dev, + "Communication to USBDUXSIGMA failed! Check firmware and cabling\n"); + + dev_info(dev->class_dev, "attached, ADC_zero = %x\n", offset); + return 0; } -static int usbduxsigma_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int usbduxsigma_firmware_upload(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { - struct usb_interface *uinterf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + uint8_t *buf; + uint8_t *tmp; int ret; - struct usbduxsub *uds; - dev->private = NULL; - down(&start_stop_sem); - uds = usb_get_intfdata(uinterf); - if (!uds || !uds->probed) { - dev_err(dev->class_dev, - "usbduxsigma: error: auto_attach failed, not connected\n"); - ret = -ENODEV; - } else if (uds->attached) { - dev_err(dev->class_dev, - "usbduxsigma: error: auto_attach failed, already attached\n"); - ret = -ENODEV; - } else - ret = usbduxsigma_attach_common(dev, uds); - up(&start_stop_sem); - return ret; -} + if (!data) + return 0; -static void usbduxsigma_detach(struct comedi_device *dev) -{ - struct usbduxsub *usb = dev->private; - - if (usb) { - down(&usb->sem); - dev->private = NULL; - usb->attached = 0; - usb->comedidev = NULL; - up(&usb->sem); + if (size > FIRMWARE_MAX_LEN) { + dev_err(dev->class_dev, "firmware binary too large for FX2\n"); + return -ENOMEM; } -} -static struct comedi_driver usbduxsigma_driver = { - .driver_name = "usbduxsigma", - .module = THIS_MODULE, - .auto_attach = usbduxsigma_auto_attach, - .detach = usbduxsigma_detach, -}; + /* we generate a local buffer for the firmware */ + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; -static void usbdux_firmware_request_complete_handler(const struct firmware *fw, - void *context) -{ - struct usbduxsub *usbduxsub_tmp = context; - struct usb_interface *uinterf = usbduxsub_tmp->interface; - int ret; + /* we need a malloc'ed buffer for usb_control_msg() */ + tmp = kmalloc(1, GFP_KERNEL); + if (!tmp) { + kfree(buf); + return -ENOMEM; + } - if (fw == NULL) { - dev_err(&uinterf->dev, - "Firmware complete handler without firmware!\n"); - return; + /* stop the current firmware on the device */ + *tmp = 1; /* 7f92 to one */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXSUB_CPUCS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "can not stop firmware\n"); + goto done; } - /* - * we need to upload the firmware here because fw will be - * freed once we've left this function - */ - ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size); + /* upload the new firmware to the device */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + 0, 0x0000, + buf, size, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "firmware upload failed\n"); + goto done; + } + + /* start the new firmware on the device */ + *tmp = 0; /* 7f92 to zero */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXSUB_CPUCS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) + dev_err(dev->class_dev, "can not start firmware\n"); - if (ret) { - dev_err(&uinterf->dev, - "Could not upload firmware (err=%d)\n", ret); - goto out; - } - comedi_usb_auto_config(uinterf, &usbduxsigma_driver, 0); -out: - release_firmware(fw); +done: + kfree(tmp); + kfree(buf); + return ret; } -static int usbduxsigma_usb_probe(struct usb_interface *uinterf, - const struct usb_device_id *id) +static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) { - struct usb_device *udev = interface_to_usbdev(uinterf); - struct device *dev = &uinterf->dev; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb; int i; - int index; - int ret; - - dev_dbg(dev, "comedi_: usbdux_: " - "finding a free structure for the usb-device\n"); - - down(&start_stop_sem); - /* look for a free place in the usbdux array */ - index = -1; - for (i = 0; i < NUMUSBDUX; i++) { - if (!(usbduxsub[i].probed)) { - index = i; - break; - } - } - - /* no more space */ - if (index == -1) { - dev_err(dev, "Too many usbduxsigma-devices connected.\n"); - up(&start_stop_sem); - return -EMFILE; - } - dev_dbg(dev, "comedi_: usbdux: " - "usbduxsub[%d] is ready to connect to comedi.\n", index); - - sema_init(&(usbduxsub[index].sem), 1); - /* save a pointer to the usb device */ - usbduxsub[index].usbdev = udev; - /* save the interface itself */ - usbduxsub[index].interface = uinterf; - /* get the interface number from the interface */ - usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber; - /* hand the private data over to the usb subsystem */ - /* will be needed for disconnect */ - usb_set_intfdata(uinterf, &(usbduxsub[index])); - - dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum); - - /* test if it is high speed (USB 2.0) */ - usbduxsub[index].high_speed = - (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH); - - /* create space for the commands of the DA converter */ - usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); - if (!usbduxsub[index].dac_commands) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the commands going to the usb device */ - usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); - if (!usbduxsub[index].dux_commands) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the in buffer and set it to zero */ - usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL); - if (!(usbduxsub[index].inBuffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space of the instruction buffer */ - usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL); - if (!(usbduxsub[index].insnBuffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + devpriv->dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); + devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); + devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL); + devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL); + devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(*urb), + GFP_KERNEL); + devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(*urb), + GFP_KERNEL); + if (!devpriv->dac_commands || !devpriv->dux_commands || + !devpriv->in_buf || !devpriv->insn_buf || + !devpriv->ai_urbs || !devpriv->ao_urbs) return -ENOMEM; - } - /* create space for the outbuffer */ - usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); - if (!(usbduxsub[index].outBuffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* setting to alternate setting 3: enabling iso ep and bulk ep. */ - i = usb_set_interface(usbduxsub[index].usbdev, - usbduxsub[index].ifnum, 3); - if (i < 0) { - dev_err(dev, "comedi_: usbduxsigma%d: " - "could not set alternate setting 3 in high speed.\n", - index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENODEV; - } - if (usbduxsub[index].high_speed) - usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSHIGH; - else - usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL; - - usbduxsub[index].urbIn = kcalloc(usbduxsub[index].numOfInBuffers, - sizeof(struct urb *), - GFP_KERNEL); - if (!(usbduxsub[index].urbIn)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - for (i = 0; i < usbduxsub[index].numOfInBuffers; i++) { + + for (i = 0; i < devpriv->n_ai_urbs; i++) { /* one frame: 1ms */ - usbduxsub[index].urbIn[i] = usb_alloc_urb(1, GFP_KERNEL); - if (usbduxsub[index].urbIn[i] == NULL) { - dev_err(dev, "comedi_: usbduxsigma%d: " - "Could not alloc. urb(%d)\n", index, i); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) return -ENOMEM; - } - usbduxsub[index].urbIn[i]->dev = usbduxsub[index].usbdev; + devpriv->ai_urbs[i] = urb; + urb->dev = usb; /* will be filled later with a pointer to the comedi-device */ /* and ONLY then the urb should be submitted */ - usbduxsub[index].urbIn[i]->context = NULL; - usbduxsub[index].urbIn[i]->pipe = - usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP); - usbduxsub[index].urbIn[i]->transfer_flags = URB_ISO_ASAP; - usbduxsub[index].urbIn[i]->transfer_buffer = - kzalloc(SIZEINBUF, GFP_KERNEL); - if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + urb->context = NULL; + urb->pipe = usb_rcvisocpipe(usb, USBDUXSIGMA_ISO_IN_EP); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); + if (!urb->transfer_buffer) return -ENOMEM; - } - usbduxsub[index].urbIn[i]->complete = usbduxsub_ai_IsocIrq; - usbduxsub[index].urbIn[i]->number_of_packets = 1; - usbduxsub[index].urbIn[i]->transfer_buffer_length = SIZEINBUF; - usbduxsub[index].urbIn[i]->iso_frame_desc[0].offset = 0; - usbduxsub[index].urbIn[i]->iso_frame_desc[0].length = - SIZEINBUF; + urb->complete = usbduxsigma_ai_urb_complete; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEINBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEINBUF; } - /* out */ - if (usbduxsub[index].high_speed) - usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSHIGH; - else - usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL; - - usbduxsub[index].urbOut = kcalloc(usbduxsub[index].numOfOutBuffers, - sizeof(struct urb *), GFP_KERNEL); - if (!(usbduxsub[index].urbOut)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - for (i = 0; i < usbduxsub[index].numOfOutBuffers; i++) { + for (i = 0; i < devpriv->n_ao_urbs; i++) { /* one frame: 1ms */ - usbduxsub[index].urbOut[i] = usb_alloc_urb(1, GFP_KERNEL); - if (usbduxsub[index].urbOut[i] == NULL) { - dev_err(dev, "comedi_: usbduxsigma%d: " - "Could not alloc. urb(%d)\n", index, i); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) return -ENOMEM; - } - usbduxsub[index].urbOut[i]->dev = usbduxsub[index].usbdev; + devpriv->ao_urbs[i] = urb; + urb->dev = usb; /* will be filled later with a pointer to the comedi-device */ /* and ONLY then the urb should be submitted */ - usbduxsub[index].urbOut[i]->context = NULL; - usbduxsub[index].urbOut[i]->pipe = - usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP); - usbduxsub[index].urbOut[i]->transfer_flags = URB_ISO_ASAP; - usbduxsub[index].urbOut[i]->transfer_buffer = - kzalloc(SIZEOUTBUF, GFP_KERNEL); - if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + urb->context = NULL; + urb->pipe = usb_sndisocpipe(usb, USBDUXSIGMA_ISO_OUT_EP); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); + if (!urb->transfer_buffer) return -ENOMEM; - } - usbduxsub[index].urbOut[i]->complete = usbduxsub_ao_IsocIrq; - usbduxsub[index].urbOut[i]->number_of_packets = 1; - usbduxsub[index].urbOut[i]->transfer_buffer_length = - SIZEOUTBUF; - usbduxsub[index].urbOut[i]->iso_frame_desc[0].offset = 0; - usbduxsub[index].urbOut[i]->iso_frame_desc[0].length = - SIZEOUTBUF; - if (usbduxsub[index].high_speed) { - /* uframes */ - usbduxsub[index].urbOut[i]->interval = 8; - } else { - /* frames */ - usbduxsub[index].urbOut[i]->interval = 1; - } + urb->complete = usbduxsigma_ao_urb_complete; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEOUTBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEOUTBUF; + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ } - /* pwm */ - if (usbduxsub[index].high_speed) { + if (devpriv->high_speed) { /* max bulk ep size in high speed */ - usbduxsub[index].sizePwmBuf = 512; - usbduxsub[index].urbPwm = usb_alloc_urb(0, GFP_KERNEL); - if (usbduxsub[index].urbPwm == NULL) { - dev_err(dev, "comedi_: usbduxsigma%d: " - "Could not alloc. pwm urb\n", index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + devpriv->pwm_buf_sz = 512; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) return -ENOMEM; - } - usbduxsub[index].urbPwm->transfer_buffer = - kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL); - if (!(usbduxsub[index].urbPwm->transfer_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + devpriv->pwm_urb = urb; + urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, GFP_KERNEL); + if (!urb->transfer_buffer) return -ENOMEM; - } } else { - usbduxsub[index].urbPwm = NULL; - usbduxsub[index].sizePwmBuf = 0; + devpriv->pwm_urb = NULL; + devpriv->pwm_buf_sz = 0; } - usbduxsub[index].ai_cmd_running = 0; - usbduxsub[index].ao_cmd_running = 0; - usbduxsub[index].pwm_cmd_running = 0; + return 0; +} - /* we've reached the bottom of the function */ - usbduxsub[index].probed = 1; - up(&start_stop_sem); +static void usbduxsigma_free_usb_buffers(struct comedi_device *dev) +{ + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb; + int i; - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, - FIRMWARE, - &udev->dev, - GFP_KERNEL, - usbduxsub + index, - usbdux_firmware_request_complete_handler - ); + /* force unlink all urbs */ + usbduxsigma_ai_stop(dev, 1); + usbduxsigma_ao_stop(dev, 1); + usbduxsigma_pwm_stop(dev, 1); + + urb = devpriv->pwm_urb; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + if (devpriv->ao_urbs) { + for (i = 0; i < devpriv->n_ao_urbs; i++) { + urb = devpriv->ao_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ao_urbs); + } + if (devpriv->ai_urbs) { + for (i = 0; i < devpriv->n_ai_urbs; i++) { + urb = devpriv->ai_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ai_urbs); + } + kfree(devpriv->insn_buf); + kfree(devpriv->in_buf); + kfree(devpriv->dux_commands); + kfree(devpriv->dac_commands); +} - if (ret) { - dev_err(dev, "Could not load firmware (err=%d)\n", ret); - return ret; +static int usbduxsigma_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv; + int ret; + + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + + sema_init(&devpriv->sem, 1); + usb_set_intfdata(intf, devpriv); + + ret = usb_set_interface(usb, + intf->altsetting->desc.bInterfaceNumber, 3); + if (ret < 0) { + dev_err(dev->class_dev, + "could not set alternate setting 3 in high speed\n"); + return -ENODEV; } - dev_info(dev, "comedi_: successfully initialised.\n"); - /* success */ - return 0; + /* test if it is high speed (USB 2.0) */ + devpriv->high_speed = (usb->speed == USB_SPEED_HIGH); + if (devpriv->high_speed) { + devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH; + } else { + devpriv->n_ai_urbs = NUMOFINBUFFERSFULL; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL; + } + + ret = usbduxsigma_alloc_usb_buffers(dev); + if (ret) + return ret; + + ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, + usbduxsigma_firmware_upload, 0); + if (ret) + return ret; + + return usbduxsigma_attach_common(dev); } -static void usbduxsigma_usb_disconnect(struct usb_interface *intf) +static void usbduxsigma_detach(struct comedi_device *dev) { - struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf); - struct usb_device *udev = interface_to_usbdev(intf); + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usbduxsigma_private *devpriv = dev->private; - if (!usbduxsub_tmp) { - dev_err(&intf->dev, - "comedi_: disconnect called with null pointer.\n"); + if (!devpriv) return; - } - if (usbduxsub_tmp->usbdev != udev) { - dev_err(&intf->dev, "comedi_: BUG! wrong ptr!\n"); - return; - } - if (usbduxsub_tmp->ai_cmd_running) - /* we are still running a command */ - usbdux_ai_stop(usbduxsub_tmp, 1); - if (usbduxsub_tmp->ao_cmd_running) - /* we are still running a command */ - usbdux_ao_stop(usbduxsub_tmp, 1); - comedi_usb_auto_unconfig(intf); - down(&start_stop_sem); - down(&usbduxsub_tmp->sem); - tidy_up(usbduxsub_tmp); - up(&usbduxsub_tmp->sem); - up(&start_stop_sem); - dev_info(&intf->dev, "comedi_: disconnected from the usb\n"); + + usb_set_intfdata(intf, NULL); + + down(&devpriv->sem); + usbduxsigma_free_usb_buffers(dev); + up(&devpriv->sem); +} + +static struct comedi_driver usbduxsigma_driver = { + .driver_name = "usbduxsigma", + .module = THIS_MODULE, + .auto_attach = usbduxsigma_auto_attach, + .detach = usbduxsigma_detach, +}; + +static int usbduxsigma_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &usbduxsigma_driver, 0); } static const struct usb_device_id usbduxsigma_usb_table[] = { @@ -2664,7 +1754,7 @@ MODULE_DEVICE_TABLE(usb, usbduxsigma_usb_table); static struct usb_driver usbduxsigma_usb_driver = { .name = "usbduxsigma", .probe = usbduxsigma_usb_probe, - .disconnect = usbduxsigma_usb_disconnect, + .disconnect = comedi_usb_auto_unconfig, .id_table = usbduxsigma_usb_table, }; module_comedi_usb_driver(usbduxsigma_driver, usbduxsigma_usb_driver); diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 2be5087414f6..0ab04c0dd410 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: vmk80xx @@ -159,8 +154,6 @@ static const struct vmk80xx_board vmk80xx_boardinfo[] = { }; struct vmk80xx_private { - struct usb_device *usb; - struct usb_interface *intf; struct usb_endpoint_descriptor *ep_rx; struct usb_endpoint_descriptor *ep_tx; struct firmware_version fw; @@ -170,9 +163,10 @@ struct vmk80xx_private { enum vmk80xx_model model; }; -static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv) +static int vmk80xx_check_data_link(struct comedi_device *dev) { - struct usb_device *usb = devpriv->usb; + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); unsigned int tx_pipe; unsigned int rx_pipe; unsigned char tx[1]; @@ -194,9 +188,10 @@ static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv) return (int)rx[1]; } -static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag) +static void vmk80xx_read_eeprom(struct comedi_device *dev, int flag) { - struct usb_device *usb = devpriv->usb; + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); unsigned int tx_pipe; unsigned int rx_pipe; unsigned char tx[1]; @@ -223,9 +218,10 @@ static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag) strncpy(devpriv->fw.ic6_vers, rx + 25, 24); } -static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv) +static void vmk80xx_do_bulk_msg(struct comedi_device *dev) { - struct usb_device *usb = devpriv->usb; + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); __u8 tx_addr; __u8 rx_addr; unsigned int tx_pipe; @@ -248,21 +244,18 @@ static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv) usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10); } -static int vmk80xx_read_packet(struct vmk80xx_private *devpriv) +static int vmk80xx_read_packet(struct comedi_device *dev) { - struct usb_device *usb; + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); struct usb_endpoint_descriptor *ep; unsigned int pipe; - if (!devpriv->intf) - return -ENODEV; - if (devpriv->model == VMK8061_MODEL) { - vmk80xx_do_bulk_msg(devpriv); + vmk80xx_do_bulk_msg(dev); return 0; } - usb = devpriv->usb; ep = devpriv->ep_rx; pipe = usb_rcvintpipe(usb, ep->bEndpointAddress); return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf, @@ -270,23 +263,20 @@ static int vmk80xx_read_packet(struct vmk80xx_private *devpriv) HZ * 10); } -static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd) +static int vmk80xx_write_packet(struct comedi_device *dev, int cmd) { - struct usb_device *usb; + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); struct usb_endpoint_descriptor *ep; unsigned int pipe; - if (!devpriv->intf) - return -ENODEV; - devpriv->usb_tx_buf[0] = cmd; if (devpriv->model == VMK8061_MODEL) { - vmk80xx_do_bulk_msg(devpriv); + vmk80xx_do_bulk_msg(dev); return 0; } - usb = devpriv->usb; ep = devpriv->ep_tx; pipe = usb_sndintpipe(usb, ep->bEndpointAddress); return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf, @@ -294,18 +284,19 @@ static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd) HZ * 10); } -static int vmk80xx_reset_device(struct vmk80xx_private *devpriv) +static int vmk80xx_reset_device(struct comedi_device *dev) { + struct vmk80xx_private *devpriv = dev->private; size_t size; int retval; size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize); memset(devpriv->usb_tx_buf, 0, size); - retval = vmk80xx_write_packet(devpriv, VMK8055_CMD_RST); + retval = vmk80xx_write_packet(dev, VMK8055_CMD_RST); if (retval) return retval; /* set outputs to known state as we cannot read them */ - return vmk80xx_write_packet(devpriv, VMK8055_CMD_WRT_AD); + return vmk80xx_write_packet(dev, VMK8055_CMD_WRT_AD); } static int vmk80xx_ai_insn_read(struct comedi_device *dev, @@ -338,7 +329,7 @@ static int vmk80xx_ai_insn_read(struct comedi_device *dev, } for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(devpriv)) + if (vmk80xx_read_packet(dev)) break; if (devpriv->model == VMK8055_MODEL) { @@ -388,7 +379,7 @@ static int vmk80xx_ao_insn_write(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { devpriv->usb_tx_buf[reg] = data[n]; - if (vmk80xx_write_packet(devpriv, cmd)) + if (vmk80xx_write_packet(dev, cmd)) break; } @@ -415,7 +406,7 @@ static int vmk80xx_ao_insn_read(struct comedi_device *dev, devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO; for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(devpriv)) + if (vmk80xx_read_packet(dev)) break; data[n] = devpriv->usb_rx_buf[reg + chan]; @@ -447,7 +438,7 @@ static int vmk80xx_di_insn_bits(struct comedi_device *dev, reg = VMK8055_DI_REG; } - retval = vmk80xx_read_packet(devpriv); + retval = vmk80xx_read_packet(dev); if (!retval) { if (devpriv->model == VMK8055_MODEL) @@ -492,7 +483,7 @@ static int vmk80xx_do_insn_bits(struct comedi_device *dev, tx_buf[reg] &= ~data[0]; tx_buf[reg] |= (data[0] & data[1]); - retval = vmk80xx_write_packet(devpriv, cmd); + retval = vmk80xx_write_packet(dev, cmd); if (retval) goto out; @@ -501,7 +492,7 @@ static int vmk80xx_do_insn_bits(struct comedi_device *dev, if (devpriv->model == VMK8061_MODEL) { tx_buf[0] = VMK8061_CMD_RD_DO; - retval = vmk80xx_read_packet(devpriv); + retval = vmk80xx_read_packet(dev); if (!retval) { data[1] = rx_buf[reg]; @@ -547,7 +538,7 @@ static int vmk80xx_cnt_insn_read(struct comedi_device *dev, } for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(devpriv)) + if (vmk80xx_read_packet(dev)) break; if (devpriv->model == VMK8055_MODEL) @@ -597,7 +588,7 @@ static int vmk80xx_cnt_insn_config(struct comedi_device *dev, } for (n = 0; n < insn->n; n++) - if (vmk80xx_write_packet(devpriv, cmd)) + if (vmk80xx_write_packet(dev, cmd)) break; up(&devpriv->limit_sem); @@ -640,7 +631,7 @@ static int vmk80xx_cnt_insn_write(struct comedi_device *dev, devpriv->usb_tx_buf[6 + chan] = val; - if (vmk80xx_write_packet(devpriv, cmd)) + if (vmk80xx_write_packet(dev, cmd)) break; } @@ -671,7 +662,7 @@ static int vmk80xx_pwm_insn_read(struct comedi_device *dev, tx_buf[0] = VMK8061_CMD_RD_PWM; for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(devpriv)) + if (vmk80xx_read_packet(dev)) break; data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]]; @@ -719,7 +710,7 @@ static int vmk80xx_pwm_insn_write(struct comedi_device *dev, tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03); tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff; - if (vmk80xx_write_packet(devpriv, cmd)) + if (vmk80xx_write_packet(dev, cmd)) break; } @@ -731,7 +722,7 @@ static int vmk80xx_pwm_insn_write(struct comedi_device *dev, static int vmk80xx_find_usb_endpoints(struct comedi_device *dev) { struct vmk80xx_private *devpriv = dev->private; - struct usb_interface *intf = devpriv->intf; + struct usb_interface *intf = comedi_to_usb_interface(dev); struct usb_host_interface *iface_desc = intf->cur_altsetting; struct usb_endpoint_descriptor *ep_desc; int i; @@ -889,8 +880,6 @@ static int vmk80xx_auto_attach(struct comedi_device *dev, return -ENOMEM; dev->private = devpriv; - devpriv->usb = interface_to_usbdev(intf); - devpriv->intf = intf; devpriv->model = boardinfo->model; ret = vmk80xx_find_usb_endpoints(dev); @@ -906,23 +895,24 @@ static int vmk80xx_auto_attach(struct comedi_device *dev, usb_set_intfdata(intf, devpriv); if (devpriv->model == VMK8061_MODEL) { - vmk80xx_read_eeprom(devpriv, IC3_VERSION); + vmk80xx_read_eeprom(dev, IC3_VERSION); dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers); - if (vmk80xx_check_data_link(devpriv)) { - vmk80xx_read_eeprom(devpriv, IC6_VERSION); + if (vmk80xx_check_data_link(dev)) { + vmk80xx_read_eeprom(dev, IC6_VERSION); dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers); } } if (devpriv->model == VMK8055_MODEL) - vmk80xx_reset_device(devpriv); + vmk80xx_reset_device(dev); return vmk80xx_init_subdevices(dev); } static void vmk80xx_detach(struct comedi_device *dev) { + struct usb_interface *intf = comedi_to_usb_interface(dev); struct vmk80xx_private *devpriv = dev->private; if (!devpriv) @@ -930,7 +920,7 @@ static void vmk80xx_detach(struct comedi_device *dev) down(&devpriv->limit_sem); - usb_set_intfdata(devpriv->intf, NULL); + usb_set_intfdata(intf, NULL); kfree(devpriv->usb_rx_buf); kfree(devpriv->usb_tx_buf); diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index 3231a483f561..da8988c6bf50 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #include <linux/module.h> diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c index 886c202de9ab..8ee94424bc8f 100644 --- a/drivers/staging/comedi/proc.c +++ b/drivers/staging/comedi/proc.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index 1dc391b76447..1f20332cc459 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #include <linux/uaccess.h> |