diff options
Diffstat (limited to 'drivers/staging/comedi')
104 files changed, 4577 insertions, 6736 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 36eec320569c..1967852eeb17 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -1,7 +1,6 @@ config COMEDI tristate "Data acquisition support (comedi)" depends on m - depends on BROKEN || FRV || M32R || MN10300 || SUPERH || TILE || X86 ---help--- Enable support a wide range of data acquisition devices for Linux. @@ -165,7 +164,7 @@ config COMEDI_PCL730 config COMEDI_PCL812 tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" - depends on VIRT_TO_BUS + depends on VIRT_TO_BUS && ISA_DMA_API ---help--- Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, @@ -176,7 +175,7 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" - depends on VIRT_TO_BUS + depends on VIRT_TO_BUS && ISA_DMA_API ---help--- Enable support for Advantech PCL-814 and PCL-816 ISA cards @@ -185,7 +184,7 @@ config COMEDI_PCL816 config COMEDI_PCL818 tristate "Advantech PCL-718 and PCL-818 ISA card support" - depends on VIRT_TO_BUS + depends on VIRT_TO_BUS && ISA_DMA_API ---help--- Enable support for Advantech PCL-818 ISA cards PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 @@ -275,10 +274,11 @@ config COMEDI_DAS08_ISA DAS08/JR-16-AO, PC104-DAS08, DAS08/JR/16. To compile this driver as a module, choose M here: the module will be - called das08. + called das08_isa. config COMEDI_DAS16 tristate "DAS-16 compatible ISA and PC/104 card support" + depends on ISA_DMA_API select COMEDI_8255 select COMEDI_FC ---help--- @@ -308,7 +308,7 @@ config COMEDI_DAS800 config COMEDI_DAS1800 tristate "DAS1800 and compatible ISA card support" - depends on VIRT_TO_BUS + depends on VIRT_TO_BUS && ISA_DMA_API select COMEDI_FC ---help--- Enable support for DAS1800 and compatible ISA cards @@ -373,7 +373,7 @@ config COMEDI_DT2817 config COMEDI_DT282X tristate "Data Translation DT2821 series and DT-EZ ISA card support" select COMEDI_FC - depends on VIRT_TO_BUS + depends on VIRT_TO_BUS && ISA_DMA_API ---help--- Enable support for Data Translation DT2821 series including DT-EZ DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI, @@ -445,7 +445,7 @@ config COMEDI_ADQ12B config COMEDI_NI_AT_A2150 tristate "NI AT-A2150 ISA card support" select COMEDI_FC - depends on VIRT_TO_BUS + depends on VIRT_TO_BUS && ISA_DMA_API ---help--- Enable support for National Instruments AT-A2150 cards @@ -542,11 +542,7 @@ menuconfig COMEDI_PCI_DRIVERS bool "Comedi PCI drivers" depends on PCI ---help--- - Enable comedi PCI drivers to be built - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about PCI comedi drivers. + Enable support for comedi PCI drivers. if COMEDI_PCI_DRIVERS @@ -567,6 +563,13 @@ config COMEDI_8255_PCI To compile this driver as a module, choose M here: the module will be called 8255_pci. +config COMEDI_ADDI_WATCHDOG + tristate + ---help--- + Provides support for the watchdog subdevice found on many ADDI-DATA + boards. This module will be automatically selected when needed. The + module will be called addi_watchdog. + config COMEDI_ADDI_APCI_035 tristate "ADDI-DATA APCI_035 support" ---help--- @@ -593,6 +596,7 @@ config COMEDI_ADDI_APCI_1500 config COMEDI_ADDI_APCI_1516 tristate "ADDI-DATA APCI-1016/1516/2016 support" + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI-1016, APCI-1516 and APCI-2016 boards. These are 16 channel, optically isolated, digital I/O boards. The 1516 @@ -619,6 +623,7 @@ config COMEDI_ADDI_APCI_16XX config COMEDI_ADDI_APCI_2032 tristate "ADDI-DATA APCI_2032 support" + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI_2032 cards @@ -627,6 +632,7 @@ config COMEDI_ADDI_APCI_2032 config COMEDI_ADDI_APCI_2200 tristate "ADDI-DATA APCI_2200 support" + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI_2200 cards @@ -796,7 +802,7 @@ config COMEDI_DAS08_PCI Enable support for PCI DAS-08 cards. To compile this driver as a module, choose M here: the module will be - called das08. + called das08_pci. config COMEDI_DT3000 tristate "Data Translation DT3000 series support" @@ -1084,11 +1090,7 @@ menuconfig COMEDI_PCMCIA_DRIVERS bool "Comedi PCMCIA drivers" depends on PCMCIA ---help--- - Enable comedi PCMCIA and PCCARD drivers to be built - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about PCMCIA comedi drivers. + Enable support for comedi PCMCIA drivers. if COMEDI_PCMCIA_DRIVERS @@ -1165,11 +1167,7 @@ menuconfig COMEDI_USB_DRIVERS bool "Comedi USB drivers" depends on USB ---help--- - Enable comedi USB drivers to be built - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about USB comedi drivers. + Enable support for comedi USB drivers. if COMEDI_USB_DRIVERS diff --git a/drivers/staging/comedi/Makefile b/drivers/staging/comedi/Makefile index 8dbd306fef88..e6dfc98f8c8e 100644 --- a/drivers/staging/comedi/Makefile +++ b/drivers/staging/comedi/Makefile @@ -1,11 +1,12 @@ -obj-$(CONFIG_COMEDI) += comedi.o +comedi-y := comedi_fops.o range.o drivers.o \ + comedi_buf.o +comedi-$(CONFIG_COMEDI_PCI_DRIVERS) += comedi_pci.o +comedi-$(CONFIG_COMEDI_PCMCIA_DRIVERS) += comedi_pcmcia.o +comedi-$(CONFIG_COMEDI_USB_DRIVERS) += comedi_usb.o +comedi-$(CONFIG_PROC_FS) += proc.o +comedi-$(CONFIG_COMPAT) += comedi_compat32.o -obj-$(CONFIG_COMEDI) += kcomedilib/ -obj-$(CONFIG_COMEDI) += drivers/ +obj-$(CONFIG_COMEDI) += comedi.o -comedi-y := \ - comedi_fops.o \ - proc.o \ - range.o \ - drivers.o \ - comedi_compat32.o \ +obj-$(CONFIG_COMEDI) += kcomedilib/ +obj-$(CONFIG_COMEDI) += drivers/ diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index c8a8ca126127..4233605df30a 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -41,7 +41,17 @@ /* number of config options in the config structure */ #define COMEDI_NDEVCONFOPTS 32 -/*length of nth chunk of firmware data*/ + +/* + * NOTE: 'comedi_config --init-data' is deprecated + * + * The following indexes in the config options were used by + * comedi_config to pass firmware blobs from user space to the + * comedi drivers. The request_firmware() hotplug interface is + * now used by all comedi drivers instead. + */ + +/* length of nth chunk of firmware data -*/ #define COMEDI_DEVCONF_AUX_DATA3_LENGTH 25 #define COMEDI_DEVCONF_AUX_DATA2_LENGTH 26 #define COMEDI_DEVCONF_AUX_DATA1_LENGTH 27 diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c new file mode 100644 index 000000000000..9b997ae67796 --- /dev/null +++ b/drivers/staging/comedi/comedi_buf.c @@ -0,0 +1,415 @@ +/* + * comedi_buf.c + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "comedidev.h" +#include "comedi_internal.h" + +#ifdef PAGE_KERNEL_NOCACHE +#define COMEDI_PAGE_PROTECTION PAGE_KERNEL_NOCACHE +#else +#define COMEDI_PAGE_PROTECTION PAGE_KERNEL +#endif + +static void __comedi_buf_free(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned n_pages) +{ + struct comedi_async *async = s->async; + struct comedi_buf_page *buf; + unsigned i; + + if (async->prealloc_buf) { + vunmap(async->prealloc_buf); + async->prealloc_buf = NULL; + async->prealloc_bufsz = 0; + } + + if (!async->buf_page_list) + return; + + for (i = 0; i < n_pages; ++i) { + buf = &async->buf_page_list[i]; + if (buf->virt_addr) { + clear_bit(PG_reserved, + &(virt_to_page(buf->virt_addr)->flags)); + if (s->async_dma_dir != DMA_NONE) { + dma_free_coherent(dev->hw_dev, + PAGE_SIZE, + buf->virt_addr, + buf->dma_addr); + } else { + free_page((unsigned long)buf->virt_addr); + } + } + } + vfree(async->buf_page_list); + async->buf_page_list = NULL; + async->n_buf_pages = 0; +} + +static void __comedi_buf_alloc(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned n_pages) +{ + struct comedi_async *async = s->async; + struct page **pages = NULL; + struct comedi_buf_page *buf; + unsigned i; + + async->buf_page_list = vzalloc(sizeof(*buf) * n_pages); + if (async->buf_page_list) + pages = vmalloc(sizeof(struct page *) * n_pages); + + if (!pages) + return; + + for (i = 0; i < n_pages; i++) { + buf = &async->buf_page_list[i]; + if (s->async_dma_dir != DMA_NONE) + buf->virt_addr = dma_alloc_coherent(dev->hw_dev, + PAGE_SIZE, + &buf->dma_addr, + GFP_KERNEL | + __GFP_COMP); + else + buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL); + if (!buf->virt_addr) + break; + + set_bit(PG_reserved, &(virt_to_page(buf->virt_addr)->flags)); + + pages[i] = virt_to_page(buf->virt_addr); + } + + /* vmap the prealloc_buf if all the pages were allocated */ + if (i == n_pages) + async->prealloc_buf = vmap(pages, n_pages, VM_MAP, + COMEDI_PAGE_PROTECTION); + + vfree(pages); +} + +int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned long new_size) +{ + struct comedi_async *async = s->async; + + /* Round up new_size to multiple of PAGE_SIZE */ + new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; + + /* if no change is required, do nothing */ + if (async->prealloc_buf && async->prealloc_bufsz == new_size) + return 0; + + /* deallocate old buffer */ + __comedi_buf_free(dev, s, async->n_buf_pages); + + /* allocate new buffer */ + if (new_size) { + unsigned n_pages = new_size >> PAGE_SHIFT; + + __comedi_buf_alloc(dev, s, n_pages); + + if (!async->prealloc_buf) { + /* allocation failed */ + __comedi_buf_free(dev, s, n_pages); + return -ENOMEM; + } + async->n_buf_pages = n_pages; + } + async->prealloc_bufsz = new_size; + + return 0; +} + +void comedi_buf_reset(struct comedi_async *async) +{ + async->buf_write_alloc_count = 0; + async->buf_write_count = 0; + async->buf_read_alloc_count = 0; + async->buf_read_count = 0; + + async->buf_write_ptr = 0; + async->buf_read_ptr = 0; + + async->cur_chan = 0; + async->scan_progress = 0; + async->munge_chan = 0; + async->munge_count = 0; + async->munge_ptr = 0; + + async->events = 0; +} + +static unsigned int comedi_buf_write_n_available(struct comedi_async *async) +{ + unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; + + return free_end - async->buf_write_alloc_count; +} + +static unsigned int __comedi_buf_write_alloc(struct comedi_async *async, + unsigned int nbytes, + int strict) +{ + unsigned int available = comedi_buf_write_n_available(async); + + if (nbytes > available) + nbytes = strict ? 0 : available; + + async->buf_write_alloc_count += nbytes; + + /* + * ensure the async buffer 'counts' are read and updated + * before we write data to the write-alloc'ed buffer space + */ + smp_mb(); + + return nbytes; +} + +/* allocates chunk for the writer from free buffer space */ +unsigned int comedi_buf_write_alloc(struct comedi_async *async, + unsigned int nbytes) +{ + return __comedi_buf_write_alloc(async, nbytes, 0); +} +EXPORT_SYMBOL(comedi_buf_write_alloc); + +/* + * munging is applied to data by core as it passes between user + * and kernel space + */ +static unsigned int comedi_buf_munge(struct comedi_async *async, + unsigned int num_bytes) +{ + struct comedi_subdevice *s = async->subdevice; + unsigned int count = 0; + const unsigned num_sample_bytes = bytes_per_sample(s); + + if (!s->munge || (async->cmd.flags & CMDF_RAWDATA)) { + async->munge_count += num_bytes; + count = num_bytes; + } else { + /* don't munge partial samples */ + num_bytes -= num_bytes % num_sample_bytes; + while (count < num_bytes) { + int block_size = num_bytes - count; + unsigned int buf_end; + + buf_end = async->prealloc_bufsz - async->munge_ptr; + if (block_size > buf_end) + block_size = buf_end; + + s->munge(s->device, s, + async->prealloc_buf + async->munge_ptr, + block_size, async->munge_chan); + + /* + * ensure data is munged in buffer before the + * async buffer munge_count is incremented + */ + smp_wmb(); + + async->munge_chan += block_size / num_sample_bytes; + async->munge_chan %= async->cmd.chanlist_len; + async->munge_count += block_size; + async->munge_ptr += block_size; + async->munge_ptr %= async->prealloc_bufsz; + count += block_size; + } + } + + return count; +} + +unsigned int comedi_buf_write_n_allocated(struct comedi_async *async) +{ + return async->buf_write_alloc_count - async->buf_write_count; +} + +/* transfers a chunk from writer to filled buffer space */ +unsigned int comedi_buf_write_free(struct comedi_async *async, + unsigned int nbytes) +{ + unsigned int allocated = comedi_buf_write_n_allocated(async); + + if (nbytes > allocated) + nbytes = allocated; + + async->buf_write_count += nbytes; + async->buf_write_ptr += nbytes; + comedi_buf_munge(async, async->buf_write_count - async->munge_count); + if (async->buf_write_ptr >= async->prealloc_bufsz) + async->buf_write_ptr %= async->prealloc_bufsz; + + return nbytes; +} +EXPORT_SYMBOL(comedi_buf_write_free); + +unsigned int comedi_buf_read_n_available(struct comedi_async *async) +{ + unsigned num_bytes; + + if (!async) + return 0; + + num_bytes = async->munge_count - async->buf_read_count; + + /* + * ensure the async buffer 'counts' are read before we + * attempt to read data from the buffer + */ + smp_rmb(); + + return num_bytes; +} +EXPORT_SYMBOL(comedi_buf_read_n_available); + +/* allocates a chunk for the reader from filled (and munged) buffer space */ +unsigned int comedi_buf_read_alloc(struct comedi_async *async, + unsigned int nbytes) +{ + unsigned int available; + + available = async->munge_count - async->buf_read_alloc_count; + if (nbytes > available) + nbytes = available; + + async->buf_read_alloc_count += nbytes; + + /* + * ensure the async buffer 'counts' are read before we + * attempt to read data from the read-alloc'ed buffer space + */ + smp_rmb(); + + return nbytes; +} +EXPORT_SYMBOL(comedi_buf_read_alloc); + +static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async) +{ + return async->buf_read_alloc_count - async->buf_read_count; +} + +/* transfers control of a chunk from reader to free buffer space */ +unsigned int comedi_buf_read_free(struct comedi_async *async, + unsigned int nbytes) +{ + unsigned int allocated; + + /* + * ensure data has been read out of buffer before + * the async read count is incremented + */ + smp_mb(); + + allocated = comedi_buf_read_n_allocated(async); + if (nbytes > allocated) + nbytes = allocated; + + async->buf_read_count += nbytes; + async->buf_read_ptr += nbytes; + async->buf_read_ptr %= async->prealloc_bufsz; + return nbytes; +} +EXPORT_SYMBOL(comedi_buf_read_free); + +int comedi_buf_put(struct comedi_async *async, short x) +{ + unsigned int n = __comedi_buf_write_alloc(async, sizeof(short), 1); + + if (n < sizeof(short)) { + async->events |= COMEDI_CB_ERROR; + return 0; + } + *(short *)(async->prealloc_buf + async->buf_write_ptr) = x; + comedi_buf_write_free(async, sizeof(short)); + return 1; +} +EXPORT_SYMBOL(comedi_buf_put); + +int comedi_buf_get(struct comedi_async *async, short *x) +{ + unsigned int n = comedi_buf_read_n_available(async); + + if (n < sizeof(short)) + return 0; + comedi_buf_read_alloc(async, sizeof(short)); + *x = *(short *)(async->prealloc_buf + async->buf_read_ptr); + comedi_buf_read_free(async, sizeof(short)); + return 1; +} +EXPORT_SYMBOL(comedi_buf_get); + +void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, + const void *data, unsigned int num_bytes) +{ + unsigned int write_ptr = async->buf_write_ptr + offset; + + if (write_ptr >= async->prealloc_bufsz) + write_ptr %= async->prealloc_bufsz; + + while (num_bytes) { + unsigned int block_size; + + if (write_ptr + num_bytes > async->prealloc_bufsz) + block_size = async->prealloc_bufsz - write_ptr; + else + block_size = num_bytes; + + memcpy(async->prealloc_buf + write_ptr, data, block_size); + + data += block_size; + num_bytes -= block_size; + + write_ptr = 0; + } +} +EXPORT_SYMBOL(comedi_buf_memcpy_to); + +void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, + void *dest, unsigned int nbytes) +{ + void *src; + unsigned int read_ptr = async->buf_read_ptr + offset; + + if (read_ptr >= async->prealloc_bufsz) + read_ptr %= async->prealloc_bufsz; + + while (nbytes) { + unsigned int block_size; + + src = async->prealloc_buf + read_ptr; + + if (nbytes >= async->prealloc_bufsz - read_ptr) + block_size = async->prealloc_bufsz - read_ptr; + else + block_size = nbytes; + + memcpy(dest, src, block_size); + nbytes -= block_size; + dest += block_size; + read_ptr = 0; + } +} +EXPORT_SYMBOL(comedi_buf_memcpy_from); diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index 4b7cbfad1d74..ad208cdd53d4 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -30,8 +30,6 @@ #include "comedi.h" #include "comedi_compat32.h" -#ifdef CONFIG_COMPAT - #define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct) #define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct) /* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR. @@ -460,5 +458,3 @@ long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return raw_ioctl(file, cmd, arg); } - -#endif /* CONFIG_COMPAT */ diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 9b038e4a7e71..e336b281b847 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -49,10 +49,6 @@ #include "comedi_internal.h" -MODULE_AUTHOR("http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi core module"); -MODULE_LICENSE("GPL"); - #ifdef CONFIG_COMEDI_DEBUG int comedi_debug; EXPORT_SYMBOL(comedi_debug); @@ -62,11 +58,6 @@ MODULE_PARM_DESC(comedi_debug, ); #endif -bool comedi_autoconfig = 1; -module_param(comedi_autoconfig, bool, S_IRUGO); -MODULE_PARM_DESC(comedi_autoconfig, - "enable drivers to auto-configure comedi devices (default 1)"); - static int comedi_num_legacy_minors; module_param(comedi_num_legacy_minors, int, S_IRUGO); MODULE_PARM_DESC(comedi_num_legacy_minors, @@ -86,17 +77,58 @@ MODULE_PARM_DESC(comedi_default_buf_maxsize_kb, "default maximum size of asynchronous buffer in KiB (default " __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")"); +struct comedi_file_info { + struct comedi_device *device; + struct comedi_subdevice *read_subdevice; + struct comedi_subdevice *write_subdevice; + struct device *hardware_device; +}; + static DEFINE_SPINLOCK(comedi_file_info_table_lock); -static struct comedi_device_file_info -*comedi_file_info_table[COMEDI_NUM_MINORS]; +static struct comedi_file_info *comedi_file_info_table[COMEDI_NUM_MINORS]; -static void do_become_nonbusy(struct comedi_device *dev, - struct comedi_subdevice *s); -static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static struct comedi_file_info *comedi_file_info_from_minor(unsigned minor) +{ + struct comedi_file_info *info; + + BUG_ON(minor >= COMEDI_NUM_MINORS); + spin_lock(&comedi_file_info_table_lock); + info = comedi_file_info_table[minor]; + spin_unlock(&comedi_file_info_table_lock); + return info; +} + +static struct comedi_device * +comedi_dev_from_file_info(struct comedi_file_info *info) +{ + return info ? info->device : NULL; +} + +struct comedi_device *comedi_dev_from_minor(unsigned minor) +{ + return comedi_dev_from_file_info(comedi_file_info_from_minor(minor)); +} +EXPORT_SYMBOL_GPL(comedi_dev_from_minor); -static int comedi_fasync(int fd, struct file *file, int on); +static struct comedi_subdevice * +comedi_read_subdevice(const struct comedi_file_info *info) +{ + if (info->read_subdevice) + return info->read_subdevice; + if (info->device) + return info->device->read_subdev; + return NULL; +} -static int is_device_busy(struct comedi_device *dev); +static struct comedi_subdevice * +comedi_write_subdevice(const struct comedi_file_info *info) +{ + if (info->write_subdevice) + return info->write_subdevice; + if (info->device) + return info->device->write_subdev; + return NULL; +} static int resize_async_buffer(struct comedi_device *dev, struct comedi_subdevice *s, @@ -134,7 +166,7 @@ static int resize_async_buffer(struct comedi_device *dev, } DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", - dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); + dev->minor, s->index, async->prealloc_bufsz); return 0; } @@ -143,8 +175,8 @@ static int resize_async_buffer(struct comedi_device *dev, static ssize_t show_max_read_buffer_kb(struct device *dev, struct device_attribute *attr, char *buf) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_read_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_read_subdevice(info); unsigned int size = 0; mutex_lock(&info->device->mutex); @@ -159,8 +191,8 @@ static ssize_t store_max_read_buffer_kb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_read_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_read_subdevice(info); unsigned int size; int err; @@ -184,8 +216,8 @@ static ssize_t store_max_read_buffer_kb(struct device *dev, static ssize_t show_read_buffer_kb(struct device *dev, struct device_attribute *attr, char *buf) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_read_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_read_subdevice(info); unsigned int size = 0; mutex_lock(&info->device->mutex); @@ -200,8 +232,8 @@ static ssize_t store_read_buffer_kb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_read_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_read_subdevice(info); unsigned int size; int err; @@ -226,8 +258,8 @@ static ssize_t show_max_write_buffer_kb(struct device *dev, struct device_attribute *attr, char *buf) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_write_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_write_subdevice(info); unsigned int size = 0; mutex_lock(&info->device->mutex); @@ -242,8 +274,8 @@ static ssize_t store_max_write_buffer_kb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_write_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_write_subdevice(info); unsigned int size; int err; @@ -267,8 +299,8 @@ static ssize_t store_max_write_buffer_kb(struct device *dev, static ssize_t show_write_buffer_kb(struct device *dev, struct device_attribute *attr, char *buf) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_write_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_write_subdevice(info); unsigned int size = 0; mutex_lock(&info->device->mutex); @@ -283,8 +315,8 @@ static ssize_t store_write_buffer_kb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - struct comedi_subdevice *s = comedi_get_write_subdevice(info); + struct comedi_file_info *info = dev_get_drvdata(dev); + struct comedi_subdevice *s = comedi_write_subdevice(info); unsigned int size; int err; @@ -317,6 +349,103 @@ static struct device_attribute comedi_dev_attrs[] = { __ATTR_NULL }; +static void comedi_set_subdevice_runflags(struct comedi_subdevice *s, + unsigned mask, unsigned bits) +{ + unsigned long flags; + + spin_lock_irqsave(&s->spin_lock, flags); + s->runflags &= ~mask; + s->runflags |= (bits & mask); + spin_unlock_irqrestore(&s->spin_lock, flags); +} + +static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) +{ + unsigned long flags; + unsigned runflags; + + spin_lock_irqsave(&s->spin_lock, flags); + runflags = s->runflags; + spin_unlock_irqrestore(&s->spin_lock, flags); + return runflags; +} + +bool comedi_is_subdevice_running(struct comedi_subdevice *s) +{ + unsigned runflags = comedi_get_subdevice_runflags(s); + + return (runflags & SRF_RUNNING) ? true : false; +} +EXPORT_SYMBOL_GPL(comedi_is_subdevice_running); + +static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s) +{ + unsigned runflags = comedi_get_subdevice_runflags(s); + + return (runflags & SRF_ERROR) ? true : false; +} + +static bool comedi_is_subdevice_idle(struct comedi_subdevice *s) +{ + unsigned runflags = comedi_get_subdevice_runflags(s); + + return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true; +} + +/* + This function restores a subdevice to an idle state. + */ +static void do_become_nonbusy(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + + comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); + if (async) { + comedi_buf_reset(async); + async->inttrig = NULL; + kfree(async->cmd.chanlist); + async->cmd.chanlist = NULL; + } else { + dev_err(dev->class_dev, + "BUG: (?) do_become_nonbusy called with async=NULL\n"); + } + + s->busy = NULL; +} + +static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +{ + int ret = 0; + + if (comedi_is_subdevice_running(s) && s->cancel) + ret = s->cancel(dev, s); + + do_become_nonbusy(dev, s); + + return ret; +} + +static int is_device_busy(struct comedi_device *dev) +{ + struct comedi_subdevice *s; + int i; + + if (!dev->attached) + return 0; + + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + if (s->busy) + return 1; + if (s->async && s->async->mmap_count) + return 1; + } + + return 0; +} + /* COMEDI_DEVCONFIG device config ioctl @@ -335,8 +464,6 @@ static int do_devconfig_ioctl(struct comedi_device *dev, { struct comedi_devconfig it; int ret; - unsigned char *aux_data = NULL; - int aux_len; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -352,36 +479,15 @@ static int do_devconfig_ioctl(struct comedi_device *dev, return 0; } - if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig))) + if (copy_from_user(&it, arg, sizeof(it))) return -EFAULT; it.board_name[COMEDI_NAMELEN - 1] = 0; - if (comedi_aux_data(it.options, 0) && - it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - int bit_shift; - aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - if (aux_len < 0) - return -EFAULT; - - aux_data = vmalloc(aux_len); - if (!aux_data) - return -ENOMEM; - - if (copy_from_user(aux_data, - (unsigned char __user * - )comedi_aux_data(it.options, 0), aux_len)) { - vfree(aux_data); - return -EFAULT; - } - it.options[COMEDI_DEVCONF_AUX_DATA_LO] = - (unsigned long)aux_data; - if (sizeof(void *) > sizeof(int)) { - bit_shift = sizeof(int) * 8; - it.options[COMEDI_DEVCONF_AUX_DATA_HI] = - ((unsigned long)aux_data) >> bit_shift; - } else - it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0; + if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { + dev_warn(dev->class_dev, + "comedi_config --init_data is deprecated\n"); + return -EINVAL; } ret = comedi_device_attach(dev, &it); @@ -392,9 +498,6 @@ static int do_devconfig_ioctl(struct comedi_device *dev, } } - if (aux_data) - vfree(aux_data); - return ret; } @@ -420,7 +523,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, struct comedi_subdevice *s; int retval = 0; - if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) + if (copy_from_user(&bc, arg, sizeof(bc))) return -EFAULT; if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0) @@ -453,7 +556,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, bc.maximum_size = async->max_bufsize; copyback: - if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig))) + if (copy_to_user(arg, &bc, sizeof(bc))) return -EFAULT; return 0; @@ -477,14 +580,10 @@ static int do_devinfo_ioctl(struct comedi_device *dev, struct comedi_devinfo __user *arg, struct file *file) { + const unsigned minor = iminor(file_inode(file)); + struct comedi_file_info *info = comedi_file_info_from_minor(minor); + struct comedi_subdevice *s; struct comedi_devinfo devinfo; - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_subdevice *read_subdev = - comedi_get_read_subdevice(dev_file_info); - struct comedi_subdevice *write_subdev = - comedi_get_write_subdevice(dev_file_info); memset(&devinfo, 0, sizeof(devinfo)); @@ -494,17 +593,19 @@ static int do_devinfo_ioctl(struct comedi_device *dev, strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN); strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN); - if (read_subdev) - devinfo.read_subdevice = read_subdev - dev->subdevices; + s = comedi_read_subdevice(info); + if (s) + devinfo.read_subdevice = s->index; else devinfo.read_subdevice = -1; - if (write_subdev) - devinfo.write_subdevice = write_subdev - dev->subdevices; + s = comedi_write_subdevice(info); + if (s) + devinfo.write_subdevice = s->index; else devinfo.write_subdevice = -1; - if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo))) + if (copy_to_user(arg, &devinfo, sizeof(devinfo))) return -EFAULT; return 0; @@ -531,9 +632,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, struct comedi_subdinfo *tmp, *us; struct comedi_subdevice *s; - tmp = - kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo), - GFP_KERNEL); + tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL); if (!tmp) return -ENOMEM; @@ -545,7 +644,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->type = s->type; us->n_chan = s->n_chan; us->subd_flags = s->subdev_flags; - if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) + if (comedi_is_subdevice_running(s)) us->subd_flags |= SDF_RUNNING; #define TIMER_nanosec 5 /* backwards compatibility */ us->timer_type = TIMER_nanosec; @@ -584,8 +683,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->settling_time_0 = s->settling_time_0; } - ret = copy_to_user(arg, tmp, - dev->n_subdevices * sizeof(struct comedi_subdinfo)); + ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp)); kfree(tmp); @@ -612,7 +710,7 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, struct comedi_subdevice *s; struct comedi_chaninfo it; - if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo))) + if (copy_from_user(&it, arg, sizeof(it))) return -EFAULT; if (it.subdev >= dev->n_subdevices) @@ -679,7 +777,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, struct comedi_subdevice *s; struct comedi_async *async; - if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo))) + if (copy_from_user(&bi, arg, sizeof(bi))) return -EFAULT; if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0) @@ -714,9 +812,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read); comedi_buf_read_free(async, bi.bytes_read); - if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | - SRF_RUNNING)) - && async->buf_write_count == async->buf_read_count) { + if (comedi_is_subdevice_idle(s) && + async->buf_write_count == async->buf_read_count) { do_become_nonbusy(dev, s); } } @@ -734,103 +831,12 @@ copyback_position: bi.buf_read_ptr = async->buf_read_ptr; copyback: - if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo))) + if (copy_to_user(arg, &bi, sizeof(bi))) return -EFAULT; return 0; } -static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, - unsigned int *data, void *file); -/* - * COMEDI_INSNLIST - * synchronous instructions - * - * arg: - * pointer to sync cmd structure - * - * reads: - * sync cmd struct at arg - * instruction list - * data (for writes) - * - * writes: - * data (for reads) - */ -/* arbitrary limits */ -#define MAX_SAMPLES 256 -static int do_insnlist_ioctl(struct comedi_device *dev, - struct comedi_insnlist __user *arg, void *file) -{ - struct comedi_insnlist insnlist; - struct comedi_insn *insns = NULL; - unsigned int *data = NULL; - int i = 0; - int ret = 0; - - if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist))) - return -EFAULT; - - data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); - if (!data) { - DPRINTK("kmalloc failed\n"); - ret = -ENOMEM; - goto error; - } - - insns = - kcalloc(insnlist.n_insns, sizeof(struct comedi_insn), GFP_KERNEL); - if (!insns) { - DPRINTK("kmalloc failed\n"); - ret = -ENOMEM; - goto error; - } - - if (copy_from_user(insns, insnlist.insns, - sizeof(struct comedi_insn) * insnlist.n_insns)) { - DPRINTK("copy_from_user failed\n"); - ret = -EFAULT; - goto error; - } - - for (i = 0; i < insnlist.n_insns; i++) { - if (insns[i].n > MAX_SAMPLES) { - DPRINTK("number of samples too large\n"); - ret = -EINVAL; - goto error; - } - if (insns[i].insn & INSN_MASK_WRITE) { - if (copy_from_user(data, insns[i].data, - insns[i].n * sizeof(unsigned int))) { - DPRINTK("copy_from_user failed\n"); - ret = -EFAULT; - goto error; - } - } - ret = parse_insn(dev, insns + i, data, file); - if (ret < 0) - goto error; - if (insns[i].insn & INSN_MASK_READ) { - if (copy_to_user(insns[i].data, data, - insns[i].n * sizeof(unsigned int))) { - DPRINTK("copy_to_user failed\n"); - ret = -EFAULT; - goto error; - } - } - if (need_resched()) - schedule(); - } - -error: - kfree(insns); - kfree(data); - - if (ret < 0) - return ret; - return i; -} - static int check_insn_config_length(struct comedi_insn *insn, unsigned int *data) { @@ -1062,6 +1068,94 @@ out: } /* + * COMEDI_INSNLIST + * synchronous instructions + * + * arg: + * pointer to sync cmd structure + * + * reads: + * sync cmd struct at arg + * instruction list + * data (for writes) + * + * writes: + * data (for reads) + */ +/* arbitrary limits */ +#define MAX_SAMPLES 256 +static int do_insnlist_ioctl(struct comedi_device *dev, + struct comedi_insnlist __user *arg, void *file) +{ + struct comedi_insnlist insnlist; + struct comedi_insn *insns = NULL; + unsigned int *data = NULL; + int i = 0; + int ret = 0; + + if (copy_from_user(&insnlist, arg, sizeof(insnlist))) + return -EFAULT; + + data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); + if (!data) { + DPRINTK("kmalloc failed\n"); + ret = -ENOMEM; + goto error; + } + + insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL); + if (!insns) { + DPRINTK("kmalloc failed\n"); + ret = -ENOMEM; + goto error; + } + + if (copy_from_user(insns, insnlist.insns, + sizeof(*insns) * insnlist.n_insns)) { + DPRINTK("copy_from_user failed\n"); + ret = -EFAULT; + goto error; + } + + for (i = 0; i < insnlist.n_insns; i++) { + if (insns[i].n > MAX_SAMPLES) { + DPRINTK("number of samples too large\n"); + ret = -EINVAL; + goto error; + } + if (insns[i].insn & INSN_MASK_WRITE) { + if (copy_from_user(data, insns[i].data, + insns[i].n * sizeof(unsigned int))) { + DPRINTK("copy_from_user failed\n"); + ret = -EFAULT; + goto error; + } + } + ret = parse_insn(dev, insns + i, data, file); + if (ret < 0) + goto error; + if (insns[i].insn & INSN_MASK_READ) { + if (copy_to_user(insns[i].data, data, + insns[i].n * sizeof(unsigned int))) { + DPRINTK("copy_to_user failed\n"); + ret = -EFAULT; + goto error; + } + } + if (need_resched()) + schedule(); + } + +error: + kfree(insns); + kfree(data); + + if (ret < 0) + return ret; + return i; +} + +/* * COMEDI_INSN * synchronous instructions * @@ -1088,7 +1182,7 @@ static int do_insn_ioctl(struct comedi_device *dev, goto error; } - if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) { + if (copy_from_user(&insn, arg, sizeof(insn))) { ret = -EFAULT; goto error; } @@ -1123,17 +1217,6 @@ error: return ret; } -static void comedi_set_subdevice_runflags(struct comedi_subdevice *s, - unsigned mask, unsigned bits) -{ - unsigned long flags; - - spin_lock_irqsave(&s->spin_lock, flags); - s->runflags &= ~mask; - s->runflags |= (bits & mask); - spin_unlock_irqrestore(&s->spin_lock, flags); -} - static int do_cmd_ioctl(struct comedi_device *dev, struct comedi_cmd __user *arg, void *file) { @@ -1143,7 +1226,7 @@ static int do_cmd_ioctl(struct comedi_device *dev, int ret = 0; unsigned int __user *user_chanlist; - if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) { + if (copy_from_user(&cmd, arg, sizeof(cmd))) { DPRINTK("bad cmd address\n"); return -EFAULT; } @@ -1233,7 +1316,7 @@ static int do_cmd_ioctl(struct comedi_device *dev, /* restore chanlist pointer before copying back */ cmd.chanlist = (unsigned int __force *)user_chanlist; cmd.data = NULL; - if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) { + if (copy_to_user(arg, &cmd, sizeof(cmd))) { DPRINTK("fault writing cmd\n"); ret = -EFAULT; goto cleanup; @@ -1248,7 +1331,7 @@ static int do_cmd_ioctl(struct comedi_device *dev, goto cleanup; } - comedi_reset_async_buf(async); + comedi_buf_reset(async); async->cb_mask = COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | @@ -1292,7 +1375,7 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, unsigned int *chanlist = NULL; unsigned int __user *user_chanlist; - if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) { + if (copy_from_user(&cmd, arg, sizeof(cmd))) { DPRINTK("bad cmd address\n"); return -EFAULT; } @@ -1356,7 +1439,7 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, /* restore chanlist pointer before copying back */ cmd.chanlist = (unsigned int __force *)user_chanlist; - if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) { + if (copy_to_user(arg, &cmd, sizeof(cmd))) { DPRINTK("bad cmd address\n"); ret = -EFAULT; goto cleanup; @@ -1532,26 +1615,29 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev; + const unsigned minor = iminor(file_inode(file)); + struct comedi_file_info *info = comedi_file_info_from_minor(minor); + struct comedi_device *dev = comedi_dev_from_file_info(info); int rc; - if (dev_file_info == NULL || dev_file_info->device == NULL) + if (!dev) return -ENODEV; - dev = dev_file_info->device; mutex_lock(&dev->mutex); /* Device config is special, because it must work on * an unconfigured device. */ if (cmd == COMEDI_DEVCONFIG) { + if (minor >= COMEDI_NUM_BOARD_MINORS) { + /* Device config not appropriate on non-board minors. */ + rc = -ENOTTY; + goto done; + } rc = do_devconfig_ioctl(dev, (struct comedi_devconfig __user *)arg); if (rc == 0) /* Evade comedi_auto_unconfig(). */ - dev_file_info->hardware_device = NULL; + info->hardware_device = NULL; goto done; } @@ -1624,19 +1710,6 @@ done: return rc; } -static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - int ret = 0; - - if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel) - ret = s->cancel(dev, s); - - do_become_nonbusy(dev, s); - - return ret; -} - - static void comedi_vm_open(struct vm_area_struct *area) { struct comedi_async *async; @@ -1670,41 +1743,39 @@ static struct vm_operations_struct comedi_vm_ops = { static int comedi_mmap(struct file *file, struct vm_area_struct *vma) { - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_async *async = NULL; + const unsigned minor = iminor(file_inode(file)); + struct comedi_file_info *info = comedi_file_info_from_minor(minor); + struct comedi_device *dev = comedi_dev_from_file_info(info); + struct comedi_subdevice *s; + struct comedi_async *async; unsigned long start = vma->vm_start; unsigned long size; int n_pages; int i; int retval; - struct comedi_subdevice *s; - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) + if (!dev) return -ENODEV; mutex_lock(&dev->mutex); + if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); retval = -ENODEV; goto done; } + if (vma->vm_flags & VM_WRITE) - s = comedi_get_write_subdevice(dev_file_info); + s = comedi_write_subdevice(info); else - s = comedi_get_read_subdevice(dev_file_info); - - if (s == NULL) { + s = comedi_read_subdevice(info); + if (!s) { retval = -EINVAL; goto done; } + async = s->async; - if (async == NULL) { + if (!async) { retval = -EINVAL; goto done; } @@ -1727,11 +1798,11 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) n_pages = size >> PAGE_SHIFT; for (i = 0; i < n_pages; ++i) { + struct comedi_buf_page *buf = &async->buf_page_list[i]; + if (remap_pfn_range(vma, start, - page_to_pfn(virt_to_page - (async->buf_page_list - [i].virt_addr)), PAGE_SIZE, - PAGE_SHARED)) { + page_to_pfn(virt_to_page(buf->virt_addr)), + PAGE_SIZE, PAGE_SHARED)) { retval = -EAGAIN; goto done; } @@ -1752,51 +1823,41 @@ done: static unsigned int comedi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_subdevice *read_subdev; - struct comedi_subdevice *write_subdev; - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); + const unsigned minor = iminor(file_inode(file)); + struct comedi_file_info *info = comedi_file_info_from_minor(minor); + struct comedi_device *dev = comedi_dev_from_file_info(info); + struct comedi_subdevice *s; - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) + if (!dev) return -ENODEV; mutex_lock(&dev->mutex); + if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); - mutex_unlock(&dev->mutex); - return 0; + goto done; } - mask = 0; - read_subdev = comedi_get_read_subdevice(dev_file_info); - if (read_subdev) { - poll_wait(file, &read_subdev->async->wait_head, wait); - if (!read_subdev->busy - || comedi_buf_read_n_available(read_subdev->async) > 0 - || !(comedi_get_subdevice_runflags(read_subdev) & - SRF_RUNNING)) { + s = comedi_read_subdevice(info); + if (s && s->async) { + poll_wait(file, &s->async->wait_head, wait); + if (!s->busy || !comedi_is_subdevice_running(s) || + comedi_buf_read_n_available(s->async) > 0) mask |= POLLIN | POLLRDNORM; - } } - write_subdev = comedi_get_write_subdevice(dev_file_info); - if (write_subdev) { - poll_wait(file, &write_subdev->async->wait_head, wait); - comedi_buf_write_alloc(write_subdev->async, - write_subdev->async->prealloc_bufsz); - if (!write_subdev->busy - || !(comedi_get_subdevice_runflags(write_subdev) & - SRF_RUNNING) - || comedi_buf_write_n_allocated(write_subdev->async) >= - bytes_per_sample(write_subdev->async->subdevice)) { + + s = comedi_write_subdevice(info); + if (s && s->async) { + unsigned int bps = bytes_per_sample(s->async->subdevice); + + poll_wait(file, &s->async->wait_head, wait); + comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); + if (!s->busy || !comedi_is_subdevice_running(s) || + comedi_buf_write_n_allocated(s->async) >= bps) mask |= POLLOUT | POLLWRNORM; - } } +done: mutex_unlock(&dev->mutex); return mask; } @@ -1808,54 +1869,39 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, struct comedi_async *async; int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); + const unsigned minor = iminor(file_inode(file)); + struct comedi_file_info *info = comedi_file_info_from_minor(minor); + struct comedi_device *dev = comedi_dev_from_file_info(info); - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) + if (!dev) return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); - retval = -ENODEV; - goto done; + return -ENODEV; } - s = comedi_get_write_subdevice(dev_file_info); - if (s == NULL) { - retval = -EIO; - goto done; - } + s = comedi_write_subdevice(info); + if (!s || !s->async) + return -EIO; + async = s->async; - if (!nbytes) { - retval = 0; - goto done; - } - if (!s->busy) { - retval = 0; - goto done; - } - if (s->busy != file) { - retval = -EACCES; - goto done; - } + if (!s->busy || !nbytes) + return 0; + if (s->busy != file) + return -EACCES; + add_wait_queue(&async->wait_head, &wait); while (nbytes > 0 && !retval) { set_current_state(TASK_INTERRUPTIBLE); - if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { + if (!comedi_is_subdevice_running(s)) { if (count == 0) { - if (comedi_get_subdevice_runflags(s) & - SRF_ERROR) { + if (comedi_is_subdevice_in_error(s)) retval = -EPIPE; - } else { + else retval = 0; - } do_become_nonbusy(dev, s); } break; @@ -1908,7 +1954,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, set_current_state(TASK_RUNNING); remove_wait_queue(&async->wait_head, &wait); -done: return count ? count : retval; } @@ -1919,41 +1964,27 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, struct comedi_async *async; int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); + const unsigned minor = iminor(file_inode(file)); + struct comedi_file_info *info = comedi_file_info_from_minor(minor); + struct comedi_device *dev = comedi_dev_from_file_info(info); - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) + if (!dev) return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); - retval = -ENODEV; - goto done; + return -ENODEV; } - s = comedi_get_read_subdevice(dev_file_info); - if (s == NULL) { - retval = -EIO; - goto done; - } + s = comedi_read_subdevice(info); + if (!s || !s->async) + return -EIO; + async = s->async; - if (!nbytes) { - retval = 0; - goto done; - } - if (!s->busy) { - retval = 0; - goto done; - } - if (s->busy != file) { - retval = -EACCES; - goto done; - } + if (!s->busy || !nbytes) + return 0; + if (s->busy != file) + return -EACCES; add_wait_queue(&async->wait_head, &wait); while (nbytes > 0 && !retval) { @@ -1970,14 +2001,12 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, n = m; if (n == 0) { - if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { + if (!comedi_is_subdevice_running(s)) { do_become_nonbusy(dev, s); - if (comedi_get_subdevice_runflags(s) & - SRF_ERROR) { + if (comedi_is_subdevice_in_error(s)) retval = -EPIPE; - } else { + else retval = 0; - } break; } if (file->f_flags & O_NONBLOCK) { @@ -2015,48 +2044,22 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, buf += n; break; /* makes device work like a pipe */ } - if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) && + if (comedi_is_subdevice_idle(s) && async->buf_read_count - async->buf_write_count == 0) { do_become_nonbusy(dev, s); } set_current_state(TASK_RUNNING); remove_wait_queue(&async->wait_head, &wait); -done: return count ? count : retval; } -/* - This function restores a subdevice to an idle state. - */ -static void do_become_nonbusy(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct comedi_async *async = s->async; - - comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); - if (async) { - comedi_reset_async_buf(async); - async->inttrig = NULL; - kfree(async->cmd.chanlist); - async->cmd.chanlist = NULL; - } else { - dev_err(dev->class_dev, - "BUG: (?) do_become_nonbusy called with async=NULL\n"); - } - - s->busy = NULL; -} - static int comedi_open(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = - dev_file_info ? dev_file_info->device : NULL; + struct comedi_device *dev = comedi_dev_from_minor(minor); - if (dev == NULL) { + if (!dev) { DPRINTK("invalid minor number\n"); return -ENODEV; } @@ -2128,19 +2131,25 @@ ok: return 0; } +static int comedi_fasync(int fd, struct file *file, int on) +{ + const unsigned minor = iminor(file_inode(file)); + struct comedi_device *dev = comedi_dev_from_minor(minor); + + if (!dev) + return -ENODEV; + + return fasync_helper(fd, file, on, &dev->async_queue); +} + static int comedi_close(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); + struct comedi_device *dev = comedi_dev_from_minor(minor); struct comedi_subdevice *s = NULL; int i; - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) + if (!dev) return -ENODEV; mutex_lock(&dev->mutex); @@ -2172,22 +2181,6 @@ static int comedi_close(struct inode *inode, struct file *file) return 0; } -static int comedi_fasync(int fd, struct file *file, int on) -{ - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); - - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) - return -ENODEV; - - return fasync_helper(fd, file, on, &dev->async_queue); -} - static const struct file_operations comedi_fops = { .owner = THIS_MODULE, .unlocked_ioctl = comedi_unlocked_ioctl, @@ -2205,99 +2198,6 @@ static const struct file_operations comedi_fops = { static struct class *comedi_class; static struct cdev comedi_cdev; -static void comedi_cleanup_legacy_minors(void) -{ - unsigned i; - - for (i = 0; i < comedi_num_legacy_minors; i++) - comedi_free_board_minor(i); -} - -static int __init comedi_init(void) -{ - int i; - int retval; - - pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n"); - - if (comedi_num_legacy_minors < 0 || - comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { - pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n", - COMEDI_NUM_BOARD_MINORS); - return -EINVAL; - } - - /* - * comedi is unusable if both comedi_autoconfig and - * comedi_num_legacy_minors are zero, so we might as well adjust the - * defaults in that case - */ - if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) - comedi_num_legacy_minors = 16; - - memset(comedi_file_info_table, 0, - sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); - - retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS, "comedi"); - if (retval) - return -EIO; - cdev_init(&comedi_cdev, &comedi_fops); - comedi_cdev.owner = THIS_MODULE; - kobject_set_name(&comedi_cdev.kobj, "comedi"); - if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return -EIO; - } - comedi_class = class_create(THIS_MODULE, "comedi"); - if (IS_ERR(comedi_class)) { - pr_err("comedi: failed to create class\n"); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return PTR_ERR(comedi_class); - } - - comedi_class->dev_attrs = comedi_dev_attrs; - - /* XXX requires /proc interface */ - comedi_proc_init(); - - /* create devices files for legacy/manual use */ - for (i = 0; i < comedi_num_legacy_minors; i++) { - int minor; - minor = comedi_alloc_board_minor(NULL); - if (minor < 0) { - comedi_cleanup_legacy_minors(); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return minor; - } - } - - return 0; -} - -static void __exit comedi_cleanup(void) -{ - int i; - - comedi_cleanup_legacy_minors(); - for (i = 0; i < COMEDI_NUM_MINORS; ++i) - BUG_ON(comedi_file_info_table[i]); - - class_destroy(comedi_class); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); - - comedi_proc_cleanup(); -} - -module_init(comedi_init); -module_exit(comedi_cleanup); - void comedi_error(const struct comedi_device *dev, const char *s) { dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s); @@ -2312,7 +2212,7 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) /* DPRINTK("comedi_event 0x%x\n",mask); */ - if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) + if (!comedi_is_subdevice_running(s)) return; if (s-> @@ -2347,40 +2247,9 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) } EXPORT_SYMBOL(comedi_event); -unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) -{ - unsigned long flags; - unsigned runflags; - - spin_lock_irqsave(&s->spin_lock, flags); - runflags = s->runflags; - spin_unlock_irqrestore(&s->spin_lock, flags); - return runflags; -} -EXPORT_SYMBOL(comedi_get_subdevice_runflags); - -static int is_device_busy(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int i; - - if (!dev->attached) - return 0; - - for (i = 0; i < dev->n_subdevices; i++) { - s = &dev->subdevices[i]; - if (s->busy) - return 1; - if (s->async && s->async->mmap_count) - return 1; - } - - return 0; -} - static void comedi_device_init(struct comedi_device *dev) { - memset(dev, 0, sizeof(struct comedi_device)); + memset(dev, 0, sizeof(*dev)); spin_lock_init(&dev->spinlock); mutex_init(&dev->mutex); dev->minor = -1; @@ -2398,11 +2267,11 @@ static void comedi_device_cleanup(struct comedi_device *dev) int comedi_alloc_board_minor(struct device *hardware_device) { - struct comedi_device_file_info *info; + struct comedi_file_info *info; struct device *csdev; unsigned i; - info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) return -ENOMEM; info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); @@ -2439,7 +2308,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) void comedi_free_board_minor(unsigned minor) { - struct comedi_device_file_info *info; + struct comedi_file_info *info; BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); spin_lock(&comedi_file_info_table_lock); @@ -2464,7 +2333,7 @@ void comedi_free_board_minor(unsigned minor) int comedi_find_board_minor(struct device *hardware_device) { int minor; - struct comedi_device_file_info *info; + struct comedi_file_info *info; for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) { spin_lock(&comedi_file_info_table_lock); @@ -2478,19 +2347,21 @@ int comedi_find_board_minor(struct device *hardware_device) return -ENODEV; } -int comedi_alloc_subdevice_minor(struct comedi_device *dev, - struct comedi_subdevice *s) +int comedi_alloc_subdevice_minor(struct comedi_subdevice *s) { - struct comedi_device_file_info *info; + struct comedi_device *dev = s->device; + struct comedi_file_info *info; struct device *csdev; unsigned i; - info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); - if (info == NULL) + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) return -ENOMEM; info->device = dev; - info->read_subdevice = s; - info->write_subdevice = s; + if (s->subdev_flags & SDF_CMD_READ) + info->read_subdevice = s; + if (s->subdev_flags & SDF_CMD_WRITE) + info->write_subdevice = s; spin_lock(&comedi_file_info_table_lock); for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { if (comedi_file_info_table[i] == NULL) { @@ -2501,23 +2372,23 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, spin_unlock(&comedi_file_info_table_lock); if (i == COMEDI_NUM_MINORS) { kfree(info); - pr_err("comedi: error: ran out of minor numbers for board device files.\n"); + pr_err("comedi: error: ran out of minor numbers for subdevice files.\n"); return -EBUSY; } s->minor = i; csdev = device_create(comedi_class, dev->class_dev, MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i", - dev->minor, (int)(s - dev->subdevices)); + dev->minor, s->index); if (!IS_ERR(csdev)) s->class_dev = csdev; dev_set_drvdata(csdev, info); - return i; + return 0; } void comedi_free_subdevice_minor(struct comedi_subdevice *s) { - struct comedi_device_file_info *info; + struct comedi_file_info *info; if (s == NULL) return; @@ -2539,14 +2410,90 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s) kfree(info); } -struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) +static void comedi_cleanup_board_minors(void) { - struct comedi_device_file_info *info; + unsigned i; - BUG_ON(minor >= COMEDI_NUM_MINORS); - spin_lock(&comedi_file_info_table_lock); - info = comedi_file_info_table[minor]; - spin_unlock(&comedi_file_info_table_lock); - return info; + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) + comedi_free_board_minor(i); +} + +static int __init comedi_init(void) +{ + int i; + int retval; + + pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n"); + + if (comedi_num_legacy_minors < 0 || + comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { + pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n", + COMEDI_NUM_BOARD_MINORS); + return -EINVAL; + } + + memset(comedi_file_info_table, 0, + sizeof(struct comedi_file_info *) * COMEDI_NUM_MINORS); + + retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS, "comedi"); + if (retval) + return -EIO; + cdev_init(&comedi_cdev, &comedi_fops); + comedi_cdev.owner = THIS_MODULE; + kobject_set_name(&comedi_cdev.kobj, "comedi"); + if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return -EIO; + } + comedi_class = class_create(THIS_MODULE, "comedi"); + if (IS_ERR(comedi_class)) { + pr_err("comedi: failed to create class\n"); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return PTR_ERR(comedi_class); + } + + comedi_class->dev_attrs = comedi_dev_attrs; + + /* XXX requires /proc interface */ + comedi_proc_init(); + + /* create devices files for legacy/manual use */ + for (i = 0; i < comedi_num_legacy_minors; i++) { + int minor; + minor = comedi_alloc_board_minor(NULL); + if (minor < 0) { + comedi_cleanup_board_minors(); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return minor; + } + } + + return 0; } -EXPORT_SYMBOL_GPL(comedi_get_device_file_info); +module_init(comedi_init); + +static void __exit comedi_cleanup(void) +{ + int i; + + comedi_cleanup_board_minors(); + for (i = 0; i < COMEDI_NUM_MINORS; ++i) + BUG_ON(comedi_file_info_table[i]); + + class_destroy(comedi_class); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); + + comedi_proc_cleanup(); +} +module_exit(comedi_cleanup); + +MODULE_AUTHOR("http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi core module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h index e70ef0515d9a..b3743135f4aa 100644 --- a/drivers/staging/comedi/comedi_internal.h +++ b/drivers/staging/comedi/comedi_internal.h @@ -8,18 +8,43 @@ */ int do_rangeinfo_ioctl(struct comedi_device *dev, struct comedi_rangeinfo __user *arg); -int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); int comedi_alloc_board_minor(struct device *hardware_device); void comedi_free_board_minor(unsigned minor); int comedi_find_board_minor(struct device *hardware_device); -void comedi_reset_async_buf(struct comedi_async *async); +int comedi_alloc_subdevice_minor(struct comedi_subdevice *s); +void comedi_free_subdevice_minor(struct comedi_subdevice *s); + int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); +void comedi_buf_reset(struct comedi_async *async); +unsigned int comedi_buf_write_n_allocated(struct comedi_async *async); extern unsigned int comedi_default_buf_size_kb; extern unsigned int comedi_default_buf_maxsize_kb; -extern bool comedi_autoconfig; + +/* drivers.c */ + extern struct comedi_driver *comedi_drivers; +int insn_inval(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + +void comedi_device_detach(struct comedi_device *); +int comedi_device_attach(struct comedi_device *, struct comedi_devconfig *); + +#ifdef CONFIG_PROC_FS + +/* proc.c */ + +void comedi_proc_init(void); +void comedi_proc_cleanup(void); +#else +static inline void comedi_proc_init(void) +{ +} +static inline void comedi_proc_cleanup(void) +{ +} +#endif + #endif /* _COMEDI_INTERNAL_H */ diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/staging/comedi/comedi_pci.c new file mode 100644 index 000000000000..37d2e4677360 --- /dev/null +++ b/drivers/staging/comedi/comedi_pci.c @@ -0,0 +1,140 @@ +/* + * comedi_pci.c + * Comedi PCI driver specific functions. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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> + +#include "comedidev.h" + +/** + * comedi_to_pci_dev() - comedi_device pointer to pci_dev pointer. + * @dev: comedi_device struct + */ +struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) +{ + return dev->hw_dev ? to_pci_dev(dev->hw_dev) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_pci_dev); + +/** + * comedi_pci_enable() - Enable the PCI device and request the regions. + * @pcidev: pci_dev struct + * @res_name: name for the requested reqource + */ +int comedi_pci_enable(struct pci_dev *pcidev, const char *res_name) +{ + int rc; + + rc = pci_enable_device(pcidev); + if (rc < 0) + return rc; + + rc = pci_request_regions(pcidev, res_name); + if (rc < 0) + pci_disable_device(pcidev); + + return rc; +} +EXPORT_SYMBOL_GPL(comedi_pci_enable); + +/** + * comedi_pci_disable() - Release the regions and disable the PCI device. + * @pcidev: pci_dev struct + * + * This must be matched with a previous successful call to comedi_pci_enable(). + */ +void comedi_pci_disable(struct pci_dev *pcidev) +{ + pci_release_regions(pcidev); + pci_disable_device(pcidev); +} +EXPORT_SYMBOL_GPL(comedi_pci_disable); + +/** + * comedi_pci_auto_config() - Configure/probe a comedi PCI driver. + * @pcidev: pci_dev struct + * @driver: comedi_driver struct + * + * Typically called from the pci_driver (*probe) function. + */ +int comedi_pci_auto_config(struct pci_dev *pcidev, + struct comedi_driver *driver) +{ + return comedi_auto_config(&pcidev->dev, driver, 0); +} +EXPORT_SYMBOL_GPL(comedi_pci_auto_config); + +/** + * comedi_pci_auto_unconfig() - Unconfigure/remove a comedi PCI driver. + * @pcidev: pci_dev struct + * + * Typically called from the pci_driver (*remove) function. + */ +void comedi_pci_auto_unconfig(struct pci_dev *pcidev) +{ + comedi_auto_unconfig(&pcidev->dev); +} +EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); + +/** + * comedi_pci_driver_register() - Register a comedi PCI driver. + * @comedi_driver: comedi_driver struct + * @pci_driver: pci_driver struct + * + * This function is used for the module_init() of comedi PCI drivers. + * Do not call it directly, use the module_comedi_pci_driver() helper + * macro instead. + */ +int comedi_pci_driver_register(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = pci_register_driver(pci_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_register); + +/** + * comedi_pci_driver_unregister() - Unregister a comedi PCI driver. + * @comedi_driver: comedi_driver struct + * @pci_driver: pci_driver struct + * + * This function is used for the module_exit() of comedi PCI drivers. + * Do not call it directly, use the module_comedi_pci_driver() helper + * macro instead. + */ +void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + pci_unregister_driver(pci_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister); diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/staging/comedi/comedi_pcmcia.c new file mode 100644 index 000000000000..453ff3b28617 --- /dev/null +++ b/drivers/staging/comedi/comedi_pcmcia.c @@ -0,0 +1,160 @@ +/* + * comedi_pcmcia.c + * Comedi PCMCIA driver specific functions. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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> + +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> + +#include "comedidev.h" + +/** + * comedi_to_pcmcia_dev() - comedi_device pointer to pcmcia_device pointer. + * @dev: comedi_device struct + */ +struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *dev) +{ + return dev->hw_dev ? to_pcmcia_dev(dev->hw_dev) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_pcmcia_dev); + +static int comedi_pcmcia_conf_check(struct pcmcia_device *link, + void *priv_data) +{ + if (link->config_index == 0) + return -EINVAL; + + return pcmcia_request_io(link); +} + +/** + * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device. + * @dev: comedi_device struct + * @conf_check: optional callback to check the pcmcia_device configuration + * + * The comedi PCMCIA driver needs to set the link->config_flags, as + * appropriate for that driver, before calling this function in order + * to allow pcmcia_loop_config() to do its internal autoconfiguration. + */ +int comedi_pcmcia_enable(struct comedi_device *dev, + int (*conf_check)(struct pcmcia_device *, void *)) +{ + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + int ret; + + if (!link) + return -ENODEV; + + if (!conf_check) + conf_check = comedi_pcmcia_conf_check; + + ret = pcmcia_loop_config(link, conf_check, NULL); + if (ret) + return ret; + + return pcmcia_enable_device(link); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_enable); + +/** + * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions. + * @dev: comedi_device struct + */ +void comedi_pcmcia_disable(struct comedi_device *dev) +{ + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + + if (link) + pcmcia_disable_device(link); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_disable); + +/** + * comedi_pcmcia_auto_config() - Configure/probe a comedi PCMCIA driver. + * @link: pcmcia_device struct + * @driver: comedi_driver struct + * + * Typically called from the pcmcia_driver (*probe) function. + */ +int comedi_pcmcia_auto_config(struct pcmcia_device *link, + struct comedi_driver *driver) +{ + return comedi_auto_config(&link->dev, driver, 0); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_config); + +/** + * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a comedi PCMCIA driver. + * @link: pcmcia_device struct + * + * Typically called from the pcmcia_driver (*remove) function. + */ +void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) +{ + comedi_auto_unconfig(&link->dev); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_unconfig); + +/** + * comedi_pcmcia_driver_register() - Register a comedi PCMCIA driver. + * @comedi_driver: comedi_driver struct + * @pcmcia_driver: pcmcia_driver struct + * + * This function is used for the module_init() of comedi USB drivers. + * Do not call it directly, use the module_comedi_pcmcia_driver() helper + * macro instead. + */ +int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver, + struct pcmcia_driver *pcmcia_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = pcmcia_register_driver(pcmcia_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_register); + +/** + * comedi_pcmcia_driver_unregister() - Unregister a comedi PCMCIA driver. + * @comedi_driver: comedi_driver struct + * @pcmcia_driver: pcmcia_driver struct + * + * This function is used for the module_exit() of comedi PCMCIA drivers. + * Do not call it directly, use the module_comedi_pcmcia_driver() helper + * macro instead. + */ +void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver, + struct pcmcia_driver *pcmcia_driver) +{ + pcmcia_unregister_driver(pcmcia_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_unregister); diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/staging/comedi/comedi_usb.c new file mode 100644 index 000000000000..9d9716a248f1 --- /dev/null +++ b/drivers/staging/comedi/comedi_usb.c @@ -0,0 +1,108 @@ +/* + * comedi_usb.c + * Comedi USB driver specific functions. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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> + +#include "comedidev.h" + +/** + * comedi_to_usb_interface() - comedi_device pointer to usb_interface pointer. + * @dev: comedi_device struct + */ +struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev) +{ + return dev->hw_dev ? to_usb_interface(dev->hw_dev) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_usb_interface); + +/** + * comedi_usb_auto_config() - Configure/probe a comedi USB driver. + * @intf: usb_interface struct + * @driver: comedi_driver struct + * @context: driver specific data, passed to comedi_auto_config() + * + * Typically called from the usb_driver (*probe) function. + */ +int comedi_usb_auto_config(struct usb_interface *intf, + struct comedi_driver *driver, + unsigned long context) +{ + return comedi_auto_config(&intf->dev, driver, context); +} +EXPORT_SYMBOL_GPL(comedi_usb_auto_config); + +/** + * comedi_pci_auto_unconfig() - Unconfigure/disconnect a comedi USB driver. + * @intf: usb_interface struct + * + * Typically called from the usb_driver (*disconnect) function. + */ +void comedi_usb_auto_unconfig(struct usb_interface *intf) +{ + comedi_auto_unconfig(&intf->dev); +} +EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig); + +/** + * comedi_usb_driver_register() - Register a comedi USB driver. + * @comedi_driver: comedi_driver struct + * @usb_driver: usb_driver struct + * + * This function is used for the module_init() of comedi USB drivers. + * Do not call it directly, use the module_comedi_usb_driver() helper + * macro instead. + */ +int comedi_usb_driver_register(struct comedi_driver *comedi_driver, + struct usb_driver *usb_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = usb_register(usb_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_usb_driver_register); + +/** + * comedi_usb_driver_unregister() - Unregister a comedi USB driver. + * @comedi_driver: comedi_driver struct + * @usb_driver: usb_driver struct + * + * This function is used for the module_exit() of comedi USB drivers. + * Do not call it directly, use the module_comedi_usb_driver() helper + * macro instead. + */ +void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver, + struct usb_driver *usb_driver) +{ + usb_deregister(usb_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister); diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index 692e1e615d44..f3a990b45df5 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -40,8 +40,6 @@ #include <linux/uaccess.h> #include <linux/io.h> #include <linux/timer.h> -#include <linux/pci.h> -#include <linux/usb.h> #include "comedi.h" @@ -55,28 +53,13 @@ COMEDI_MINORVERSION, COMEDI_MICROVERSION) #define COMEDI_RELEASE VERSION -/* - * PCI Vendor IDs not in <linux/pci_ids.h> - */ -#define PCI_VENDOR_ID_KOLTER 0x1001 -#define PCI_VENDOR_ID_ICP 0x104c -#define PCI_VENDOR_ID_AMCC 0x10e8 -#define PCI_VENDOR_ID_DT 0x1116 -#define PCI_VENDOR_ID_IOTECH 0x1616 -#define PCI_VENDOR_ID_CONTEC 0x1221 -#define PCI_VENDOR_ID_CB 0x1307 /* Measurement Computing */ -#define PCI_VENDOR_ID_ADVANTECH 0x13fe -#define PCI_VENDOR_ID_MEILHAUS 0x1402 -#define PCI_VENDOR_ID_RTD 0x1435 -#define PCI_VENDOR_ID_ADLINK 0x144a -#define PCI_VENDOR_ID_AMPLICON 0x14dc - #define COMEDI_NUM_MINORS 0x100 #define COMEDI_NUM_BOARD_MINORS 0x30 #define COMEDI_FIRST_SUBDEVICE_MINOR COMEDI_NUM_BOARD_MINORS struct comedi_subdevice { struct comedi_device *device; + int index; int type; int n_chan; int subdev_flags; @@ -250,13 +233,6 @@ static inline const void *comedi_board(const struct comedi_device *dev) return dev->board_ptr; } -struct comedi_device_file_info { - struct comedi_device *device; - struct comedi_subdevice *read_subdevice; - struct comedi_subdevice *write_subdevice; - struct device *hardware_device; -}; - #ifdef CONFIG_COMEDI_DEBUG extern int comedi_debug; #else @@ -280,105 +256,13 @@ enum comedi_minor_bits { static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4; static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1; -struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor); - -static inline struct comedi_subdevice *comedi_get_read_subdevice( - const struct comedi_device_file_info *info) -{ - if (info->read_subdevice) - return info->read_subdevice; - if (info->device == NULL) - return NULL; - return info->device->read_subdev; -} - -static inline struct comedi_subdevice *comedi_get_write_subdevice( - const struct comedi_device_file_info *info) -{ - if (info->write_subdevice) - return info->write_subdevice; - if (info->device == NULL) - return NULL; - return info->device->write_subdev; -} - -int comedi_alloc_subdevices(struct comedi_device *, int); - -void comedi_device_detach(struct comedi_device *dev); -int comedi_device_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -int comedi_driver_register(struct comedi_driver *); -int comedi_driver_unregister(struct comedi_driver *); - -/** - * module_comedi_driver() - Helper macro for registering a comedi driver - * @__comedi_driver: comedi_driver struct - * - * Helper macro for comedi drivers which do not do anything special in module - * init/exit. This eliminates a lot of boilerplate. Each module may only use - * this macro once, and calling it replaces module_init() and module_exit(). - */ -#define module_comedi_driver(__comedi_driver) \ - module_driver(__comedi_driver, comedi_driver_register, \ - comedi_driver_unregister) - -int comedi_pci_enable(struct pci_dev *, const char *); -void comedi_pci_disable(struct pci_dev *); - -int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *); -void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *); - -/** - * module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver - * @__comedi_driver: comedi_driver struct - * @__pci_driver: pci_driver struct - * - * Helper macro for comedi PCI drivers which do not do anything special - * in module init/exit. This eliminates a lot of boilerplate. Each - * module may only use this macro once, and calling it replaces - * module_init() and module_exit() - */ -#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \ - module_driver(__comedi_driver, comedi_pci_driver_register, \ - comedi_pci_driver_unregister, &(__pci_driver)) - -struct usb_driver; - -int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *); -void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *); - -/** - * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver - * @__comedi_driver: comedi_driver struct - * @__usb_driver: usb_driver struct - * - * Helper macro for comedi USB drivers which do not do anything special - * in module init/exit. This eliminates a lot of boilerplate. Each - * module may only use this macro once, and calling it replaces - * module_init() and module_exit() - */ -#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \ - module_driver(__comedi_driver, comedi_usb_driver_register, \ - comedi_usb_driver_unregister, &(__usb_driver)) +struct comedi_device *comedi_dev_from_minor(unsigned minor); void init_polling(void); void cleanup_polling(void); void start_polling(struct comedi_device *); void stop_polling(struct comedi_device *); -#ifdef CONFIG_PROC_FS -void comedi_proc_init(void); -void comedi_proc_cleanup(void); -#else -static inline void comedi_proc_init(void) -{ -} - -static inline void comedi_proc_cleanup(void) -{ -} -#endif - /* subdevice runflags */ enum subdevice_runflags { SRF_USER = 0x00000001, @@ -389,10 +273,11 @@ enum subdevice_runflags { SRF_RUNNING = 0x08000000 }; +bool comedi_is_subdevice_running(struct comedi_subdevice *s); + int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist); -unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s); /* range stuff */ @@ -433,111 +318,186 @@ static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) return sizeof(short); } -/* must be used in attach to set dev->hw_dev if you wish to dma directly -into comedi's buffer */ -static inline void comedi_set_hw_dev(struct comedi_device *dev, - struct device *hw_dev) -{ - if (dev->hw_dev == hw_dev) - return; - if (dev->hw_dev) - put_device(dev->hw_dev); - dev->hw_dev = hw_dev; - if (dev->hw_dev) { - dev->hw_dev = get_device(dev->hw_dev); - BUG_ON(dev->hw_dev == NULL); - } -} +/* + * Must set dev->hw_dev if you wish to dma directly into comedi's buffer. + * Also useful for retrieving a previously configured hardware device of + * known bus type. Set automatically for auto-configured devices. + * Automatically set to NULL when detaching hardware device. + */ +int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev); -static inline struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) -{ - return dev->hw_dev ? to_pci_dev(dev->hw_dev) : NULL; -} +unsigned int comedi_buf_write_alloc(struct comedi_async *, unsigned int); +unsigned int comedi_buf_write_free(struct comedi_async *, unsigned int); -static inline struct usb_interface * -comedi_to_usb_interface(struct comedi_device *dev) -{ - return dev->hw_dev ? to_usb_interface(dev->hw_dev) : NULL; -} +unsigned int comedi_buf_read_n_available(struct comedi_async *); +unsigned int comedi_buf_read_alloc(struct comedi_async *, unsigned int); +unsigned int comedi_buf_read_free(struct comedi_async *, unsigned int); + +int comedi_buf_put(struct comedi_async *, short); +int comedi_buf_get(struct comedi_async *, short *); -int comedi_buf_put(struct comedi_async *async, short x); -int comedi_buf_get(struct comedi_async *async, short *x); - -unsigned int comedi_buf_write_n_available(struct comedi_async *async); -unsigned int comedi_buf_write_alloc(struct comedi_async *async, - unsigned int nbytes); -unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async, - unsigned int nbytes); -unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes); -unsigned comedi_buf_read_alloc(struct comedi_async *async, unsigned nbytes); -unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes); -unsigned int comedi_buf_read_n_available(struct comedi_async *async); void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, const void *source, unsigned int num_bytes); void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, void *destination, unsigned int num_bytes); -static inline unsigned comedi_buf_write_n_allocated(struct comedi_async *async) -{ - return async->buf_write_alloc_count - async->buf_write_count; -} -static inline unsigned comedi_buf_read_n_allocated(struct comedi_async *async) -{ - return async->buf_read_alloc_count - async->buf_read_count; -} +/* drivers.c - general comedi driver functions */ -static inline void *comedi_aux_data(int options[], int n) -{ - unsigned long address; - unsigned long addressLow; - int bit_shift; - if (sizeof(int) >= sizeof(void *)) - address = options[COMEDI_DEVCONF_AUX_DATA_LO]; - else { - address = options[COMEDI_DEVCONF_AUX_DATA_HI]; - bit_shift = sizeof(int) * 8; - address <<= bit_shift; - addressLow = options[COMEDI_DEVCONF_AUX_DATA_LO]; - addressLow &= (1UL << bit_shift) - 1; - address |= addressLow; - } - if (n >= 1) - address += options[COMEDI_DEVCONF_AUX_DATA0_LENGTH]; - if (n >= 2) - address += options[COMEDI_DEVCONF_AUX_DATA1_LENGTH]; - if (n >= 3) - address += options[COMEDI_DEVCONF_AUX_DATA2_LENGTH]; - BUG_ON(n > 3); - return (void *)address; -} +int comedi_alloc_subdevices(struct comedi_device *, int); -int comedi_alloc_subdevice_minor(struct comedi_device *dev, - struct comedi_subdevice *s); -void comedi_free_subdevice_minor(struct comedi_subdevice *s); -int comedi_auto_config(struct device *hardware_device, - struct comedi_driver *driver, unsigned long context); -void comedi_auto_unconfig(struct device *hardware_device); +int comedi_auto_config(struct device *, struct comedi_driver *, + unsigned long context); +void comedi_auto_unconfig(struct device *); -static inline int comedi_pci_auto_config(struct pci_dev *pcidev, - struct comedi_driver *driver) -{ - return comedi_auto_config(&pcidev->dev, driver, 0); -} +int comedi_driver_register(struct comedi_driver *); +int comedi_driver_unregister(struct comedi_driver *); + +/** + * module_comedi_driver() - Helper macro for registering a comedi driver + * @__comedi_driver: comedi_driver struct + * + * Helper macro for comedi drivers which do not do anything special in module + * init/exit. This eliminates a lot of boilerplate. Each module may only use + * this macro once, and calling it replaces module_init() and module_exit(). + */ +#define module_comedi_driver(__comedi_driver) \ + module_driver(__comedi_driver, comedi_driver_register, \ + comedi_driver_unregister) + +#ifdef CONFIG_COMEDI_PCI_DRIVERS + +/* comedi_pci.c - comedi PCI driver specific functions */ + +/* + * PCI Vendor IDs not in <linux/pci_ids.h> + */ +#define PCI_VENDOR_ID_KOLTER 0x1001 +#define PCI_VENDOR_ID_ICP 0x104c +#define PCI_VENDOR_ID_AMCC 0x10e8 +#define PCI_VENDOR_ID_DT 0x1116 +#define PCI_VENDOR_ID_IOTECH 0x1616 +#define PCI_VENDOR_ID_CONTEC 0x1221 +#define PCI_VENDOR_ID_RTD 0x1435 + +struct pci_dev; +struct pci_driver; + +struct pci_dev *comedi_to_pci_dev(struct comedi_device *); + +int comedi_pci_enable(struct pci_dev *, const char *); +void comedi_pci_disable(struct pci_dev *); + +int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *); +void comedi_pci_auto_unconfig(struct pci_dev *); + +int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *); +void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *); + +/** + * module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver + * @__comedi_driver: comedi_driver struct + * @__pci_driver: pci_driver struct + * + * Helper macro for comedi PCI drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \ + module_driver(__comedi_driver, comedi_pci_driver_register, \ + comedi_pci_driver_unregister, &(__pci_driver)) -static inline void comedi_pci_auto_unconfig(struct pci_dev *pcidev) +#else + +/* + * Some of the comedi mixed ISA/PCI drivers call the PCI specific + * functions. Provide some dummy functions if CONFIG_COMEDI_PCI_DRIVERS + * is not enabled. + */ + +static inline struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) { - comedi_auto_unconfig(&pcidev->dev); + return NULL; } -static inline int comedi_usb_auto_config(struct usb_interface *intf, - struct comedi_driver *driver) +static inline int comedi_pci_enable(struct pci_dev *dev, const char *name) { - return comedi_auto_config(&intf->dev, driver, 0); + return -ENOSYS; } -static inline void comedi_usb_auto_unconfig(struct usb_interface *intf) +static inline void comedi_pci_disable(struct pci_dev *dev) { - comedi_auto_unconfig(&intf->dev); } +#endif /* CONFIG_COMEDI_PCI_DRIVERS */ + +#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS + +/* comedi_pcmcia.c - comedi PCMCIA driver specific functions */ + +struct pcmcia_driver; +struct pcmcia_device; + +struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *); + +int comedi_pcmcia_enable(struct comedi_device *, + int (*conf_check)(struct pcmcia_device *, void *)); +void comedi_pcmcia_disable(struct comedi_device *); + +int comedi_pcmcia_auto_config(struct pcmcia_device *, struct comedi_driver *); +void comedi_pcmcia_auto_unconfig(struct pcmcia_device *); + +int comedi_pcmcia_driver_register(struct comedi_driver *, + struct pcmcia_driver *); +void comedi_pcmcia_driver_unregister(struct comedi_driver *, + struct pcmcia_driver *); + +/** + * module_comedi_pcmcia_driver() - Helper macro for registering a comedi PCMCIA driver + * @__comedi_driver: comedi_driver struct + * @__pcmcia_driver: pcmcia_driver struct + * + * Helper macro for comedi PCMCIA drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_pcmcia_driver(__comedi_driver, __pcmcia_driver) \ + module_driver(__comedi_driver, comedi_pcmcia_driver_register, \ + comedi_pcmcia_driver_unregister, &(__pcmcia_driver)) + +#endif /* CONFIG_COMEDI_PCMCIA_DRIVERS */ + +#ifdef CONFIG_COMEDI_USB_DRIVERS + +/* comedi_usb.c - comedi USB driver specific functions */ + +struct usb_driver; +struct usb_interface; + +struct usb_interface *comedi_to_usb_interface(struct comedi_device *); + +int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *, + unsigned long context); +void comedi_usb_auto_unconfig(struct usb_interface *); + +int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *); +void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *); + +/** + * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver + * @__comedi_driver: comedi_driver struct + * @__usb_driver: usb_driver struct + * + * Helper macro for comedi USB drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \ + module_driver(__comedi_driver, comedi_usb_driver_register, \ + comedi_usb_driver_unregister, &(__usb_driver)) + +#endif /* CONFIG_COMEDI_USB_DRIVERS */ + #endif /* _COMEDIDEV_H */ diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 50cf498698e2..64be7c5e891e 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -23,8 +23,6 @@ #include <linux/device.h> #include <linux/module.h> -#include <linux/pci.h> -#include <linux/usb.h> #include <linux/errno.h> #include <linux/kconfig.h> #include <linux/kernel.h> @@ -43,16 +41,25 @@ #include "comedidev.h" #include "comedi_internal.h" -static int postconfig(struct comedi_device *dev); -static int insn_rw_emulate_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static void *comedi_recognize(struct comedi_driver *driv, const char *name); -static void comedi_report_boards(struct comedi_driver *driv); -static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s); - struct comedi_driver *comedi_drivers; +int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev) +{ + if (hw_dev == dev->hw_dev) + return 0; + if (dev->hw_dev != NULL) + return -EEXIST; + dev->hw_dev = get_device(hw_dev); + return 0; +} +EXPORT_SYMBOL_GPL(comedi_set_hw_dev); + +static void comedi_clear_hw_dev(struct comedi_device *dev) +{ + put_device(dev->hw_dev); + dev->hw_dev = NULL; +} + int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) { struct comedi_subdevice *s; @@ -70,6 +77,7 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) for (i = 0; i < num_subdevices; ++i) { s = &dev->subdevices[i]; s->device = dev; + s->index = i; s->async_dma_dir = DMA_NONE; spin_lock_init(&s->spin_lock); s->minor = -1; @@ -107,7 +115,7 @@ static void cleanup_device(struct comedi_device *dev) dev->write_subdev = NULL; dev->open = NULL; dev->close = NULL; - comedi_set_hw_dev(dev, NULL); + comedi_clear_hw_dev(dev); } static void __comedi_device_detach(struct comedi_device *dev) @@ -128,131 +136,105 @@ void comedi_device_detach(struct comedi_device *dev) __comedi_device_detach(dev); } -/* do a little post-config cleanup */ -/* called with module refcount incremented, decrements it */ -static int comedi_device_postconfig(struct comedi_device *dev) +static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s) { - int ret = postconfig(dev); - module_put(dev->driver->module); - if (ret < 0) { - __comedi_device_detach(dev); - return ret; - } - if (!dev->board_name) { - dev_warn(dev->class_dev, "BUG: dev->board_name=NULL\n"); - dev->board_name = "BUG"; - } - smp_wmb(); - dev->attached = 1; - return 0; + return -EINVAL; } -int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) +int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - struct comedi_driver *driv; + return -EINVAL; +} + +static int insn_rw_emulate_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct comedi_insn new_insn; int ret; + static const unsigned channels_per_bitfield = 32; - if (dev->attached) - return -EBUSY; + unsigned chan = CR_CHAN(insn->chanspec); + const unsigned base_bitfield_channel = + (chan < channels_per_bitfield) ? 0 : chan; + unsigned int new_data[2]; + memset(new_data, 0, sizeof(new_data)); + memset(&new_insn, 0, sizeof(new_insn)); + new_insn.insn = INSN_BITS; + new_insn.chanspec = base_bitfield_channel; + new_insn.n = 2; + new_insn.subdev = insn->subdev; - for (driv = comedi_drivers; driv; driv = driv->next) { - if (!try_module_get(driv->module)) - continue; - if (driv->num_names) { - dev->board_ptr = comedi_recognize(driv, it->board_name); - if (dev->board_ptr) - break; - } else if (strcmp(driv->driver_name, it->board_name) == 0) - break; - module_put(driv->module); - } - if (driv == NULL) { - /* recognize has failed if we get here */ - /* report valid board names before returning error */ - for (driv = comedi_drivers; driv; driv = driv->next) { - if (!try_module_get(driv->module)) - continue; - comedi_report_boards(driv); - module_put(driv->module); - } - return -EIO; - } - if (driv->attach == NULL) { - /* driver does not support manual configuration */ - dev_warn(dev->class_dev, - "driver '%s' does not support attach using comedi_config\n", - driv->driver_name); - module_put(driv->module); - return -ENOSYS; + if (insn->insn == INSN_WRITE) { + if (!(s->subdev_flags & SDF_WRITABLE)) + return -EINVAL; + new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */ + new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel)) + : 0; /* bits */ } - /* initialize dev->driver here so - * comedi_error() can be called from attach */ - dev->driver = driv; - ret = driv->attach(dev, it); - if (ret < 0) { - module_put(dev->driver->module); - __comedi_device_detach(dev); + + ret = s->insn_bits(dev, s, &new_insn, new_data); + if (ret < 0) return ret; - } - return comedi_device_postconfig(dev); -} -int comedi_driver_register(struct comedi_driver *driver) -{ - driver->next = comedi_drivers; - comedi_drivers = driver; + if (insn->insn == INSN_READ) + data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1; - return 0; + return 1; } -EXPORT_SYMBOL(comedi_driver_register); -int comedi_driver_unregister(struct comedi_driver *driver) +static int __comedi_device_postconfig_async(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_driver *prev; - int i; + struct comedi_async *async; + unsigned int buf_size; + int ret; - /* check for devices using this driver */ - for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(i); - struct comedi_device *dev; + if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) { + dev_warn(dev->class_dev, + "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n"); + return -EINVAL; + } + if (!s->do_cmdtest) { + dev_warn(dev->class_dev, + "async subdevices must have a do_cmdtest() function\n"); + return -EINVAL; + } - if (dev_file_info == NULL) - continue; - dev = dev_file_info->device; + async = kzalloc(sizeof(*async), GFP_KERNEL); + if (!async) + return -ENOMEM; - mutex_lock(&dev->mutex); - if (dev->attached && dev->driver == driver) { - if (dev->use_count) - dev_warn(dev->class_dev, - "BUG! detaching device with use_count=%d\n", - dev->use_count); - comedi_device_detach(dev); - } - mutex_unlock(&dev->mutex); - } + init_waitqueue_head(&async->wait_head); + async->subdevice = s; + s->async = async; - if (comedi_drivers == driver) { - comedi_drivers = driver->next; - return 0; - } + async->max_bufsize = comedi_default_buf_maxsize_kb * 1024; + buf_size = comedi_default_buf_size_kb * 1024; + if (buf_size > async->max_bufsize) + buf_size = async->max_bufsize; - for (prev = comedi_drivers; prev->next; prev = prev->next) { - if (prev->next == driver) { - prev->next = driver->next; - return 0; - } + if (comedi_buf_alloc(dev, s, buf_size) < 0) { + dev_warn(dev->class_dev, "Buffer allocation failed\n"); + return -ENOMEM; } - return -EINVAL; + if (s->buf_change) { + ret = s->buf_change(dev, s, buf_size); + if (ret < 0) + return ret; + } + + comedi_alloc_subdevice_minor(s); + + return 0; } -EXPORT_SYMBOL(comedi_driver_unregister); -static int postconfig(struct comedi_device *dev) +static int __comedi_device_postconfig(struct comedi_device *dev) { - int i; struct comedi_subdevice *s; - struct comedi_async *async = NULL; int ret; + int i; for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; @@ -264,42 +246,9 @@ static int postconfig(struct comedi_device *dev) s->len_chanlist = 1; if (s->do_cmd) { - unsigned int buf_size; - - BUG_ON((s->subdev_flags & (SDF_CMD_READ | - SDF_CMD_WRITE)) == 0); - BUG_ON(!s->do_cmdtest); - - async = - kzalloc(sizeof(struct comedi_async), GFP_KERNEL); - if (async == NULL) { - dev_warn(dev->class_dev, - "failed to allocate async struct\n"); - return -ENOMEM; - } - init_waitqueue_head(&async->wait_head); - async->subdevice = s; - s->async = async; - - async->max_bufsize = - comedi_default_buf_maxsize_kb * 1024; - buf_size = comedi_default_buf_size_kb * 1024; - if (buf_size > async->max_bufsize) - buf_size = async->max_bufsize; - - async->prealloc_buf = NULL; - async->prealloc_bufsz = 0; - if (comedi_buf_alloc(dev, s, buf_size) < 0) { - dev_warn(dev->class_dev, - "Buffer allocation failed\n"); - return -ENOMEM; - } - if (s->buf_change) { - ret = s->buf_change(dev, s, buf_size); - if (ret < 0) - return ret; - } - comedi_alloc_subdevice_minor(dev, s); + ret = __comedi_device_postconfig_async(dev, s); + if (ret) + return ret; } if (!s->range_table && !s->range_table_list) @@ -326,6 +275,25 @@ static int postconfig(struct comedi_device *dev) return 0; } +/* do a little post-config cleanup */ +/* called with module refcount incremented, decrements it */ +static int comedi_device_postconfig(struct comedi_device *dev) +{ + int ret = __comedi_device_postconfig(dev); + module_put(dev->driver->module); + if (ret < 0) { + __comedi_device_detach(dev); + return ret; + } + if (!dev->board_name) { + dev_warn(dev->class_dev, "BUG: dev->board_name=NULL\n"); + dev->board_name = "BUG"; + } + smp_wmb(); + dev->attached = 1; + return 0; +} + /* * Generic recognize function for drivers that register their supported * board names. @@ -384,463 +352,63 @@ static void comedi_report_boards(struct comedi_driver *driv) pr_info(" %s\n", driv->driver_name); } -static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s) -{ - return -EINVAL; -} - -int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return -EINVAL; -} - -static int insn_rw_emulate_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct comedi_insn new_insn; + struct comedi_driver *driv; int ret; - static const unsigned channels_per_bitfield = 32; - - unsigned chan = CR_CHAN(insn->chanspec); - const unsigned base_bitfield_channel = - (chan < channels_per_bitfield) ? 0 : chan; - unsigned int new_data[2]; - memset(new_data, 0, sizeof(new_data)); - memset(&new_insn, 0, sizeof(new_insn)); - new_insn.insn = INSN_BITS; - new_insn.chanspec = base_bitfield_channel; - new_insn.n = 2; - new_insn.subdev = insn->subdev; - if (insn->insn == INSN_WRITE) { - if (!(s->subdev_flags & SDF_WRITABLE)) - return -EINVAL; - new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */ - new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel)) - : 0; /* bits */ - } - - ret = s->insn_bits(dev, s, &new_insn, new_data); - if (ret < 0) - return ret; - - if (insn->insn == INSN_READ) - data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1; - - return 1; -} - -int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned long new_size) -{ - struct comedi_async *async = s->async; - - /* Round up new_size to multiple of PAGE_SIZE */ - new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; - - /* if no change is required, do nothing */ - if (async->prealloc_buf && async->prealloc_bufsz == new_size) - return 0; - - /* deallocate old buffer */ - if (async->prealloc_buf) { - vunmap(async->prealloc_buf); - async->prealloc_buf = NULL; - async->prealloc_bufsz = 0; - } - if (async->buf_page_list) { - unsigned i; - for (i = 0; i < async->n_buf_pages; ++i) { - if (async->buf_page_list[i].virt_addr) { - clear_bit(PG_reserved, - &(virt_to_page(async->buf_page_list[i]. - virt_addr)->flags)); - if (s->async_dma_dir != DMA_NONE) { - dma_free_coherent(dev->hw_dev, - PAGE_SIZE, - async-> - buf_page_list - [i].virt_addr, - async-> - buf_page_list - [i].dma_addr); - } else { - free_page((unsigned long) - async->buf_page_list[i]. - virt_addr); - } - } - } - vfree(async->buf_page_list); - async->buf_page_list = NULL; - async->n_buf_pages = 0; - } - /* allocate new buffer */ - if (new_size) { - unsigned i = 0; - unsigned n_pages = new_size >> PAGE_SHIFT; - struct page **pages = NULL; - - async->buf_page_list = - vzalloc(sizeof(struct comedi_buf_page) * n_pages); - if (async->buf_page_list) - pages = vmalloc(sizeof(struct page *) * n_pages); - - if (pages) { - for (i = 0; i < n_pages; i++) { - if (s->async_dma_dir != DMA_NONE) { - async->buf_page_list[i].virt_addr = - dma_alloc_coherent(dev->hw_dev, - PAGE_SIZE, - &async-> - buf_page_list - [i].dma_addr, - GFP_KERNEL | - __GFP_COMP); - } else { - async->buf_page_list[i].virt_addr = - (void *) - get_zeroed_page(GFP_KERNEL); - } - if (async->buf_page_list[i].virt_addr == NULL) - break; - - set_bit(PG_reserved, - &(virt_to_page(async->buf_page_list[i]. - virt_addr)->flags)); - pages[i] = virt_to_page(async->buf_page_list[i]. - virt_addr); - } - } - if (i == n_pages) { - async->prealloc_buf = -#ifdef PAGE_KERNEL_NOCACHE - vmap(pages, n_pages, VM_MAP, PAGE_KERNEL_NOCACHE); -#else - vmap(pages, n_pages, VM_MAP, PAGE_KERNEL); -#endif - } - vfree(pages); - - if (async->prealloc_buf == NULL) { - /* Some allocation failed above. */ - if (async->buf_page_list) { - for (i = 0; i < n_pages; i++) { - if (async->buf_page_list[i].virt_addr == - NULL) { - break; - } - clear_bit(PG_reserved, - &(virt_to_page(async-> - buf_page_list[i]. - virt_addr)->flags)); - if (s->async_dma_dir != DMA_NONE) { - dma_free_coherent(dev->hw_dev, - PAGE_SIZE, - async-> - buf_page_list - [i].virt_addr, - async-> - buf_page_list - [i].dma_addr); - } else { - free_page((unsigned long) - async->buf_page_list - [i].virt_addr); - } - } - vfree(async->buf_page_list); - async->buf_page_list = NULL; - } - return -ENOMEM; - } - async->n_buf_pages = n_pages; - } - async->prealloc_bufsz = new_size; - - return 0; -} + if (dev->attached) + return -EBUSY; -/* munging is applied to data by core as it passes between user - * and kernel space */ -static unsigned int comedi_buf_munge(struct comedi_async *async, - unsigned int num_bytes) -{ - struct comedi_subdevice *s = async->subdevice; - unsigned int count = 0; - const unsigned num_sample_bytes = bytes_per_sample(s); - - if (s->munge == NULL || (async->cmd.flags & CMDF_RAWDATA)) { - async->munge_count += num_bytes; - BUG_ON((int)(async->munge_count - async->buf_write_count) > 0); - return num_bytes; - } - /* don't munge partial samples */ - num_bytes -= num_bytes % num_sample_bytes; - while (count < num_bytes) { - int block_size; - - block_size = num_bytes - count; - if (block_size < 0) { - dev_warn(s->device->class_dev, - "%s: %s: bug! block_size is negative\n", - __FILE__, __func__); + for (driv = comedi_drivers; driv; driv = driv->next) { + if (!try_module_get(driv->module)) + continue; + if (driv->num_names) { + dev->board_ptr = comedi_recognize(driv, it->board_name); + if (dev->board_ptr) + break; + } else if (strcmp(driv->driver_name, it->board_name) == 0) break; - } - if ((int)(async->munge_ptr + block_size - - async->prealloc_bufsz) > 0) - block_size = async->prealloc_bufsz - async->munge_ptr; - - s->munge(s->device, s, async->prealloc_buf + async->munge_ptr, - block_size, async->munge_chan); - - smp_wmb(); /* barrier insures data is munged in buffer - * before munge_count is incremented */ - - async->munge_chan += block_size / num_sample_bytes; - async->munge_chan %= async->cmd.chanlist_len; - async->munge_count += block_size; - async->munge_ptr += block_size; - async->munge_ptr %= async->prealloc_bufsz; - count += block_size; - } - BUG_ON((int)(async->munge_count - async->buf_write_count) > 0); - return count; -} - -unsigned int comedi_buf_write_n_available(struct comedi_async *async) -{ - unsigned int free_end; - unsigned int nbytes; - - if (async == NULL) - return 0; - - free_end = async->buf_read_count + async->prealloc_bufsz; - nbytes = free_end - async->buf_write_alloc_count; - nbytes -= nbytes % bytes_per_sample(async->subdevice); - /* barrier insures the read of buf_read_count in this - query occurs before any following writes to the buffer which - might be based on the return value from this query. - */ - smp_mb(); - return nbytes; -} - -/* allocates chunk for the writer from free buffer space */ -unsigned int comedi_buf_write_alloc(struct comedi_async *async, - unsigned int nbytes) -{ - unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; - - if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0) - nbytes = free_end - async->buf_write_alloc_count; - - async->buf_write_alloc_count += nbytes; - /* barrier insures the read of buf_read_count above occurs before - we write data to the write-alloc'ed buffer space */ - smp_mb(); - return nbytes; -} -EXPORT_SYMBOL(comedi_buf_write_alloc); - -/* allocates nothing unless it can completely fulfill the request */ -unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async, - unsigned int nbytes) -{ - unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; - - if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0) - nbytes = 0; - - async->buf_write_alloc_count += nbytes; - /* barrier insures the read of buf_read_count above occurs before - we write data to the write-alloc'ed buffer space */ - smp_mb(); - return nbytes; -} - -/* transfers a chunk from writer to filled buffer space */ -unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes) -{ - if ((int)(async->buf_write_count + nbytes - - async->buf_write_alloc_count) > 0) { - dev_info(async->subdevice->device->class_dev, - "attempted to write-free more bytes than have been write-allocated.\n"); - nbytes = async->buf_write_alloc_count - async->buf_write_count; - } - async->buf_write_count += nbytes; - async->buf_write_ptr += nbytes; - comedi_buf_munge(async, async->buf_write_count - async->munge_count); - if (async->buf_write_ptr >= async->prealloc_bufsz) - async->buf_write_ptr %= async->prealloc_bufsz; - - return nbytes; -} -EXPORT_SYMBOL(comedi_buf_write_free); - -/* allocates a chunk for the reader from filled (and munged) buffer space */ -unsigned comedi_buf_read_alloc(struct comedi_async *async, unsigned nbytes) -{ - if ((int)(async->buf_read_alloc_count + nbytes - async->munge_count) > - 0) { - nbytes = async->munge_count - async->buf_read_alloc_count; - } - async->buf_read_alloc_count += nbytes; - /* barrier insures read of munge_count occurs before we actually read - data out of buffer */ - smp_rmb(); - return nbytes; -} -EXPORT_SYMBOL(comedi_buf_read_alloc); - -/* transfers control of a chunk from reader to free buffer space */ -unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes) -{ - /* barrier insures data has been read out of - * buffer before read count is incremented */ - smp_mb(); - if ((int)(async->buf_read_count + nbytes - - async->buf_read_alloc_count) > 0) { - dev_info(async->subdevice->device->class_dev, - "attempted to read-free more bytes than have been read-allocated.\n"); - nbytes = async->buf_read_alloc_count - async->buf_read_count; + module_put(driv->module); } - async->buf_read_count += nbytes; - async->buf_read_ptr += nbytes; - async->buf_read_ptr %= async->prealloc_bufsz; - return nbytes; -} -EXPORT_SYMBOL(comedi_buf_read_free); - -void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, - const void *data, unsigned int num_bytes) -{ - unsigned int write_ptr = async->buf_write_ptr + offset; - - if (write_ptr >= async->prealloc_bufsz) - write_ptr %= async->prealloc_bufsz; - - while (num_bytes) { - unsigned int block_size; - - if (write_ptr + num_bytes > async->prealloc_bufsz) - block_size = async->prealloc_bufsz - write_ptr; - else - block_size = num_bytes; - - memcpy(async->prealloc_buf + write_ptr, data, block_size); - - data += block_size; - num_bytes -= block_size; - - write_ptr = 0; + if (driv == NULL) { + /* recognize has failed if we get here */ + /* report valid board names before returning error */ + for (driv = comedi_drivers; driv; driv = driv->next) { + if (!try_module_get(driv->module)) + continue; + comedi_report_boards(driv); + module_put(driv->module); + } + return -EIO; } -} -EXPORT_SYMBOL(comedi_buf_memcpy_to); - -void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, - void *dest, unsigned int nbytes) -{ - void *src; - unsigned int read_ptr = async->buf_read_ptr + offset; - - if (read_ptr >= async->prealloc_bufsz) - read_ptr %= async->prealloc_bufsz; - - while (nbytes) { - unsigned int block_size; - - src = async->prealloc_buf + read_ptr; - - if (nbytes >= async->prealloc_bufsz - read_ptr) - block_size = async->prealloc_bufsz - read_ptr; - else - block_size = nbytes; - - memcpy(dest, src, block_size); - nbytes -= block_size; - dest += block_size; - read_ptr = 0; + if (driv->attach == NULL) { + /* driver does not support manual configuration */ + dev_warn(dev->class_dev, + "driver '%s' does not support attach using comedi_config\n", + driv->driver_name); + module_put(driv->module); + return -ENOSYS; } -} -EXPORT_SYMBOL(comedi_buf_memcpy_from); - -unsigned int comedi_buf_read_n_available(struct comedi_async *async) -{ - unsigned num_bytes; - - if (async == NULL) - return 0; - num_bytes = async->munge_count - async->buf_read_count; - /* barrier insures the read of munge_count in this - query occurs before any following reads of the buffer which - might be based on the return value from this query. - */ - smp_rmb(); - return num_bytes; -} -EXPORT_SYMBOL(comedi_buf_read_n_available); - -int comedi_buf_get(struct comedi_async *async, short *x) -{ - unsigned int n = comedi_buf_read_n_available(async); - - if (n < sizeof(short)) - return 0; - comedi_buf_read_alloc(async, sizeof(short)); - *x = *(short *)(async->prealloc_buf + async->buf_read_ptr); - comedi_buf_read_free(async, sizeof(short)); - return 1; -} -EXPORT_SYMBOL(comedi_buf_get); - -int comedi_buf_put(struct comedi_async *async, short x) -{ - unsigned int n = comedi_buf_write_alloc_strict(async, sizeof(short)); - - if (n < sizeof(short)) { - async->events |= COMEDI_CB_ERROR; - return 0; + /* initialize dev->driver here so + * comedi_error() can be called from attach */ + dev->driver = driv; + ret = driv->attach(dev, it); + if (ret < 0) { + module_put(dev->driver->module); + __comedi_device_detach(dev); + return ret; } - *(short *)(async->prealloc_buf + async->buf_write_ptr) = x; - comedi_buf_write_free(async, sizeof(short)); - return 1; -} -EXPORT_SYMBOL(comedi_buf_put); - -void comedi_reset_async_buf(struct comedi_async *async) -{ - async->buf_write_alloc_count = 0; - async->buf_write_count = 0; - async->buf_read_alloc_count = 0; - async->buf_read_count = 0; - - async->buf_write_ptr = 0; - async->buf_read_ptr = 0; - - async->cur_chan = 0; - async->scan_progress = 0; - async->munge_chan = 0; - async->munge_count = 0; - async->munge_ptr = 0; - - async->events = 0; + return comedi_device_postconfig(dev); } int comedi_auto_config(struct device *hardware_device, struct comedi_driver *driver, unsigned long context) { int minor; - struct comedi_device_file_info *dev_file_info; struct comedi_device *comedi_dev; int ret; - if (!comedi_autoconfig) - return 0; - if (!driver->auto_attach) { dev_warn(hardware_device, "BUG! comedi driver '%s' has no auto_attach handler\n", @@ -852,8 +420,7 @@ int comedi_auto_config(struct device *hardware_device, if (minor < 0) return minor; - dev_file_info = comedi_get_device_file_info(minor); - comedi_dev = dev_file_info->device; + comedi_dev = comedi_dev_from_minor(minor); mutex_lock(&comedi_dev->mutex); if (comedi_dev->attached) @@ -888,103 +455,53 @@ void comedi_auto_unconfig(struct device *hardware_device) minor = comedi_find_board_minor(hardware_device); if (minor < 0) return; - BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); comedi_free_board_minor(minor); } EXPORT_SYMBOL_GPL(comedi_auto_unconfig); -/** - * comedi_pci_enable() - Enable the PCI device and request the regions. - * @pdev: pci_dev struct - * @res_name: name for the requested reqource - */ -int comedi_pci_enable(struct pci_dev *pdev, const char *res_name) -{ - int rc; - - rc = pci_enable_device(pdev); - if (rc < 0) - return rc; - - rc = pci_request_regions(pdev, res_name); - if (rc < 0) - pci_disable_device(pdev); - - return rc; -} -EXPORT_SYMBOL_GPL(comedi_pci_enable); - -/** - * comedi_pci_disable() - Release the regions and disable the PCI device. - * @pdev: pci_dev struct - * - * This must be matched with a previous successful call to comedi_pci_enable(). - */ -void comedi_pci_disable(struct pci_dev *pdev) -{ - pci_release_regions(pdev); - pci_disable_device(pdev); -} -EXPORT_SYMBOL_GPL(comedi_pci_disable); - -int comedi_pci_driver_register(struct comedi_driver *comedi_driver, - struct pci_driver *pci_driver) +int comedi_driver_register(struct comedi_driver *driver) { - int ret; - - ret = comedi_driver_register(comedi_driver); - if (ret < 0) - return ret; - - /* FIXME: Remove this test after auditing all comedi pci drivers */ - if (!pci_driver->name) - pci_driver->name = comedi_driver->driver_name; - - ret = pci_register_driver(pci_driver); - if (ret < 0) { - comedi_driver_unregister(comedi_driver); - return ret; - } + driver->next = comedi_drivers; + comedi_drivers = driver; return 0; } -EXPORT_SYMBOL_GPL(comedi_pci_driver_register); +EXPORT_SYMBOL(comedi_driver_register); -void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, - struct pci_driver *pci_driver) +int comedi_driver_unregister(struct comedi_driver *driver) { - pci_unregister_driver(pci_driver); - comedi_driver_unregister(comedi_driver); -} -EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister); - -#if IS_ENABLED(CONFIG_USB) + struct comedi_driver *prev; + int i; -int comedi_usb_driver_register(struct comedi_driver *comedi_driver, - struct usb_driver *usb_driver) -{ - int ret; + /* check for devices using this driver */ + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { + struct comedi_device *dev = comedi_dev_from_minor(i); - ret = comedi_driver_register(comedi_driver); - if (ret < 0) - return ret; + if (!dev) + continue; - ret = usb_register(usb_driver); - if (ret < 0) { - comedi_driver_unregister(comedi_driver); - return ret; + mutex_lock(&dev->mutex); + if (dev->attached && dev->driver == driver) { + if (dev->use_count) + dev_warn(dev->class_dev, + "BUG! detaching device with use_count=%d\n", + dev->use_count); + comedi_device_detach(dev); + } + mutex_unlock(&dev->mutex); } - return 0; -} -EXPORT_SYMBOL_GPL(comedi_usb_driver_register); + if (comedi_drivers == driver) { + comedi_drivers = driver->next; + return 0; + } -void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver, - struct usb_driver *usb_driver) -{ - usb_deregister(usb_driver); - comedi_driver_unregister(comedi_driver); + for (prev = comedi_drivers; prev->next; prev = prev->next) { + if (prev->next == driver) { + prev->next = driver->next; + return 0; + } + } + return -EINVAL; } -EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister); - -#endif +EXPORT_SYMBOL(comedi_driver_unregister); diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index e0a79521f35a..0ae356ae56ea 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -54,6 +54,8 @@ Interrupt support for these boards is also not currently supported. Configuration Options: not applicable, uses PCI auto config */ +#include <linux/pci.h> + #include "../comedidev.h" #include "8255.h" @@ -314,11 +316,6 @@ static int pci_8255_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &pci_8255_driver); } -static void pci_8255_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(pci_8255_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7224) }, { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7248) }, @@ -342,7 +339,7 @@ static struct pci_driver pci_8255_pci_driver = { .name = "8255_pci", .id_table = pci_8255_pci_table, .probe = pci_8255_pci_probe, - .remove = pci_8255_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(pci_8255_driver, pci_8255_pci_driver); diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 0de4d2eb76fc..315e836ff99b 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -2,7 +2,6 @@ # # Comedi "helper" modules -obj-$(CONFIG_COMEDI) += pcm_common.o # Comedi misc drivers obj-$(CONFIG_COMEDI_BOND) += comedi_bond.o @@ -26,6 +25,7 @@ obj-$(CONFIG_COMEDI_PCM3730) += pcm3730.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o +obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o obj-$(CONFIG_COMEDI_DAS16) += das16.o obj-$(CONFIG_COMEDI_DAS800) += das800.o obj-$(CONFIG_COMEDI_DAS1800) += das1800.o @@ -56,6 +56,7 @@ obj-$(CONFIG_COMEDI_POC) += poc.o # Comedi PCI drivers obj-$(CONFIG_COMEDI_8255_PCI) += 8255_pci.o +obj-$(CONFIG_COMEDI_ADDI_WATCHDOG) += addi_watchdog.o obj-$(CONFIG_COMEDI_ADDI_APCI_035) += addi_apci_035.o obj-$(CONFIG_COMEDI_ADDI_APCI_1032) += addi_apci_1032.o obj-$(CONFIG_COMEDI_ADDI_APCI_1500) += addi_apci_1500.o @@ -81,6 +82,7 @@ obj-$(CONFIG_COMEDI_AMPLC_PC263) += amplc_pc263.o obj-$(CONFIG_COMEDI_AMPLC_PCI224) += amplc_pci224.o obj-$(CONFIG_COMEDI_AMPLC_PCI230) += amplc_pci230.o obj-$(CONFIG_COMEDI_CONTEC_PCI_DIO) += contec_pci_dio.o +obj-$(CONFIG_COMEDI_DAS08_PCI) += das08_pci.o obj-$(CONFIG_COMEDI_DT3000) += dt3000.o obj-$(CONFIG_COMEDI_DYNA_PCI10XX) += dyna_pci10xx.o obj-$(CONFIG_COMEDI_UNIOXX5) += unioxx5.o diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 90cc43263aee..1051fa5ce8f7 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -11,13 +11,21 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. http://www.addi-data.com info@addi-data.com -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +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 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. +You should also find the complete GPL in the COPYING file accompanying this +source code. @endverbatim */ @@ -29,10 +37,10 @@ You should also find the complete GPL in the COPYING file accompanying this sour | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | +-----------------------------------------------------------------------+ - | Project : ADDI DATA | Compiler : GCC | + | Project : ADDI DATA | Compiler : GCC | | Modulname : addi_common.c | Version : 2.96 | +-------------------------------+---------------------------------------+ - | Author : | Date : | + | Author : | Date : | +-----------------------------------------------------------------------+ | Description : ADDI COMMON Main Module | +-----------------------------------------------------------------------+ @@ -167,11 +175,11 @@ static int addi_auto_attach(struct comedi_device *dev, if (this_board->i_PCIEeprom) { if (!(strcmp(this_board->pc_EepromChip, "S5920"))) { /* Set 3 wait stait */ - if (!(strcmp(dev->board_name, "apci035"))) { + if (!(strcmp(dev->board_name, "apci035"))) outl(0x80808082, devpriv->i_IobaseAmcc + 0x60); - } else { + else outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); - } + /* Enable the interrupt for the controller */ dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c deleted file mode 100644 index 5958a9cb2a38..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c +++ /dev/null @@ -1,807 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1648 | Compiler : gcc | - | Module name : TTL.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: S. Weber | Date : 25/05/2005 | - +-----------------------------------------------------------------------+ - | Description : APCI-16XX TTL I/O module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - |25.05.2005| S.Weber | Creation | - | | | | - +-----------------------------------------------------------------------+ -*/ - -#ifndef COMEDI_SUBD_TTLIO -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#endif - -#define APCI16XX_TTL_INIT 0 -#define APCI16XX_TTL_INITDIRECTION 1 -#define APCI16XX_TTL_OUTPUTMEMORY 2 - -#define APCI16XX_TTL_READCHANNEL 0 -#define APCI16XX_TTL_READPORT 1 - -#define APCI16XX_TTL_WRITECHANNEL_ON 0 -#define APCI16XX_TTL_WRITECHANNEL_OFF 1 -#define APCI16XX_TTL_WRITEPORT_ON 2 -#define APCI16XX_TTL_WRITEPORT_OFF 3 - -#define APCI16XX_TTL_READ_ALL_INPUTS 0 -#define APCI16XX_TTL_READ_ALL_OUTPUTS 1 - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnConfigInitTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task APCI16XX_TTL_INIT (using defaults) : | -| Configure the TTL I/O operating mode from all ports | -| You must calling this function be | -| for you call any other function witch access of TTL. | -| APCI16XX_TTL_INITDIRECTION(user inputs for direction) | -+----------------------------------------------------------------------------+ -| Input Parameters : b_InitType = (unsigned char) data[0]; | -| b_Port0Mode = (unsigned char) data[1]; | -| b_Port1Mode = (unsigned char) data[2]; | -| b_Port2Mode = (unsigned char) data[3]; | -| b_Port3Mode = (unsigned char) data[4]; | -| ........ | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -1: Port 0 mode selection is wrong | -| -2: Port 1 mode selection is wrong | -| -3: Port 2 mode selection is wrong | -| -4: Port 3 mode selection is wrong | -| -X: Port X-1 mode selection is wrong | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI16XX_InsnConfigInitTTLIO(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_Command = 0; - unsigned char b_Cpt = 0; - unsigned char b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 8); - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_INIT) || - (b_Command == APCI16XX_TTL_INITDIRECTION) || - (b_Command == APCI16XX_TTL_OUTPUTMEMORY)) { - /***************************************/ - /* Test the initialisation buffer size */ - /***************************************/ - - if ((b_Command == APCI16XX_TTL_INITDIRECTION) - && ((unsigned char) (insn->n - 1) != b_NumberOfPort)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - if ((b_Command == APCI16XX_TTL_OUTPUTMEMORY) - && ((unsigned char) (insn->n) != 2)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - /**************************************************************************/ - /* Test if no error occur and APCI16XX_TTL_INITDIRECTION command selected */ - /**************************************************************************/ - - if ((i_ReturnValue >= 0) && (b_Command == APCI16XX_TTL_INITDIRECTION)) { - memset(devpriv->ul_TTLPortConfiguration, 0, - sizeof(devpriv->ul_TTLPortConfiguration)); - - /*************************************/ - /* Test the port direction selection */ - /*************************************/ - - for (b_Cpt = 1; - (b_Cpt <= b_NumberOfPort) && (i_ReturnValue >= 0); - b_Cpt++) { - /**********************/ - /* Test the direction */ - /**********************/ - - if ((data[b_Cpt] != 0) && (data[b_Cpt] != 0xFF)) { - /************************/ - /* Port direction error */ - /************************/ - - printk("\nPort %d direction selection error", - (int) b_Cpt); - i_ReturnValue = -(int) b_Cpt; - } - - /**************************/ - /* Save the configuration */ - /**************************/ - - devpriv->ul_TTLPortConfiguration[(b_Cpt - 1) / 4] = - devpriv->ul_TTLPortConfiguration[(b_Cpt - - 1) / 4] | (data[b_Cpt] << (8 * ((b_Cpt - - 1) % 4))); - } - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /***********************************/ - /* Test if TTL port initilaisation */ - /***********************************/ - - if ((b_Command == APCI16XX_TTL_INIT) - || (b_Command == APCI16XX_TTL_INITDIRECTION)) { - /******************************/ - /* Set all port configuration */ - /******************************/ - - for (b_Cpt = 0; b_Cpt <= b_NumberOfPort; b_Cpt++) { - if ((b_Cpt % 4) == 0) { - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(devpriv-> - ul_TTLPortConfiguration[b_Cpt / - 4], - devpriv->iobase + 32 + b_Cpt); - } - } - } - } - - /************************************************/ - /* Test if output memory initialisation command */ - /************************************************/ - - if (b_Command == APCI16XX_TTL_OUTPUTMEMORY) { - if (data[1]) { - devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } else { - devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnBitsReadTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from selected TTL digital input | -| (b_InputChannel) | -+----------------------------------------------------------------------------+ -| Task : Read the status from digital input port | -| (b_SelectedPort) | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| APCI16XX_TTL_READCHANNEL | -| b_SelectedPort= CR_RANGE(insn->chanspec); | -| b_InputChannel= CR_CHAN(insn->chanspec); | -| b_ReadType = (unsigned char) data[0]; | -| | -| APCI16XX_TTL_READPORT | -| b_SelectedPort= CR_RANGE(insn->chanspec); | -| b_ReadType = (unsigned char) data[0]; | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] 0 : Channle is not active | -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -100 : Config command error | -| -101 : Data size error | -| -102 : The selected TTL input port is wrong | -| -103 : The selected TTL digital input is wrong | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI16XX_InsnBitsReadTTLIO(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_Command = 0; - unsigned char b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 8); - unsigned char b_SelectedPort = CR_RANGE(insn->chanspec); - unsigned char b_InputChannel = CR_CHAN(insn->chanspec); - unsigned char *pb_Status; - unsigned int dw_Status; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_READCHANNEL) - || (b_Command == APCI16XX_TTL_READPORT)) { - /**************************/ - /* Test the selected port */ - /**************************/ - - if (b_SelectedPort < b_NumberOfPort) { - /**********************/ - /* Test if input port */ - /**********************/ - - if (((devpriv->ul_TTLPortConfiguration - [b_SelectedPort / - 4] >> (8 * - (b_SelectedPort - % - 4))) & - 0xFF) == 0) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if ((b_Command == - APCI16XX_TTL_READCHANNEL) - && (b_InputChannel > 7)) { - /*******************************************/ - /* The selected TTL digital input is wrong */ - /*******************************************/ - - printk("\nChannel selection error"); - i_ReturnValue = -103; - } - } else { - /****************************************/ - /* The selected TTL input port is wrong */ - /****************************************/ - - printk("\nPort selection error"); - i_ReturnValue = -102; - } - } else { - /****************************************/ - /* The selected TTL input port is wrong */ - /****************************************/ - - printk("\nPort selection error"); - i_ReturnValue = -102; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - pb_Status = (unsigned char *) &data[0]; - - /*******************************/ - /* Get the digital inpu status */ - /*******************************/ - - dw_Status = - inl(devpriv->iobase + 8 + ((b_SelectedPort / 4) * 4)); - dw_Status = (dw_Status >> (8 * (b_SelectedPort % 4))) & 0xFF; - - /***********************/ - /* Save the port value */ - /***********************/ - - *pb_Status = (unsigned char) dw_Status; - - /***************************************/ - /* Test if read channel status command */ - /***************************************/ - - if (b_Command == APCI16XX_TTL_READCHANNEL) { - *pb_Status = (*pb_Status >> b_InputChannel) & 1; - } - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnReadTTLIOAllPortValue | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from all digital input ports | -+----------------------------------------------------------------------------+ -| Input Parameters : - | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Port 0 to 3 data | -| data[1] : Port 4 to 7 data | -| .... | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -100 : Read command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct addi_board *this_board = comedi_board(dev); - struct addi_private *devpriv = dev->private; - unsigned char b_Command = (unsigned char) CR_AREF(insn->chanspec); - int i_ReturnValue = insn->n; - unsigned char b_Cpt = 0; - unsigned char b_NumberOfPort = 0; - unsigned int *pls_ReadData = data; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_READ_ALL_INPUTS) - || (b_Command == APCI16XX_TTL_READ_ALL_OUTPUTS)) { - /**********************************/ - /* Get the number of 32-Bit ports */ - /**********************************/ - - b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 32); - if ((b_NumberOfPort * 32) < - this_board->i_NbrTTLChannel) { - b_NumberOfPort = b_NumberOfPort + 1; - } - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= b_NumberOfPort) { - if (b_Command == APCI16XX_TTL_READ_ALL_INPUTS) { - /**************************/ - /* Read all digital input */ - /**************************/ - - for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) { - /************************/ - /* Read the 32-Bit port */ - /************************/ - - pls_ReadData[b_Cpt] = - inl(devpriv->iobase + 8 + - (b_Cpt * 4)); - - /**************************************/ - /* Mask all channels used als outputs */ - /**************************************/ - - pls_ReadData[b_Cpt] = - pls_ReadData[b_Cpt] & - (~devpriv-> - ul_TTLPortConfiguration[b_Cpt]); - } - } else { - /****************************/ - /* Read all digital outputs */ - /****************************/ - - for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) { - /************************/ - /* Read the 32-Bit port */ - /************************/ - - pls_ReadData[b_Cpt] = - inl(devpriv->iobase + 20 + - (b_Cpt * 4)); - - /**************************************/ - /* Mask all channels used als outputs */ - /**************************************/ - - pls_ReadData[b_Cpt] = - pls_ReadData[b_Cpt] & devpriv-> - ul_TTLPortConfiguration[b_Cpt]; - } - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - } else { - /*****************/ - /* Command error */ - /*****************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnBitsWriteTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Set the state from selected TTL digital output | -| (b_OutputChannel) | -+----------------------------------------------------------------------------+ -| Task : Set the state from digital output port | -| (b_SelectedPort) | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| APCI16XX_TTL_WRITECHANNEL_ON | APCI16XX_TTL_WRITECHANNEL_OFF | -| b_SelectedPort = CR_RANGE(insn->chanspec); | -| b_OutputChannel= CR_CHAN(insn->chanspec); | -| b_Command = (unsigned char) data[0]; | -| | -| APCI16XX_TTL_WRITEPORT_ON | APCI16XX_TTL_WRITEPORT_OFF | -| b_SelectedPort = CR_RANGE(insn->chanspec); | -| b_Command = (unsigned char) data[0]; | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : TTL output port 0 to 3 data | -| data[1] : TTL output port 4 to 7 data | -| .... | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -100 : Command error | -| -101 : Data size error | -| -102 : The selected TTL output port is wrong | -| -103 : The selected TTL digital output is wrong | -| -104 : Output memory disabled | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI16XX_InsnBitsWriteTTLIO(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_Command = 0; - unsigned char b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 8); - unsigned char b_SelectedPort = CR_RANGE(insn->chanspec); - unsigned char b_OutputChannel = CR_CHAN(insn->chanspec); - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) || - (b_Command == APCI16XX_TTL_WRITEPORT_ON) || - (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) || - (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) { - /**************************/ - /* Test the selected port */ - /**************************/ - - if (b_SelectedPort < b_NumberOfPort) { - /***********************/ - /* Test if output port */ - /***********************/ - - if (((devpriv->ul_TTLPortConfiguration - [b_SelectedPort / - 4] >> (8 * - (b_SelectedPort - % - 4))) & - 0xFF) == 0xFF) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) || (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF)) && (b_OutputChannel > 7)) { - /********************************************/ - /* The selected TTL digital output is wrong */ - /********************************************/ - - printk("\nChannel selection error"); - i_ReturnValue = -103; - } - - if (((b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE)) { - /********************************************/ - /* The selected TTL digital output is wrong */ - /********************************************/ - - printk("\nOutput memory disabled"); - i_ReturnValue = -104; - } - - /************************/ - /* Test the buffer size */ - /************************/ - - if (((b_Command == APCI16XX_TTL_WRITEPORT_ON) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (insn->n < 2)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - } else { - /*****************************************/ - /* The selected TTL output port is wrong */ - /*****************************************/ - - printk("\nPort selection error %lX", - (unsigned long)devpriv-> - ul_TTLPortConfiguration[0]); - i_ReturnValue = -102; - } - } else { - /****************************************/ - /* The selected TTL output port is wrong */ - /****************************************/ - - printk("\nPort selection error %d %d", - b_SelectedPort, b_NumberOfPort); - i_ReturnValue = -102; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /********************************/ - /* Get the digital output state */ - /********************************/ - - dw_Status = - inl(devpriv->iobase + 20 + ((b_SelectedPort / 4) * 4)); - - /**********************************/ - /* Test if output memory not used */ - /**********************************/ - - if (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE) { - /*********************************/ - /* Clear the selected port value */ - /*********************************/ - - dw_Status = - dw_Status & (0xFFFFFFFFUL - - (0xFFUL << (8 * (b_SelectedPort % 4)))); - } - - /******************************/ - /* Test if setting channel ON */ - /******************************/ - - if (b_Command == APCI16XX_TTL_WRITECHANNEL_ON) { - dw_Status = - dw_Status | (1UL << ((8 * (b_SelectedPort % - 4)) + b_OutputChannel)); - } - - /***************************/ - /* Test if setting port ON */ - /***************************/ - - if (b_Command == APCI16XX_TTL_WRITEPORT_ON) { - dw_Status = - dw_Status | ((data[1] & 0xFF) << (8 * - (b_SelectedPort % 4))); - } - - /*******************************/ - /* Test if setting channel OFF */ - /*******************************/ - - if (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) { - dw_Status = - dw_Status & (0xFFFFFFFFUL - - (1UL << ((8 * (b_SelectedPort % 4)) + - b_OutputChannel))); - } - - /****************************/ - /* Test if setting port OFF */ - /****************************/ - - if (b_Command == APCI16XX_TTL_WRITEPORT_OFF) { - dw_Status = - dw_Status & (0xFFFFFFFFUL - - ((data[1] & 0xFF) << (8 * (b_SelectedPort % - 4)))); - } - - outl(dw_Status, - devpriv->iobase + 20 + ((b_SelectedPort / 4) * 4)); - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_Reset(struct comedi_device *dev) | +----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI16XX_Reset(struct comedi_device *dev) -{ - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c deleted file mode 100644 index 9d4a117aad43..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c +++ /dev/null @@ -1,263 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-2200 | Compiler : GCC | - | Module name : hwdrv_apci2200.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-2200 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/********* Definitions for APCI-2200 card *****/ - -/* Card Specific information */ -#define APCI2200_ADDRESS_RANGE 64 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI2200_DIGITAL_OP 4 -#define APCI2200_DIGITAL_IP 0 - -/* TIMER COUNTER WATCHDOG DEFINES */ - -#define APCI2200_WATCHDOG 0x08 -#define APCI2200_WATCHDOG_ENABLEDISABLE 12 -#define APCI2200_WATCHDOG_RELOAD_VALUE 4 -#define APCI2200_WATCHDOG_STATUS 16 - -static int apci2200_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] = inw(devpriv->iobase + APCI2200_DIGITAL_IP); - - return insn->n; -} - -static int apci2200_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 = inw(devpriv->iobase + APCI2200_DIGITAL_OP); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - - outw(s->state, devpriv->iobase + APCI2200_DIGITAL_OP); - } - - data[1] = s->state; - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, -| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - if (data[0] == 0) { - /* Disable the watchdog */ - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - /* Loading the Reload value */ - outw(data[1], - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE); - data[1] = data[1] >> 16; - outw(data[1], - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE + 2); - } /* if(data[0]==0) */ - else { - printk("\nThe input parameters are wrong\n"); - return -EINVAL; - } /* elseif(data[0]==0) */ - - return insn->n; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI2200_StartStopWriteWatchdog | - | (struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data); | - +----------------------------------------------------------------------------+ - | Task : Start / Stop The Watchdog | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ - */ - -static int i_APCI2200_StartStopWriteWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - switch (data[0]) { - case 0: /* stop the watchdog */ - outw(0x0, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); /* disable the watchdog */ - break; - case 1: /* start the watchdog */ - outw(0x0001, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - break; - case 2: /* Software trigger */ - outw(0x0201, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - break; - default: - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* switch(data[0]) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_ReadWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI2200_ReadWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - data[0] = - inw(devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_STATUS) & 0x1; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI2200_Reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - - outw(0x0, devpriv->iobase + APCI2200_DIGITAL_OP); /* RESETS THE DIGITAL OUTPUTS */ - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE); - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE + 2); - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 829af187b249..c7908730caa5 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -633,7 +633,7 @@ static int apci3200_do_insn_bits(struct comedi_device *dev, s->state = inl(devpriv->i_IobaseAddon) & 0xf; if (mask) { s->state &= ~mask; - s->state |= (bits & mask) + s->state |= (bits & mask); outl(s->state, devpriv->i_IobaseAddon); } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index 7a18ce704ba4..ebc1534a8df8 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -1,274 +1,27 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/*. - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-3501 | Compiler : GCC | - | Module name : hwdrv_apci3501.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-3501 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* Card Specific information */ -#define APCI3501_ADDRESS_RANGE 255 - -#define APCI3501_DIGITAL_IP 0x50 -#define APCI3501_DIGITAL_OP 0x40 -#define APCI3501_ANALOG_OUTPUT 0x00 - -/* Analog Output related Defines */ -#define APCI3501_AO_VOLT_MODE 0 -#define APCI3501_AO_PROG 4 -#define APCI3501_AO_TRIG_SCS 8 -#define UNIPOLAR 0 -#define BIPOLAR 1 -#define MODE0 0 -#define MODE1 1 - /* Watchdog Related Defines */ -#define APCI3501_WATCHDOG 0x20 -#define APCI3501_TCW_SYNC_ENABLEDISABLE 0 -#define APCI3501_TCW_RELOAD_VALUE 4 -#define APCI3501_TCW_TIMEBASE 8 -#define APCI3501_TCW_PROG 12 -#define APCI3501_TCW_TRIG_STATUS 16 -#define APCI3501_TCW_IRQ 20 -#define APCI3501_TCW_WARN_TIMEVAL 24 -#define APCI3501_TCW_WARN_TIMEBASE 28 #define ADDIDATA_TIMER 0 #define ADDIDATA_WATCHDOG 2 -/* ANALOG OUTPUT RANGE */ -static struct comedi_lrange range_apci3501_ao = { - 2, { - BIP_RANGE(10), - UNI_RANGE(10) - } -}; - -static int apci3501_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 + APCI3501_DIGITAL_IP) & 0x3; - - return insn->n; -} - -static int apci3501_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - s->state = inl(devpriv->iobase + APCI3501_DIGITAL_OP); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - - outl(s->state, devpriv->iobase + APCI3501_DIGITAL_OP); - } - - data[1] = s->state; - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ConfigAnalogOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Analog Output Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : Voltage Mode | -| 0:Mode 0 | -| 1:Mode 1 | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - outl(data[0], - devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_VOLT_MODE); - - if (data[0]) { - devpriv->b_InterruptMode = MODE1; - } else { - devpriv->b_InterruptMode = MODE0; - } - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_WriteAnalogOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes To the Selected Anlog Output Channel | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0; - - ul_Channel_no = CR_CHAN(insn->chanspec); - - if (devpriv->b_InterruptMode == MODE1) { - ul_Polarity = 0x80000000; - if ((*data < 0) || (*data > 16384)) { - printk("\nIn WriteAnalogOutput :: Not Valid Data\n"); - } - - } /* end if(devpriv->b_InterruptMode==MODE1) */ - else { - ul_Polarity = 0; - if ((*data < 0) || (*data > 8192)) { - printk("\nIn WriteAnalogOutput :: Not Valid Data\n"); - } - - } /* end else */ - - if ((ul_Channel_no < 0) || (ul_Channel_no > 7)) { - printk("\nIn WriteAnalogOutput :: Not Valid Channel\n"); - } /* end if((ul_Channel_no<0)||(ul_Channel_no>7)) */ - - ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - - while (ul_DAC_Ready == 0) { - ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - ul_DAC_Ready = (ul_DAC_Ready >> 8) & 1; - } - - if (ul_DAC_Ready) { -/* Output the Value on the output channels. */ - ul_Command1 = - (unsigned int) ((unsigned int) (ul_Channel_no & 0xFF) | - (unsigned int) ((*data << 0x8) & 0x7FFFFF00L) | - (unsigned int) (ul_Polarity)); - outl(ul_Command1, - devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_PROG); - } - - return insn->n; -} - /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ConfigTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Counter | -| 2 Configure As Watchdog | -| data[1] : 1 Enable Interrupt | -| 0 Disable Interrupt | -| data[2] : Time Unit | -| data[3] : Reload Value | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ + * (*insn_config) for the timer subdevice + * + * Configures The Timer, Counter or Watchdog + * Data Pointer contains configuration parameters as below + * data[0] : 0 Configure As Timer + * 1 Configure As Counter + * 2 Configure As Watchdog + * data[1] : 1 Enable Interrupt + * 0 Disable Interrupt + * data[2] : Time Unit + * data[3] : Reload Value + */ static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; devpriv->tsk_Current = current; @@ -276,224 +29,146 @@ static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; /* Disable the watchdog */ - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Wa */ + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); if (data[1] == 1) { /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x02, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(0x02, dev->iobase + APCI3501_TIMER_CTRL_REG); } else { - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Timer interrupt */ + /* disable Timer interrupt */ + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); } - /* Loading the Timebase value */ - outl(data[2], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TIMEBASE); + outl(data[2], dev->iobase + APCI3501_TIMER_TIMEBASE_REG); + outl(data[3], dev->iobase + APCI3501_TIMER_RELOAD_REG); - /* Loading the Reload value */ - outl(data[3], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_RELOAD_VALUE); - /* Set the mode */ - ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG) | 0xFFF819E0UL; /* e2->e0 */ - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); - } /* end if(data[0]==ADDIDATA_WATCHDOG) */ + /* Set the mode (e2->e0) */ + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG) | 0xFFF819E0UL; + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + } else if (data[0] == ADDIDATA_TIMER) { /* First Stop The Timer */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* Stop The Timer */ + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x02, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(0x02, dev->iobase + APCI3501_TIMER_CTRL_REG); } else { - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Timer interrupt */ + /* disable Timer interrupt */ + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); } - /* Loading Timebase */ - outl(data[2], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TIMEBASE); - - /* Loading the Reload value */ - outl(data[3], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_RELOAD_VALUE); + outl(data[2], dev->iobase + APCI3501_TIMER_TIMEBASE_REG); + outl(data[3], dev->iobase + APCI3501_TIMER_RELOAD_REG); - /* printk ("\nTimer Address :: %x\n", (devpriv->iobase+APCI3501_WATCHDOG)); */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + /* mode 2 */ + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* mode 2 */ - - } /* end if(data[0]==ADDIDATA_TIMER) */ + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_StartStopWriteTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : 1 Start | -| 0 Stop | 2 Trigger | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - + * (*insn_write) for the timer subdevice + * + * Start / Stop The Selected Timer , Counter or Watchdog + * Data Pointer contains configuration parameters as below + * data[0] : 0 Timer + * 1 Counter + * 2 Watchdog + * data[1] : 1 Start + * 0 Stop + * 2 Trigger + */ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; int i_Temp; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Watchdog */ - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); } else if (data[1] == 0) /* Stop The Watchdog */ { /* Stop The Watchdog */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(0x0, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); } else if (data[1] == 2) { - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x200UL; - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); - } /* if(data[1]==2) */ - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Timer */ - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); } else if (data[1] == 0) { /* Stop The Timer */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); } else if (data[1] == 2) { /* Trigger the Timer */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x200UL; - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); } + } - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - i_Temp = inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; + i_Temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ReadTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : Timer Counter Watchdog Number | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - + * (*insn_read) for the timer subdevice + * + * Read The Selected Timer, Counter or Watchdog + * Data Pointer contains configuration parameters as below + * data[0] : 0 Timer + * 1 Counter + * 2 Watchdog + * data[1] : Timer Counter Watchdog Number + */ static int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci3501_private *devpriv = dev->private; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { - data[0] = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; - data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG); - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + data[0] = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + data[1] = inl(dev->iobase + APCI3501_TIMER_SYNC_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { - data[0] = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; - data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG); - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ + data[0] = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + data[1] = inl(dev->iobase + APCI3501_TIMER_SYNC_REG); + } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)) { @@ -501,111 +176,3 @@ static int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, } return insn->n; } - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task :Resets the registers of the card | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI3501_Reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - int i_Count = 0, i_temp = 0; - unsigned int ul_Command1 = 0, ul_Polarity, ul_DAC_Ready = 0; - - outl(0x0, devpriv->iobase + APCI3501_DIGITAL_OP); - outl(1, devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_VOLT_MODE); - - ul_Polarity = 0x80000000; - - for (i_Count = 0; i_Count <= 7; i_Count++) { - ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - - while (ul_DAC_Ready == 0) { - ul_DAC_Ready = - inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - ul_DAC_Ready = (ul_DAC_Ready >> 8) & 1; - } - - if (ul_DAC_Ready) { - /* Output the Value on the output channels. */ - ul_Command1 = - (unsigned int) ((unsigned int) (i_Count & 0xFF) | - (unsigned int) ((i_temp << 0x8) & 0x7FFFFF00L) | - (unsigned int) (ul_Polarity)); - outl(ul_Command1, - devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_PROG); - } - } - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI3501_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt processing Routine | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI3501_Interrupt(int irq, void *d) -{ - int i_temp; - struct comedi_device *dev = d; - struct addi_private *devpriv = dev->private; - unsigned int ui_Timer_AOWatchdog; - unsigned long ul_Command1; - - /* Disable Interrupt */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - - ul_Command1 = (ul_Command1 & 0xFFFFF9FDul); - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - - ui_Timer_AOWatchdog = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_IRQ) & 0x1; - - if ((!ui_Timer_AOWatchdog)) { - comedi_error(dev, "IRQ from unknown source"); - return; - } - -/* -* Enable Interrupt Send a signal to from kernel to user space -*/ - send_sig(SIGIO, devpriv->tsk_Current, 0); - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1); - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - i_temp = inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; - return; -} diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c index c981d4b1cc73..5a53e58258a0 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -1,3 +1,5 @@ +#include <linux/pci.h> + #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" @@ -53,11 +55,6 @@ static int apci035_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci035_driver); } -static void apci035_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci035_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x0300) }, { 0 } @@ -68,7 +65,7 @@ static struct pci_driver apci035_pci_driver = { .name = "addi_apci_035", .id_table = apci035_pci_table, .probe = apci035_pci_probe, - .remove = apci035_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci035_driver, apci035_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 7f9424205a64..c0d0429c35c8 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -29,6 +29,9 @@ * source code. */ +#include <linux/pci.h> +#include <linux/interrupt.h> + #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" @@ -375,11 +378,6 @@ static int apci1032_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1032_driver); } -static void apci1032_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci1032_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1003) }, { 0 } @@ -390,7 +388,7 @@ static struct pci_driver apci1032_pci_driver = { .name = "addi_apci_1032", .id_table = apci1032_pci_table, .probe = apci1032_pci_probe, - .remove = apci1032_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index 8e686a9b811b..9c2f8eeb7977 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -1,3 +1,5 @@ +#include <linux/pci.h> + #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" @@ -53,11 +55,6 @@ static int apci1500_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1500_driver); } -static void apci1500_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci1500_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, 0x80fc) }, { 0 } @@ -68,7 +65,7 @@ static struct pci_driver apci1500_pci_driver = { .name = "addi_apci_1500", .id_table = apci1500_pci_table, .probe = apci1500_pci_probe, - .remove = apci1500_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci1500_driver, apci1500_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index 8fef04b4d197..69e399638419 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -29,7 +29,10 @@ * this source code. */ +#include <linux/pci.h> + #include "../comedidev.h" +#include "addi_watchdog.h" #include "comedi_fc.h" /* @@ -49,13 +52,6 @@ * PCI bar 2 I/O Register map - Watchdog (APCI-1516 and APCI-2016) */ #define APCI1516_WDOG_REG 0x00 -#define APCI1516_WDOG_RELOAD_REG 0x04 -#define APCI1516_WDOG_CTRL_REG 0x0c -#define APCI1516_WDOG_CTRL_ENABLE (1 << 0) -#define APCI1516_WDOG_CTRL_SW_TRIG (1 << 9) -#define APCI1516_WDOG_STATUS_REG 0x10 -#define APCI1516_WDOG_STATUS_ENABLED (1 << 0) -#define APCI1516_WDOG_STATUS_SW_TRIG (1 << 1) struct apci1516_boardinfo { const char *name; @@ -86,7 +82,6 @@ static const struct apci1516_boardinfo apci1516_boardtypes[] = { struct apci1516_private { unsigned long wdog_iobase; - unsigned int ctrl; }; static int apci1516_di_insn_bits(struct comedi_device *dev, @@ -120,82 +115,6 @@ static int apci1516_do_insn_bits(struct comedi_device *dev, return insn->n; } -/* - * The watchdog subdevice is configured with two INSN_CONFIG instructions: - * - * Enable the watchdog and set the reload timeout: - * data[0] = INSN_CONFIG_ARM - * data[1] = timeout reload value - * - * Disable the watchdog: - * data[0] = INSN_CONFIG_DISARM - */ -static int apci1516_wdog_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1516_private *devpriv = dev->private; - unsigned int reload; - - switch (data[0]) { - case INSN_CONFIG_ARM: - devpriv->ctrl = APCI1516_WDOG_CTRL_ENABLE; - reload = data[1] & s->maxdata; - outw(reload, devpriv->wdog_iobase + APCI1516_WDOG_RELOAD_REG); - - /* Time base is 20ms, let the user know the timeout */ - dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n", - 20 * reload + 20); - break; - case INSN_CONFIG_DISARM: - devpriv->ctrl = 0; - break; - default: - return -EINVAL; - } - - outw(devpriv->ctrl, devpriv->wdog_iobase + APCI1516_WDOG_CTRL_REG); - - return insn->n; -} - -static int apci1516_wdog_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1516_private *devpriv = dev->private; - int i; - - if (devpriv->ctrl == 0) { - dev_warn(dev->class_dev, "watchdog is disabled\n"); - return -EINVAL; - } - - /* "ping" the watchdog */ - for (i = 0; i < insn->n; i++) { - outw(devpriv->ctrl | APCI1516_WDOG_CTRL_SW_TRIG, - devpriv->wdog_iobase + APCI1516_WDOG_CTRL_REG); - } - - return insn->n; -} - -static int apci1516_wdog_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1516_private *devpriv = dev->private; - int i; - - for (i = 0; i < insn->n; i++) - data[i] = inw(devpriv->wdog_iobase + APCI1516_WDOG_STATUS_REG); - - return insn->n; -} - static int apci1516_reset(struct comedi_device *dev) { const struct apci1516_boardinfo *this_board = comedi_board(dev); @@ -205,8 +124,8 @@ static int apci1516_reset(struct comedi_device *dev) return 0; outw(0x0, dev->iobase + APCI1516_DO_REG); - outw(0x0, devpriv->wdog_iobase + APCI1516_WDOG_CTRL_REG); - outw(0x0, devpriv->wdog_iobase + APCI1516_WDOG_RELOAD_REG); + + addi_watchdog_reset(devpriv->wdog_iobase); return 0; } @@ -285,13 +204,9 @@ static int apci1516_auto_attach(struct comedi_device *dev, /* Initialize the watchdog subdevice */ s = &dev->subdevices[2]; if (this_board->has_wdog) { - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 1; - s->maxdata = 0xff; - s->insn_write = apci1516_wdog_insn_write; - s->insn_read = apci1516_wdog_insn_read; - s->insn_config = apci1516_wdog_insn_config; + ret = addi_watchdog_init(s, devpriv->wdog_iobase); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -304,10 +219,12 @@ static void apci1516_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - if (dev->iobase) { + if (dev->iobase) apci1516_reset(dev); + if (dev->subdevices) + addi_watchdog_cleanup(&dev->subdevices[2]); + if (dev->iobase) comedi_pci_disable(pcidev); - } } static struct comedi_driver apci1516_driver = { @@ -323,11 +240,6 @@ static int apci1516_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1516_driver); } -static void apci1516_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci1516_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1016) }, { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1516) }, @@ -340,7 +252,7 @@ static struct pci_driver apci1516_pci_driver = { .name = "addi_apci_1516", .id_table = apci1516_pci_table, .probe = apci1516_pci_probe, - .remove = apci1516_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci1516_driver, apci1516_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 513e536f292f..ddea64df9180 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -1,3 +1,5 @@ +#include <linux/pci.h> + #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" @@ -50,11 +52,6 @@ static int apci1564_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1564_driver); } -static void apci1564_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci1564_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1006) }, { 0 } @@ -65,7 +62,7 @@ static struct pci_driver apci1564_pci_driver = { .name = "addi_apci_1564", .id_table = apci1564_pci_table, .probe = apci1564_pci_probe, - .remove = apci1564_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci1564_driver, apci1564_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index ab9a96ac8180..e51f80001363 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -1,49 +1,227 @@ +/* + * addi_apci_16xx.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: S. Weber + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You 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> + #include "../comedidev.h" -#include "comedi_fc.h" -#include "amcc_s5933.h" -#include "addi-data/addi_common.h" +/* + * PCI device ids supported by this driver + */ +#define PCI_DEVICE_ID_APCI1648 0x1009 +#define PCI_DEVICE_ID_APCI1696 0x100a -#include "addi-data/addi_eeprom.c" -#include "addi-data/hwdrv_apci16xx.c" -#include "addi-data/addi_common.c" +/* + * Register I/O map + */ +#define APCI16XX_IN_REG(x) (((x) * 4) + 0x08) +#define APCI16XX_OUT_REG(x) (((x) * 4) + 0x14) +#define APCI16XX_DIR_REG(x) (((x) * 4) + 0x20) -static const struct addi_board apci16xx_boardtypes[] = { +struct apci16xx_boardinfo { + const char *name; + unsigned short vendor; + unsigned short device; + int n_chan; +}; + +static const struct apci16xx_boardinfo apci16xx_boardtypes[] = { { - .pc_DriverName = "apci1648", - .i_VendorId = PCI_VENDOR_ID_ADDIDATA, - .i_DeviceId = 0x1009, - .i_IorangeBase0 = 128, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .i_NbrTTLChannel = 48, - .reset = i_APCI16XX_Reset, - .ttl_config = i_APCI16XX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO, - .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue, - .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO, + .name = "apci1648", + .vendor = PCI_VENDOR_ID_ADDIDATA, + .device = PCI_DEVICE_ID_APCI1648, + .n_chan = 48, /* 2 subdevices */ }, { - .pc_DriverName = "apci1696", - .i_VendorId = PCI_VENDOR_ID_ADDIDATA, - .i_DeviceId = 0x100A, - .i_IorangeBase0 = 128, - .i_PCIEeprom = ADDIDATA_NO_EEPROM, - .i_NbrTTLChannel = 96, - .reset = i_APCI16XX_Reset, - .ttl_config = i_APCI16XX_InsnConfigInitTTLIO, - .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO, - .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue, - .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO, + .name = "apci1696", + .vendor = PCI_VENDOR_ID_ADDIDATA, + .device = PCI_DEVICE_ID_APCI1696, + .n_chan = 96, /* 3 subdevices */ }, }; +static int apci16xx_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); + unsigned int bits; + + /* + * Each 8-bit "port" is configurable as either input or + * output. Changing the configuration of any channel in + * a port changes the entire port. + */ + if (chan_mask & 0x000000ff) + bits = 0x000000ff; + else if (chan_mask & 0x0000ff00) + bits = 0x0000ff00; + else if (chan_mask & 0x00ff0000) + bits = 0x00ff0000; + else + bits = 0xff000000; + + 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_INPUT : COMEDI_OUTPUT; + return insn->n; + default: + return -EINVAL; + } + + outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(s->index)); + + return insn->n; +} + +static int apci16xx_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask = data[0]; + unsigned int bits = data[1]; + + /* Only update the channels configured as outputs */ + mask &= s->io_bits; + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + outl(s->state, dev->iobase + APCI16XX_OUT_REG(s->index)); + } + + data[1] = inl(dev->iobase + APCI16XX_IN_REG(s->index)); + + return insn->n; +} + +static const void *apci16xx_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct apci16xx_boardinfo *board; + int i; + + for (i = 0; i < ARRAY_SIZE(apci16xx_boardtypes); i++) { + board = &apci16xx_boardtypes[i]; + if (board->vendor == pcidev->vendor && + board->device == pcidev->device) + return board; + } + return NULL; +} + +static int apci16xx_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct apci16xx_boardinfo *board; + struct comedi_subdevice *s; + unsigned int n_subdevs; + unsigned int last; + int i; + int ret; + + board = apci16xx_find_boardinfo(dev, pcidev); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 0); + + /* + * Work out the nubmer of subdevices needed to support all the + * digital i/o channels on the board. Each subdevice supports + * up to 32 channels. + */ + n_subdevs = board->n_chan / 32; + if ((n_subdevs * 32) < board->n_chan) { + last = board->n_chan - (n_subdevs * 32); + n_subdevs++; + } else { + last = 0; + } + + ret = comedi_alloc_subdevices(dev, n_subdevs); + if (ret) + return ret; + + /* Initialize the TTL digital i/o subdevices */ + for (i = 0; i < n_subdevs; i++) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_WRITEABLE | SDF_READABLE; + s->n_chan = ((i * 32) < board->n_chan) ? 32 : last; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = apci16xx_insn_config; + s->insn_bits = apci16xx_dio_insn_bits; + + /* Default all channels to inputs */ + s->io_bits = 0; + outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(i)); + } + + return 0; +} + +static void apci16xx_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + } +} + static struct comedi_driver apci16xx_driver = { .driver_name = "addi_apci_16xx", .module = THIS_MODULE, - .auto_attach = addi_auto_attach, - .detach = i_ADDI_Detach, + .auto_attach = apci16xx_auto_attach, + .detach = apci16xx_detach, .num_names = ARRAY_SIZE(apci16xx_boardtypes), - .board_name = &apci16xx_boardtypes[0].pc_DriverName, - .offset = sizeof(struct addi_board), + .board_name = &apci16xx_boardtypes[0].name, + .offset = sizeof(struct apci16xx_boardinfo), }; static int apci16xx_pci_probe(struct pci_dev *dev, @@ -52,14 +230,9 @@ static int apci16xx_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci16xx_driver); } -static void apci16xx_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci16xx_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1009) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x100a) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1648) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1696) }, { 0 } }; MODULE_DEVICE_TABLE(pci, apci16xx_pci_table); @@ -68,10 +241,10 @@ static struct pci_driver apci16xx_pci_driver = { .name = "addi_apci_16xx", .id_table = apci16xx_pci_table, .probe = apci16xx_pci_probe, - .remove = apci16xx_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci16xx_driver, apci16xx_pci_driver); +MODULE_DESCRIPTION("ADDI-DATA APCI-1648/1696, TTL I/O boards"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c index 152e7ef9b17b..e83e829831b0 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1710.c +++ b/drivers/staging/comedi/drivers/addi_apci_1710.c @@ -1,3 +1,5 @@ +#include <linux/pci.h> + #include <asm/i387.h> #include "../comedidev.h" @@ -128,11 +130,6 @@ static int apci1710_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1710_driver); } -static void apci1710_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci1710_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, APCI1710_BOARD_DEVICE_ID) }, { 0 } @@ -143,7 +140,7 @@ static struct pci_driver apci1710_pci_driver = { .name = "addi_apci_1710", .id_table = apci1710_pci_table, .probe = apci1710_pci_probe, - .remove = apci1710_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci1710_driver, apci1710_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index 8f8d3e95fc78..9ce1d26aff2f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -29,7 +29,11 @@ * this source code. */ +#include <linux/pci.h> +#include <linux/interrupt.h> + #include "../comedidev.h" +#include "addi_watchdog.h" #include "comedi_fc.h" /* @@ -45,17 +49,12 @@ #define APCI2032_STATUS_REG 0x0c #define APCI2032_STATUS_IRQ (1 << 0) #define APCI2032_WDOG_REG 0x10 -#define APCI2032_WDOG_RELOAD_REG 0x14 -#define APCI2032_WDOG_TIMEBASE 0x18 -#define APCI2032_WDOG_CTRL_REG 0x1c -#define APCI2032_WDOG_CTRL_ENABLE (1 << 0) -#define APCI2032_WDOG_CTRL_SW_TRIG (1 << 9) -#define APCI2032_WDOG_STATUS_REG 0x20 -#define APCI2032_WDOG_STATUS_ENABLED (1 << 0) -#define APCI2032_WDOG_STATUS_SW_TRIG (1 << 1) - -struct apci2032_private { - unsigned int wdog_ctrl; + +struct apci2032_int_private { + spinlock_t spinlock; + unsigned int stop_count; + bool active; + unsigned char enabled_isns; }; static int apci2032_do_insn_bits(struct comedi_device *dev, @@ -79,88 +78,47 @@ static int apci2032_do_insn_bits(struct comedi_device *dev, return insn->n; } -/* - * The watchdog subdevice is configured with two INSN_CONFIG instructions: - * - * Enable the watchdog and set the reload timeout: - * data[0] = INSN_CONFIG_ARM - * data[1] = timeout reload value - * - * Disable the watchdog: - * data[0] = INSN_CONFIG_DISARM - */ -static int apci2032_wdog_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci2032_int_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct apci2032_private *devpriv = dev->private; - unsigned int reload; - - switch (data[0]) { - case INSN_CONFIG_ARM: - devpriv->wdog_ctrl = APCI2032_WDOG_CTRL_ENABLE; - reload = data[1] & s->maxdata; - outw(reload, dev->iobase + APCI2032_WDOG_RELOAD_REG); - - /* Time base is 20ms, let the user know the timeout */ - dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n", - 20 * reload + 20); - break; - case INSN_CONFIG_DISARM: - devpriv->wdog_ctrl = 0; - break; - default: - return -EINVAL; - } - - outw(devpriv->wdog_ctrl, dev->iobase + APCI2032_WDOG_CTRL_REG); - + data[1] = inl(dev->iobase + APCI2032_INT_STATUS_REG) & 3; return insn->n; } -static int apci2032_wdog_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static void apci2032_int_stop(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct apci2032_private *devpriv = dev->private; - int i; - - if (devpriv->wdog_ctrl == 0) { - dev_warn(dev->class_dev, "watchdog is disabled\n"); - return -EINVAL; - } - - /* "ping" the watchdog */ - for (i = 0; i < insn->n; i++) { - outw(devpriv->wdog_ctrl | APCI2032_WDOG_CTRL_SW_TRIG, - dev->iobase + APCI2032_WDOG_CTRL_REG); - } + struct apci2032_int_private *subpriv = s->private; - return insn->n; + subpriv->active = false; + subpriv->enabled_isns = 0; + outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); } -static int apci2032_wdog_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static bool apci2032_int_start(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned char enabled_isns) { - int i; - - for (i = 0; i < insn->n; i++) - data[i] = inl(dev->iobase + APCI2032_WDOG_STATUS_REG); - - return insn->n; -} + struct apci2032_int_private *subpriv = s->private; + struct comedi_cmd *cmd = &s->async->cmd; + bool do_event; + + subpriv->enabled_isns = enabled_isns; + subpriv->stop_count = cmd->stop_arg; + if (cmd->stop_src == TRIG_COUNT && subpriv->stop_count == 0) { + /* An empty acquisition! */ + s->async->events |= COMEDI_CB_EOA; + subpriv->active = false; + do_event = true; + } else { + subpriv->active = true; + outl(enabled_isns, dev->iobase + APCI2032_INT_CTRL_REG); + do_event = false; + } -static int apci2032_int_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - data[1] = s->state; - return insn->n; + return do_event; } static int apci2032_int_cmdtest(struct comedi_device *dev, @@ -172,15 +130,17 @@ static int apci2032_int_cmdtest(struct comedi_device *dev, /* 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_OTHER); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); + 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) @@ -189,18 +149,11 @@ static int apci2032_int_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - - /* - * 0 == no trigger - * 1 == trigger on VCC interrupt - * 2 == trigger on CC interrupt - * 3 == trigger on either VCC or CC interrupt - */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 3); - + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + if (cmd->stop_src == TRIG_NONE) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; @@ -217,8 +170,22 @@ static int apci2032_int_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; + struct apci2032_int_private *subpriv = s->private; + unsigned char enabled_isns; + unsigned int n; + unsigned long flags; + bool do_event; + + enabled_isns = 0; + for (n = 0; n < cmd->chanlist_len; n++) + enabled_isns |= 1 << CR_CHAN(cmd->chanlist[n]); + + spin_lock_irqsave(&subpriv->spinlock, flags); + do_event = apci2032_int_start(dev, s, enabled_isns); + spin_unlock_irqrestore(&subpriv->spinlock, flags); - outl(cmd->scan_begin_arg, dev->iobase + APCI2032_INT_CTRL_REG); + if (do_event) + comedi_event(dev, s); return 0; } @@ -226,7 +193,13 @@ static int apci2032_int_cmd(struct comedi_device *dev, static int apci2032_int_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); + struct apci2032_int_private *subpriv = s->private; + unsigned long flags; + + spin_lock_irqsave(&subpriv->spinlock, flags); + if (subpriv->active) + apci2032_int_stop(dev, s); + spin_unlock_irqrestore(&subpriv->spinlock, flags); return 0; } @@ -235,19 +208,64 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; + struct apci2032_int_private *subpriv; unsigned int val; + bool do_event = false; + + if (!dev->attached) + return IRQ_NONE; /* Check if VCC OR CC interrupt has occurred */ val = inl(dev->iobase + APCI2032_STATUS_REG) & APCI2032_STATUS_IRQ; if (!val) return IRQ_NONE; - s->state = inl(dev->iobase + APCI2032_INT_STATUS_REG); - outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); + subpriv = s->private; + spin_lock(&subpriv->spinlock); + + val = inl(dev->iobase + APCI2032_INT_STATUS_REG) & 3; + /* Disable triggered interrupt sources. */ + outl(~val & 3, dev->iobase + APCI2032_INT_CTRL_REG); + /* + * Note: We don't reenable the triggered interrupt sources because they + * are level-sensitive, hardware error status interrupt sources and + * they'd keep triggering interrupts repeatedly. + */ - comedi_buf_put(s->async, s->state); - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(dev, s); + if (subpriv->active && (val & subpriv->enabled_isns) != 0) { + unsigned short bits; + unsigned int n, len; + unsigned int *chanlist; + + /* Bits in scan data correspond to indices in channel list. */ + bits = 0; + len = s->async->cmd.chanlist_len; + chanlist = &s->async->cmd.chanlist[0]; + for (n = 0; n < len; n++) + if ((val & (1U << CR_CHAN(chanlist[n]))) != 0) + bits |= 1U << n; + + if (comedi_buf_put(s->async, bits)) { + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + if (s->async->cmd.stop_src == TRIG_COUNT && + subpriv->stop_count > 0) { + subpriv->stop_count--; + if (subpriv->stop_count == 0) { + /* end of acquisition */ + s->async->events |= COMEDI_CB_EOA; + apci2032_int_stop(dev, s); + } + } + } else { + apci2032_int_stop(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; + } + do_event = true; + } + + spin_unlock(&subpriv->spinlock); + if (do_event) + comedi_event(dev, s); return IRQ_HANDLED; } @@ -256,8 +274,8 @@ static int apci2032_reset(struct comedi_device *dev) { outl(0x0, dev->iobase + APCI2032_DO_REG); outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); - outl(0x0, dev->iobase + APCI2032_WDOG_CTRL_REG); - outl(0x0, dev->iobase + APCI2032_WDOG_RELOAD_REG); + + addi_watchdog_reset(dev->iobase + APCI2032_WDOG_REG); return 0; } @@ -266,21 +284,16 @@ static int apci2032_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct apci2032_private *devpriv; struct comedi_subdevice *s; int ret; dev->board_name = dev->driver->driver_name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - ret = comedi_pci_enable(pcidev, dev->board_name); if (ret) return ret; dev->iobase = pci_resource_start(pcidev, 1); + apci2032_reset(dev); if (pcidev->irq > 0) { ret = request_irq(pcidev->irq, apci2032_interrupt, @@ -304,32 +317,34 @@ static int apci2032_auto_attach(struct comedi_device *dev, /* Initialize the watchdog subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 1; - s->maxdata = 0xff; - s->insn_write = apci2032_wdog_insn_write; - s->insn_read = apci2032_wdog_insn_read; - s->insn_config = apci2032_wdog_insn_config; + ret = addi_watchdog_init(s, dev->iobase + APCI2032_WDOG_REG); + if (ret) + return ret; /* Initialize the interrupt subdevice */ s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 2; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci2032_int_insn_bits; if (dev->irq) { + struct apci2032_int_private *subpriv; + dev->read_subdev = s; - s->type = COMEDI_SUBD_DI | SDF_CMD_READ; - s->subdev_flags = SDF_READABLE; - s->n_chan = 1; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = apci2032_int_insn_bits; + subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); + if (!subpriv) + return -ENOMEM; + spin_lock_init(&subpriv->spinlock); + s->private = subpriv; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->len_chanlist = 2; s->do_cmdtest = apci2032_int_cmdtest; s->do_cmd = apci2032_int_cmd; s->cancel = apci2032_int_cancel; - } else { - s->type = COMEDI_SUBD_UNUSED; } - apci2032_reset(dev); return 0; } @@ -341,6 +356,10 @@ static void apci2032_detach(struct comedi_device *dev) apci2032_reset(dev); if (dev->irq) free_irq(dev->irq, dev); + if (dev->read_subdev) + kfree(dev->read_subdev->private); + if (dev->subdevices) + addi_watchdog_cleanup(&dev->subdevices[1]); if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); @@ -360,11 +379,6 @@ static int apci2032_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci2032_driver); } -static void apci2032_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci2032_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1004) }, { 0 } @@ -375,7 +389,7 @@ static struct pci_driver apci2032_pci_driver = { .name = "addi_apci_2032", .id_table = apci2032_pci_table, .probe = apci2032_pci_probe, - .remove = apci2032_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci2032_driver, apci2032_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index 7c2c5db01218..b1c4226902e1 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -1,42 +1,152 @@ +/* + * addi_apci_2200.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You 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> + #include "../comedidev.h" -#include "comedi_fc.h" -#include "amcc_s5933.h" - -#include "addi-data/addi_common.h" - -#include "addi-data/addi_eeprom.c" -#include "addi-data/hwdrv_apci2200.c" -#include "addi-data/addi_common.c" - -static const struct addi_board apci2200_boardtypes[] = { - { - .pc_DriverName = "apci2200", - .i_VendorId = PCI_VENDOR_ID_ADDIDATA, - .i_DeviceId = 0x1005, - .i_IorangeBase0 = 4, - .i_IorangeBase1 = APCI2200_ADDRESS_RANGE, - .i_PCIEeprom = ADDIDATA_EEPROM, - .pc_EepromChip = ADDIDATA_93C76, - .i_NbrDiChannel = 8, - .i_NbrDoChannel = 16, - .i_Timer = 1, - .reset = i_APCI2200_Reset, - .di_bits = apci2200_di_insn_bits, - .do_bits = apci2200_do_insn_bits, - .timer_config = i_APCI2200_ConfigWatchdog, - .timer_write = i_APCI2200_StartStopWriteWatchdog, - .timer_read = i_APCI2200_ReadWatchdog, - }, -}; +#include "addi_watchdog.h" + +/* + * I/O Register Map + */ +#define APCI2200_DI_REG 0x00 +#define APCI2200_DO_REG 0x04 +#define APCI2200_WDOG_REG 0x08 + +static int apci2200_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inw(dev->iobase + APCI2200_DI_REG); + + return insn->n; +} + +static int apci2200_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask = data[0]; + unsigned int bits = data[1]; + + s->state = inw(dev->iobase + APCI2200_DO_REG); + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + outw(s->state, dev->iobase + APCI2200_DO_REG); + } + + data[1] = s->state; + + return insn->n; +} + +static int apci2200_reset(struct comedi_device *dev) +{ + outw(0x0, dev->iobase + APCI2200_DO_REG); + + addi_watchdog_reset(dev->iobase + APCI2200_WDOG_REG); + + return 0; +} + +static int apci2200_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret; + + dev->board_name = dev->driver->driver_name; + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 1); + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* Initialize the digital input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci2200_di_insn_bits; + + /* Initialize the digital output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci2200_do_insn_bits; + + /* Initialize the watchdog subdevice */ + s = &dev->subdevices[2]; + ret = addi_watchdog_init(s, dev->iobase + APCI2200_WDOG_REG); + if (ret) + return ret; + + apci2200_reset(dev); + return 0; +} + +static void apci2200_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (dev->iobase) + apci2200_reset(dev); + if (dev->subdevices) + addi_watchdog_cleanup(&dev->subdevices[2]); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + } +} static struct comedi_driver apci2200_driver = { .driver_name = "addi_apci_2200", .module = THIS_MODULE, - .auto_attach = addi_auto_attach, - .detach = i_ADDI_Detach, - .num_names = ARRAY_SIZE(apci2200_boardtypes), - .board_name = &apci2200_boardtypes[0].pc_DriverName, - .offset = sizeof(struct addi_board), + .auto_attach = apci2200_auto_attach, + .detach = apci2200_detach, }; static int apci2200_pci_probe(struct pci_dev *dev, @@ -45,11 +155,6 @@ static int apci2200_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci2200_driver); } -static void apci2200_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci2200_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1005) }, { 0 } @@ -60,10 +165,10 @@ static struct pci_driver apci2200_pci_driver = { .name = "addi_apci_2200", .id_table = apci2200_pci_table, .probe = apci2200_pci_probe, - .remove = apci2200_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci2200_driver, apci2200_pci_driver); +MODULE_DESCRIPTION("ADDI-DATA APCI-2200 Relay board, optically isolated"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index fec2962affc7..917234d24e99 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -1,3 +1,5 @@ +#include <linux/pci.h> + #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" @@ -251,11 +253,6 @@ static int apci3120_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3120_driver); } -static void apci3120_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci3120_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, 0x818d) }, { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, 0x828d) }, @@ -267,7 +264,7 @@ static struct pci_driver apci3120_pci_driver = { .name = "addi_apci_3120", .id_table = apci3120_pci_table, .probe = apci3120_pci_probe, - .remove = apci3120_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c index 9085b774b48d..90ee4f844f91 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ b/drivers/staging/comedi/drivers/addi_apci_3200.c @@ -1,3 +1,5 @@ +#include <linux/pci.h> + #include <asm/i387.h> #include "../comedidev.h" @@ -106,15 +108,10 @@ static int apci3200_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3200_driver); } -static void apci3200_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver apci3200_pci_driver = { .name = "addi_apci_3200", .id_table = apci3200_pci_table, .probe = apci3200_pci_probe, - .remove = apci3200_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci3200_driver, apci3200_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index ed297deb8634..786fcaf82c32 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -1,54 +1,445 @@ +/* + * addi_apci_3501.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You 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> +#include <linux/interrupt.h> +#include <linux/sched.h> + #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" -#include "addi-data/addi_common.h" +/* + * PCI bar 1 register I/O map + */ +#define APCI3501_AO_CTRL_STATUS_REG 0x00 +#define APCI3501_AO_CTRL_BIPOLAR (1 << 0) +#define APCI3501_AO_STATUS_READY (1 << 8) +#define APCI3501_AO_DATA_REG 0x04 +#define APCI3501_AO_DATA_CHAN(x) ((x) << 0) +#define APCI3501_AO_DATA_VAL(x) ((x) << 8) +#define APCI3501_AO_DATA_BIPOLAR (1 << 31) +#define APCI3501_AO_TRIG_SCS_REG 0x08 +#define APCI3501_TIMER_SYNC_REG 0x20 +#define APCI3501_TIMER_RELOAD_REG 0x24 +#define APCI3501_TIMER_TIMEBASE_REG 0x28 +#define APCI3501_TIMER_CTRL_REG 0x2c +#define APCI3501_TIMER_STATUS_REG 0x30 +#define APCI3501_TIMER_IRQ_REG 0x34 +#define APCI3501_TIMER_WARN_RELOAD_REG 0x38 +#define APCI3501_TIMER_WARN_TIMEBASE_REG 0x3c +#define APCI3501_DO_REG 0x40 +#define APCI3501_DI_REG 0x50 -#include "addi-data/addi_eeprom.c" -#include "addi-data/hwdrv_apci3501.c" -#include "addi-data/addi_common.c" - -static const struct addi_board apci3501_boardtypes[] = { - { - .pc_DriverName = "apci3501", - .i_VendorId = PCI_VENDOR_ID_ADDIDATA, - .i_DeviceId = 0x3001, - .i_IorangeBase0 = 64, - .i_IorangeBase1 = APCI3501_ADDRESS_RANGE, - .i_PCIEeprom = ADDIDATA_EEPROM, - .pc_EepromChip = ADDIDATA_S5933, - .i_AoMaxdata = 16383, - .pr_AoRangelist = &range_apci3501_ao, - .i_NbrDiChannel = 2, - .i_NbrDoChannel = 2, - .i_DoMaxdata = 0x3, - .i_Timer = 1, - .interrupt = v_APCI3501_Interrupt, - .reset = i_APCI3501_Reset, - .ao_config = i_APCI3501_ConfigAnalogOutput, - .ao_write = i_APCI3501_WriteAnalogOutput, - .di_bits = apci3501_di_insn_bits, - .do_bits = apci3501_do_insn_bits, - .timer_config = i_APCI3501_ConfigTimerCounterWatchdog, - .timer_write = i_APCI3501_StartStopWriteTimerCounterWatchdog, - .timer_read = i_APCI3501_ReadTimerCounterWatchdog, - }, +/* + * AMCC S5933 NVRAM + */ +#define NVRAM_USER_DATA_START 0x100 + +#define NVCMD_BEGIN_READ (0x7 << 5) +#define NVCMD_LOAD_LOW (0x4 << 5) +#define NVCMD_LOAD_HIGH (0x5 << 5) + +/* + * Function types stored in the eeprom + */ +#define EEPROM_DIGITALINPUT 0 +#define EEPROM_DIGITALOUTPUT 1 +#define EEPROM_ANALOGINPUT 2 +#define EEPROM_ANALOGOUTPUT 3 +#define EEPROM_TIMER 4 +#define EEPROM_WATCHDOG 5 +#define EEPROM_TIMER_WATCHDOG_COUNTER 10 + +struct apci3501_private { + int i_IobaseAmcc; + struct task_struct *tsk_Current; + unsigned char b_TimerSelectMode; }; -static DEFINE_PCI_DEVICE_TABLE(apci3501_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3001) }, - { 0 } +static struct comedi_lrange apci3501_ao_range = { + 2, { + BIP_RANGE(10), + UNI_RANGE(10) + } }; -MODULE_DEVICE_TABLE(pci, apci3501_pci_table); + +static int apci3501_wait_for_dac(struct comedi_device *dev) +{ + unsigned int status; + + do { + status = inl(dev->iobase + APCI3501_AO_CTRL_STATUS_REG); + } while (!(status & APCI3501_AO_STATUS_READY)); + + return 0; +} + +static int apci3501_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = 0; + int i; + int ret; + + /* + * All analog output channels have the same output range. + * 14-bit bipolar: 0-10V + * 13-bit unipolar: +/-10V + * Changing the range of one channel changes all of them! + */ + if (range) { + outl(0, dev->iobase + APCI3501_AO_CTRL_STATUS_REG); + } else { + val |= APCI3501_AO_DATA_BIPOLAR; + outl(APCI3501_AO_CTRL_BIPOLAR, + dev->iobase + APCI3501_AO_CTRL_STATUS_REG); + } + + val |= APCI3501_AO_DATA_CHAN(chan); + + for (i = 0; i < insn->n; i++) { + if (range == 1) { + if (data[i] > 0x1fff) { + dev_err(dev->class_dev, + "Unipolar resolution is only 13-bits\n"); + return -EINVAL; + } + } + + ret = apci3501_wait_for_dac(dev); + if (ret) + return ret; + + outl(val | APCI3501_AO_DATA_VAL(data[i]), + dev->iobase + APCI3501_AO_DATA_REG); + } + + return insn->n; +} + +#include "addi-data/hwdrv_apci3501.c" + +static int apci3501_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inl(dev->iobase + APCI3501_DI_REG) & 0x3; + + return insn->n; +} + +static int apci3501_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask = data[0]; + unsigned int bits = data[1]; + + s->state = inl(dev->iobase + APCI3501_DO_REG); + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + outl(s->state, dev->iobase + APCI3501_DO_REG); + } + + data[1] = s->state; + + return insn->n; +} + +static void apci3501_eeprom_wait(unsigned long iobase) +{ + unsigned char val; + + do { + val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD); + } while (val & 0x80); +} + +static unsigned short apci3501_eeprom_readw(unsigned long iobase, + unsigned short addr) +{ + unsigned short val = 0; + unsigned char tmp; + unsigned char i; + + /* Add the offset to the start of the user data */ + addr += NVRAM_USER_DATA_START; + + for (i = 0; i < 2; i++) { + /* Load the low 8 bit address */ + outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD); + apci3501_eeprom_wait(iobase); + outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); + apci3501_eeprom_wait(iobase); + + /* Load the high 8 bit address */ + outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD); + apci3501_eeprom_wait(iobase); + outb(((addr + i) >> 8) & 0xff, + iobase + AMCC_OP_REG_MCSR_NVDATA); + apci3501_eeprom_wait(iobase); + + /* Read the eeprom data byte */ + outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); + apci3501_eeprom_wait(iobase); + tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); + apci3501_eeprom_wait(iobase); + + if (i == 0) + val |= tmp; + else + val |= (tmp << 8); + } + + return val; +} + +static int apci3501_eeprom_get_ao_n_chan(struct comedi_device *dev) +{ + struct apci3501_private *devpriv = dev->private; + unsigned long iobase = devpriv->i_IobaseAmcc; + unsigned char nfuncs; + int i; + + nfuncs = apci3501_eeprom_readw(iobase, 10) & 0xff; + + /* Read functionality details */ + for (i = 0; i < nfuncs; i++) { + unsigned short offset = i * 4; + unsigned short addr; + unsigned char func; + unsigned short val; + + func = apci3501_eeprom_readw(iobase, 12 + offset) & 0x3f; + addr = apci3501_eeprom_readw(iobase, 14 + offset); + + if (func == EEPROM_ANALOGOUTPUT) { + val = apci3501_eeprom_readw(iobase, addr + 10); + return (val >> 4) & 0x3ff; + } + } + return 0; +} + +static int apci3501_eeprom_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3501_private *devpriv = dev->private; + unsigned short addr = CR_CHAN(insn->chanspec); + + data[0] = apci3501_eeprom_readw(devpriv->i_IobaseAmcc, 2 * addr); + + return insn->n; +} + +static irqreturn_t apci3501_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct apci3501_private *devpriv = dev->private; + unsigned int ui_Timer_AOWatchdog; + unsigned long ul_Command1; + int i_temp; + + /* Disable Interrupt */ + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); + ul_Command1 = (ul_Command1 & 0xFFFFF9FDul); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + + ui_Timer_AOWatchdog = inl(dev->iobase + APCI3501_TIMER_IRQ_REG) & 0x1; + if ((!ui_Timer_AOWatchdog)) { + comedi_error(dev, "IRQ from unknown source"); + return IRQ_NONE; + } + + /* Enable Interrupt Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); + ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + i_temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + + return IRQ_HANDLED; +} + +static int apci3501_reset(struct comedi_device *dev) +{ + unsigned int val; + int chan; + int ret; + + /* Reset all digital outputs to "0" */ + outl(0x0, dev->iobase + APCI3501_DO_REG); + + /* Default all analog outputs to 0V (bipolar) */ + outl(APCI3501_AO_CTRL_BIPOLAR, + dev->iobase + APCI3501_AO_CTRL_STATUS_REG); + val = APCI3501_AO_DATA_BIPOLAR | APCI3501_AO_DATA_VAL(0); + + /* Set all analog output channels */ + for (chan = 0; chan < 8; chan++) { + ret = apci3501_wait_for_dac(dev); + if (ret) { + dev_warn(dev->class_dev, + "%s: DAC not-ready for channel %i\n", + __func__, chan); + } else { + outl(val | APCI3501_AO_DATA_CHAN(chan), + dev->iobase + APCI3501_AO_DATA_REG); + } + } + + return 0; +} + +static int apci3501_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct apci3501_private *devpriv; + struct comedi_subdevice *s; + int ao_n_chan; + int ret; + + dev->board_name = dev->driver->driver_name; + + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 1); + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + + ao_n_chan = apci3501_eeprom_get_ao_n_chan(dev); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, apci3501_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 5); + if (ret) + return ret; + + /* Initialize the analog output subdevice */ + s = &dev->subdevices[0]; + if (ao_n_chan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = ao_n_chan; + s->maxdata = 0x3fff; + s->range_table = &apci3501_ao_range; + s->insn_write = apci3501_ao_insn_write; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Initialize the digital input subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 2; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3501_di_insn_bits; + + /* Initialize the digital output subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3501_do_insn_bits; + + /* Initialize the timer/watchdog subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog; + s->insn_read = i_APCI3501_ReadTimerCounterWatchdog; + s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog; + + /* Initialize the eeprom subdevice */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_INTERNAL; + s->n_chan = 256; + s->maxdata = 0xffff; + s->insn_read = apci3501_eeprom_insn_read; + + apci3501_reset(dev); + return 0; +} + +static void apci3501_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (dev->iobase) + apci3501_reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + } +} static struct comedi_driver apci3501_driver = { .driver_name = "addi_apci_3501", .module = THIS_MODULE, - .auto_attach = addi_auto_attach, - .detach = i_ADDI_Detach, - .num_names = ARRAY_SIZE(apci3501_boardtypes), - .board_name = &apci3501_boardtypes[0].pc_DriverName, - .offset = sizeof(struct addi_board), + .auto_attach = apci3501_auto_attach, + .detach = apci3501_detach, }; static int apci3501_pci_probe(struct pci_dev *dev, @@ -57,19 +448,20 @@ static int apci3501_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3501_driver); } -static void apci3501_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} +static DEFINE_PCI_DEVICE_TABLE(apci3501_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3001) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci3501_pci_table); static struct pci_driver apci3501_pci_driver = { .name = "addi_apci_3501", .id_table = apci3501_pci_table, .probe = apci3501_pci_probe, - .remove = apci3501_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci3501_driver, apci3501_pci_driver); +MODULE_DESCRIPTION("ADDI-DATA APCI-3501 Analog output board"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index 1562347ed64b..09d4b21fce23 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -1,3 +1,5 @@ +#include <linux/pci.h> + #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" @@ -751,11 +753,6 @@ static int apci3xxx_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3xxx_driver); } -static void apci3xxx_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(apci3xxx_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3010) }, { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x300f) }, @@ -790,7 +787,7 @@ static struct pci_driver apci3xxx_pci_driver = { .name = "addi_apci_3xxx", .id_table = apci3xxx_pci_table, .probe = apci3xxx_pci_probe, - .remove = apci3xxx_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(apci3xxx_driver, apci3xxx_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c new file mode 100644 index 000000000000..375ab665e091 --- /dev/null +++ b/drivers/staging/comedi/drivers/addi_watchdog.c @@ -0,0 +1,172 @@ +/* + * COMEDI driver for the watchdog subdevice found on some addi-data boards + * Copyright (c) 2013 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on implementations in various addi-data COMEDI drivers. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "../comedidev.h" +#include "addi_watchdog.h" + +/* + * Register offsets/defines for the addi-data watchdog + */ +#define ADDI_WDOG_REG 0x00 +#define ADDI_WDOG_RELOAD_REG 0x04 +#define ADDI_WDOG_TIMEBASE 0x08 +#define ADDI_WDOG_CTRL_REG 0x0c +#define ADDI_WDOG_CTRL_ENABLE (1 << 0) +#define ADDI_WDOG_CTRL_SW_TRIG (1 << 9) +#define ADDI_WDOG_STATUS_REG 0x10 +#define ADDI_WDOG_STATUS_ENABLED (1 << 0) +#define ADDI_WDOG_STATUS_SW_TRIG (1 << 1) + +struct addi_watchdog_private { + unsigned long iobase; + unsigned int wdog_ctrl; +}; + +/* + * The watchdog subdevice is configured with two INSN_CONFIG instructions: + * + * Enable the watchdog and set the reload timeout: + * data[0] = INSN_CONFIG_ARM + * data[1] = timeout reload value + * + * Disable the watchdog: + * data[0] = INSN_CONFIG_DISARM + */ +static int addi_watchdog_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_watchdog_private *spriv = s->private; + unsigned int reload; + + switch (data[0]) { + case INSN_CONFIG_ARM: + spriv->wdog_ctrl = ADDI_WDOG_CTRL_ENABLE; + reload = data[1] & s->maxdata; + outl(reload, spriv->iobase + ADDI_WDOG_RELOAD_REG); + + /* Time base is 20ms, let the user know the timeout */ + dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n", + 20 * reload + 20); + break; + case INSN_CONFIG_DISARM: + spriv->wdog_ctrl = 0; + break; + default: + return -EINVAL; + } + + outl(spriv->wdog_ctrl, spriv->iobase + ADDI_WDOG_CTRL_REG); + + return insn->n; +} + +static int addi_watchdog_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_watchdog_private *spriv = s->private; + int i; + + for (i = 0; i < insn->n; i++) + data[i] = inl(spriv->iobase + ADDI_WDOG_STATUS_REG); + + return insn->n; +} + +static int addi_watchdog_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_watchdog_private *spriv = s->private; + int i; + + if (spriv->wdog_ctrl == 0) { + dev_warn(dev->class_dev, "watchdog is disabled\n"); + return -EINVAL; + } + + /* "ping" the watchdog */ + for (i = 0; i < insn->n; i++) { + outl(spriv->wdog_ctrl | ADDI_WDOG_CTRL_SW_TRIG, + spriv->iobase + ADDI_WDOG_CTRL_REG); + } + + return insn->n; +} + +void addi_watchdog_reset(unsigned long iobase) +{ + outl(0x0, iobase + ADDI_WDOG_CTRL_REG); + outl(0x0, iobase + ADDI_WDOG_RELOAD_REG); +} +EXPORT_SYMBOL_GPL(addi_watchdog_reset); + +int addi_watchdog_init(struct comedi_subdevice *s, unsigned long iobase) +{ + struct addi_watchdog_private *spriv; + + spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); + if (!spriv) + return -ENOMEM; + + spriv->iobase = iobase; + + s->private = spriv; + + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 1; + s->maxdata = 0xff; + s->insn_config = addi_watchdog_insn_config; + s->insn_read = addi_watchdog_insn_read; + s->insn_write = addi_watchdog_insn_write; + + return 0; +} +EXPORT_SYMBOL_GPL(addi_watchdog_init); + +void addi_watchdog_cleanup(struct comedi_subdevice *s) +{ + kfree(s->private); +} +EXPORT_SYMBOL_GPL(addi_watchdog_cleanup); + +static int __init addi_watchdog_module_init(void) +{ + return 0; +} +module_init(addi_watchdog_module_init); + +static void __exit addi_watchdog_module_exit(void) +{ +} +module_exit(addi_watchdog_module_exit); + +MODULE_DESCRIPTION("ADDI-DATA Watchdog subdevice"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_watchdog.h b/drivers/staging/comedi/drivers/addi_watchdog.h new file mode 100644 index 000000000000..f374a7bff44d --- /dev/null +++ b/drivers/staging/comedi/drivers/addi_watchdog.h @@ -0,0 +1,10 @@ +#ifndef _ADDI_WATCHDOG_H +#define _ADDI_WATCHDOG_H + +#include "../comedidev.h" + +void addi_watchdog_reset(unsigned long iobase); +int addi_watchdog_init(struct comedi_subdevice *, unsigned long iobase); +void addi_watchdog_cleanup(struct comedi_subdevice *s); + +#endif diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 9a56eed3910f..7b3e331616ed 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -42,6 +42,8 @@ References: - adl_pci9118.c */ +#include <linux/pci.h> + #include "../comedidev.h" /* @@ -270,11 +272,6 @@ static int adl_pci6208_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adl_pci6208_driver); } -static void adl_pci6208_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6208) }, { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6216) }, @@ -286,7 +283,7 @@ static struct pci_driver adl_pci6208_pci_driver = { .name = "adl_pci6208", .id_table = adl_pci6208_pci_table, .probe = adl_pci6208_pci_probe, - .remove = adl_pci6208_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver); diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index 772edc02f5ce..f27f48e6e702 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -38,12 +38,6 @@ Author: H Hartley Sweeten <hsweeten@visionengravers.com> Updated: Thu, 02 Aug 2012 14:27:46 -0700 Status: untested -This driver only attaches using the PCI PnP auto config support -in the comedi core. The module parameter 'comedi_autoconfig' -must be 1 (default) to enable this feature. The COMEDI_DEVCONFIG -ioctl, used by the comedi_config utility, is not supported by -this driver. - The PCI-7230, PCI-7432 and PCI-7433 boards also support external interrupt signals on digital input channels 0 and 1. The PCI-7233 has dual-interrupt sources for change-of-state (COS) on any 16 @@ -51,9 +45,11 @@ digital input channels of LSB and for COS on any 16 digital input lines of MSB. Interrupts are not currently supported by this driver. -Configuration Options: not applicable +Configuration Options: not applicable, uses comedi PCI auto config */ +#include <linux/pci.h> + #include "../comedidev.h" /* @@ -302,11 +298,6 @@ static int adl_pci7x3x_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adl_pci7x3x_driver); } -static void adl_pci7x3x_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) }, { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7233) }, @@ -322,7 +313,7 @@ static struct pci_driver adl_pci7x3x_pci_driver = { .name = "adl_pci7x3x", .id_table = adl_pci7x3x_pci_table, .probe = adl_pci7x3x_pci_probe, - .remove = adl_pci7x3x_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver); diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index 4dd9d707a79d..d06b83f38653 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -30,9 +30,11 @@ Updated: Mon, 14 Apr 2008 15:10:32 +0100 Configuration Options: not applicable, uses PCI auto config */ -#include "../comedidev.h" #include <linux/kernel.h> +#include <linux/pci.h> #include <linux/delay.h> + +#include "../comedidev.h" #include "comedi_fc.h" #include "8253.h" @@ -62,35 +64,35 @@ static void adl_pci8164_insn_read(struct comedi_device *dev, char *action, unsigned short offset) { int axis, axis_reg; - char *axisname; + char axisname; axis = CR_CHAN(insn->chanspec); switch (axis) { case 0: axis_reg = PCI8164_AXIS_X; - axisname = "X"; + axisname = 'X'; break; case 1: axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; + axisname = 'Y'; break; case 2: axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; + axisname = 'Z'; break; case 3: axis_reg = PCI8164_AXIS_U; - axisname = "U"; + axisname = 'U'; break; default: axis_reg = PCI8164_AXIS_X; - axisname = "X"; + axisname = 'X'; } data[0] = inw(dev->iobase + axis_reg + offset); dev_dbg(dev->class_dev, - "pci8164 %s read -> %04X:%04X on axis %s\n", + "pci8164 %s read -> %04X:%04X on axis %c\n", action, data[0], data[1], axisname); } @@ -142,36 +144,36 @@ static void adl_pci8164_insn_out(struct comedi_device *dev, { unsigned int axis, axis_reg; - char *axisname; + char axisname; axis = CR_CHAN(insn->chanspec); switch (axis) { case 0: axis_reg = PCI8164_AXIS_X; - axisname = "X"; + axisname = 'X'; break; case 1: axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; + axisname = 'Y'; break; case 2: axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; + axisname = 'Z'; break; case 3: axis_reg = PCI8164_AXIS_U; - axisname = "U"; + axisname = 'U'; break; default: axis_reg = PCI8164_AXIS_X; - axisname = "X"; + axisname = 'X'; } outw(data[0], dev->iobase + axis_reg + offset); dev_dbg(dev->class_dev, - "pci8164 %s write -> %04X:%04X on axis %s\n", + "pci8164 %s write -> %04X:%04X on axis %c\n", action, data[0], data[1], axisname); } @@ -298,11 +300,6 @@ static int adl_pci8164_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adl_pci8164_driver); } -static void adl_pci8164_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) }, {0} @@ -313,7 +310,7 @@ static struct pci_driver adl_pci8164_pci_driver = { .name = "adl_pci8164", .id_table = adl_pci8164_pci_table, .probe = adl_pci8164_pci_probe, - .remove = adl_pci8164_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver); diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index a339b9dd27cf..eeb10ec7f178 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -68,11 +68,12 @@ TODO: */ -#include "../comedidev.h" - +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include "../comedidev.h" + #include "8253.h" #include "comedi_fc.h" @@ -963,11 +964,6 @@ static int pci9111_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adl_pci9111_driver); } -static void pci9111_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ @@ -979,7 +975,7 @@ static struct pci_driver adl_pci9111_pci_driver = { .name = "adl_pci9111", .id_table = pci9111_pci_table, .probe = pci9111_pci_probe, - .remove = pci9111_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver); diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index b6dda809bd13..4dbac7459a48 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -76,13 +76,15 @@ Configuration options: * attachment if necessary, and possibly to set other options supported by * manual attachment. */ -#include "../comedidev.h" +#include <linux/pci.h> #include <linux/delay.h> #include <linux/gfp.h> #include <linux/interrupt.h> #include <linux/io.h> +#include "../comedidev.h" + #include "amcc_s5933.h" #include "8253.h" #include "comedi_fc.h" @@ -808,7 +810,7 @@ static void pci9118_calc_divisors(char mode, struct comedi_device *dev, *tim2 = *div1 * devpriv->i8254_osc_base; /* real convert timer */ - if (usessh & (chnsshfront == 0)) /* use BSSH signal */ + if (usessh && (chnsshfront == 0)) /* use BSSH signal */ if (*div2 < (chans + 2)) *div2 = chans + 2; @@ -2225,11 +2227,6 @@ static int adl_pci9118_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adl_pci9118_driver); } -static void adl_pci9118_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) }, { 0 } @@ -2240,7 +2237,7 @@ static struct pci_driver adl_pci9118_pci_driver = { .name = "adl_pci9118", .id_table = adl_pci9118_pci_table, .probe = adl_pci9118_pci_probe, - .remove = adl_pci9118_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adl_pci9118_driver, adl_pci9118_pci_driver); diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index a6fd8c2c16ca..3d788c76d648 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -41,6 +41,7 @@ Configuration options: device will be used. */ +#include <linux/pci.h> #include <linux/interrupt.h> #include "../comedidev.h" @@ -1402,11 +1403,6 @@ static int adv_pci1710_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adv_pci1710_driver); } -static void adv_pci1710_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) }, { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) }, @@ -1421,7 +1417,7 @@ static struct pci_driver adv_pci1710_pci_driver = { .name = "adv_pci1710", .id_table = adv_pci1710_pci_table, .probe = adv_pci1710_pci_probe, - .remove = adv_pci1710_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver); diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 5af73146dd85..02ce55a01d2a 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -48,6 +48,8 @@ TODO: 3. Implement calibration. */ +#include <linux/pci.h> + #include "../comedidev.h" /* all the registers for the pci1723 board */ @@ -327,11 +329,6 @@ static int adv_pci1723_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adv_pci1723_driver); } -static void adv_pci1723_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) }, { 0 } @@ -342,7 +339,7 @@ static struct pci_driver adv_pci1723_pci_driver = { .name = "adv_pci1723", .id_table = adv_pci1723_pci_table, .probe = adv_pci1723_pci_probe, - .remove = adv_pci1723_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver); diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index 05a663e970c6..338c43e716ba 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -29,10 +29,11 @@ Configuration options: */ -#include "../comedidev.h" - +#include <linux/pci.h> #include <linux/delay.h> +#include "../comedidev.h" + #include "8255.h" #include "8253.h" @@ -1206,11 +1207,6 @@ static int adv_pci_dio_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adv_pci_dio_driver); } -static void adv_pci_dio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) }, { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) }, @@ -1234,7 +1230,7 @@ static struct pci_driver adv_pci_dio_pci_driver = { .name = "adv_pci_dio", .id_table = adv_pci_dio_pci_table, .probe = adv_pci_dio_pci_probe, - .remove = adv_pci_dio_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver); diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 5f309ba88a1a..7c53dea12c76 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -258,6 +258,7 @@ * order they appear in the channel list. */ +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -1104,10 +1105,9 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s, struct dio200_subdev_intr *subpriv; subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); - if (!subpriv) { - dev_err(dev->class_dev, "error! out of memory!\n"); + if (!subpriv) return -ENOMEM; - } + subpriv->ofs = offset; subpriv->valid_isns = valid_isns; spin_lock_init(&subpriv->spinlock); @@ -1443,10 +1443,8 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int chan; subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); - if (!subpriv) { - dev_err(dev->class_dev, "error! out of memory!\n"); + if (!subpriv) return -ENOMEM; - } s->private = subpriv; s->type = COMEDI_SUBD_COUNTER; @@ -1977,8 +1975,7 @@ static int dio200_auto_attach(struct comedi_device *dev, devpriv->io.u.iobase = (unsigned long)base; devpriv->io.regtype = io_regtype; } - switch (thisboard->model) - { + switch (thisboard->model) { case pcie215_model: case pcie236_model: case pcie296_model: @@ -2079,16 +2076,11 @@ static int amplc_dio200_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &lc_dio200_driver); } -static void amplc_dio200_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver amplc_dio200_pci_driver = { .name = DIO200_DRIVER_NAME, .id_table = dio200_pci_table, .probe = &lc_dio200_pci_probe, - .remove = &lc_dio200_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(amplc_dio200_driver, amplc_dio200_pci_driver); #else diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 289835419577..479e10fddd22 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -52,6 +52,7 @@ the IRQ jumper. If no interrupt is connected, then subdevice 1 is unused. */ +#include <linux/pci.h> #include <linux/interrupt.h> #include "../comedidev.h" @@ -614,16 +615,11 @@ static int amplc_pc236_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &lc_pc236_driver); } -static void amplc_pc236_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver amplc_pc236_pci_driver = { .name = PC236_DRIVER_NAME, .id_table = pc236_pci_table, .probe = &lc_pc236_pci_probe, - .remove = &lc_pc236_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(amplc_pc236_driver, amplc_pc236_pci_driver); diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index dfbff77cd795..11c1f4764eac 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -44,6 +44,8 @@ connected to a reed-relay. Relay contacts are closed when output is 1. The state of the outputs can be read. */ +#include <linux/pci.h> + #include "../comedidev.h" #define PC263_DRIVER_NAME "amplc_pc263" @@ -372,16 +374,11 @@ static int amplc_pc263_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &lc_pc263_driver); } -static void amplc_pc263_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver amplc_pc263_pci_driver = { .name = PC263_DRIVER_NAME, .id_table = pc263_pci_table, .probe = &lc_pc263_pci_probe, - .remove = &lc_pc263_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(amplc_pc263_driver, amplc_pc263_pci_driver); #else diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 6e2566a2dd57..c9da4cd74baa 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -103,6 +103,7 @@ Caveats: correctly. */ +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -1512,11 +1513,6 @@ static int amplc_pci224_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &lc_pci224_driver); } -static void amplc_pci224_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) }, { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) }, @@ -1528,7 +1524,7 @@ static struct pci_driver amplc_pci224_pci_driver = { .name = "amplc_pci224", .id_table = amplc_pci224_pci_table, .probe = amplc_pci224_pci_probe, - .remove = amplc_pci224_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver); diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 366c68be56bd..e2244c6e536b 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -188,11 +188,12 @@ Support for PCI230+/260+, more triggered scan functionality, and workarounds for (or detection of) various hardware problems added by Ian Abbott. */ -#include "../comedidev.h" - +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include "../comedidev.h" + #include "comedi_fc.h" #include "8253.h" #include "8255.h" @@ -2863,11 +2864,6 @@ static int amplc_pci230_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &lc_pci230_driver); } -static void amplc_pci230_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) }, { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) }, @@ -2879,7 +2875,7 @@ static struct pci_driver amplc_pci230_pci_driver = { .name = "amplc_pci230", .id_table = amplc_pci230_pci_table, .probe = amplc_pci230_pci_probe, - .remove = amplc_pci230_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver); diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 93731de1f2b1..f874fff44523 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -40,9 +40,10 @@ Status: experimental #include <linux/interrupt.h> #include <linux/slab.h> -#include "../comedidev.h" #include <linux/delay.h> +#include "../comedidev.h" + #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -89,8 +90,6 @@ struct das16cs_private { unsigned short status2; }; -static struct pcmcia_device *cur_dev; - static const struct comedi_lrange das16cs_ai_range = { 4, { BIP_RANGE(10), @@ -383,46 +382,45 @@ static int das16cs_dio_insn_config(struct comedi_device *dev, return insn->n; } -static const struct das16cs_board *das16cs_probe(struct comedi_device *dev, - struct pcmcia_device *link) +static const void *das16cs_find_boardinfo(struct comedi_device *dev, + struct pcmcia_device *link) { + const struct das16cs_board *board; int i; for (i = 0; i < ARRAY_SIZE(das16cs_boards); i++) { - if (das16cs_boards[i].device_id == link->card_id) - return das16cs_boards + i; + board = &das16cs_boards[i]; + if (board->device_id == link->card_id) + return board; } - dev_dbg(dev->class_dev, "unknown board!\n"); - return NULL; } -static int das16cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int das16cs_auto_attach(struct comedi_device *dev, + unsigned long context) { - const struct das16cs_board *thisboard; + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + const struct das16cs_board *board; struct das16cs_private *devpriv; - struct pcmcia_device *link; struct comedi_subdevice *s; int ret; - link = cur_dev; /* XXX hack */ - if (!link) - return -EIO; - - dev->board_ptr = das16cs_probe(dev, link); - if (!dev->board_ptr) - return -EIO; - thisboard = comedi_board(dev); - - dev->board_name = thisboard->name; + board = das16cs_find_boardinfo(dev, link); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; dev->iobase = link->resource[0]->start; - ret = request_irq(link->irq, das16cs_interrupt, - IRQF_SHARED, "cb_das16_cs", dev); - if (ret < 0) + link->priv = dev; + ret = pcmcia_request_irq(link, das16cs_interrupt); + if (ret) return ret; dev->irq = link->irq; @@ -450,10 +448,10 @@ static int das16cs_attach(struct comedi_device *dev, s = &dev->subdevices[1]; /* analog output subdevice */ - if (thisboard->n_ao_chans) { + if (board->n_ao_chans) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->n_ao_chans; + s->n_chan = board->n_ao_chans; s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = &das16cs_ao_winsn; @@ -479,58 +477,16 @@ static int das16cs_attach(struct comedi_device *dev, return 0; } -static void das16cs_detach(struct comedi_device *dev) -{ - if (dev->irq) - free_irq(dev->irq, dev); -} - static struct comedi_driver driver_das16cs = { .driver_name = "cb_das16_cs", .module = THIS_MODULE, - .attach = das16cs_attach, - .detach = das16cs_detach, + .auto_attach = das16cs_auto_attach, + .detach = comedi_pcmcia_disable, }; -static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - static int das16cs_pcmcia_attach(struct pcmcia_device *link) { - int ret; - - /* Do we need to allocate an interrupt? */ - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - cur_dev = link; - return 0; - -failed: - pcmcia_disable_device(link); - return ret; -} - -static void das16cs_pcmcia_detach(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); - cur_dev = NULL; + return comedi_pcmcia_auto_config(link, &driver_das16cs); } static const struct pcmcia_device_id das16cs_id_table[] = { @@ -543,35 +499,11 @@ MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table); static struct pcmcia_driver das16cs_driver = { .name = "cb_das16_cs", .owner = THIS_MODULE, - .probe = das16cs_pcmcia_attach, - .remove = das16cs_pcmcia_detach, .id_table = das16cs_id_table, + .probe = das16cs_pcmcia_attach, + .remove = comedi_pcmcia_auto_unconfig, }; - -static int __init das16cs_init(void) -{ - int ret; - - ret = comedi_driver_register(&driver_das16cs); - if (ret < 0) - return ret; - - ret = pcmcia_register_driver(&das16cs_driver); - if (ret < 0) { - comedi_driver_unregister(&driver_das16cs); - return ret; - } - - return 0; -} -module_init(das16cs_init); - -static void __exit das16cs_exit(void) -{ - pcmcia_unregister_driver(&das16cs_driver); - comedi_driver_unregister(&driver_das16cs); -} -module_exit(das16cs_exit); +module_comedi_pcmcia_driver(driver_das16cs, das16cs_driver); MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16"); diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index aed68639cc9a..79c72118a090 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -67,10 +67,12 @@ TODO: analog triggering on 1602 series */ -#include "../comedidev.h" +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include "../comedidev.h" + #include "8253.h" #include "8255.h" #include "amcc_s5933.h" @@ -1632,11 +1634,6 @@ static int cb_pcidas_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &cb_pcidas_driver); } -static void cb_pcidas_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) }, { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) }, @@ -1654,7 +1651,7 @@ static struct pci_driver cb_pcidas_pci_driver = { .name = "cb_pcidas", .id_table = cb_pcidas_pci_table, .probe = cb_pcidas_pci_probe, - .remove = cb_pcidas_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver); diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index d72b46cc06bc..9f3112cb7a21 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -87,10 +87,12 @@ TODO: #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "../comedidev.h" +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include "../comedidev.h" + #include "8253.h" #include "8255.h" #include "plx9080.h" @@ -3299,7 +3301,6 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) num_bytes = load_ao_dma_buffer(dev, cmd); if (num_bytes == 0) return -1; - if (num_bytes >= DMA_BUFFER_SIZE) ; load_ao_dma(dev, cmd); dma_start_sync(dev, 0); @@ -4220,11 +4221,6 @@ static int cb_pcidas64_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &cb_pcidas64_driver); } -static void cb_pcidas64_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001d) }, { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001e) }, @@ -4253,7 +4249,7 @@ static struct pci_driver cb_pcidas64_pci_driver = { .name = "cb_pcidas64", .id_table = cb_pcidas64_pci_table, .probe = cb_pcidas64_pci_probe, - .remove = cb_pcidas64_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver); diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 7c6029a8c3e1..e2cadc728455 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -41,6 +41,8 @@ * Only simple analog output writing is supported. */ +#include <linux/pci.h> + #include "../comedidev.h" #include "comedi_fc.h" @@ -438,11 +440,6 @@ static int cb_pcidda_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &cb_pcidda_driver); } -static void cb_pcidda_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA02_12) }, { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA04_12) }, @@ -458,7 +455,7 @@ static struct pci_driver cb_pcidda_pci_driver = { .name = "cb_pcidda", .id_table = cb_pcidda_pci_table, .probe = cb_pcidda_pci_probe, - .remove = cb_pcidda_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver); diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index b43a5f80ac26..aae063ca85a0 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -40,11 +40,12 @@ No interrupts, multi channel or FIFO AI, although the card looks like it could s See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. */ -#include "../comedidev.h" - +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include "../comedidev.h" + #include "plx9052.h" #include "8255.h" @@ -299,11 +300,6 @@ static int cb_pcimdas_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &cb_pcimdas_driver); } -static void cb_pcimdas_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) }, { 0 } @@ -314,7 +310,7 @@ static struct pci_driver cb_pcimdas_pci_driver = { .name = "cb_pcimdas", .id_table = cb_pcimdas_pci_table, .probe = cb_pcimdas_pci_probe, - .remove = cb_pcimdas_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver); diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 699b84f54cc7..63cfbaf3a3fe 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -79,6 +79,8 @@ Configuration Options: not applicable, uses PCI auto config -Calin Culianu <calin@ajvar.org> */ +#include <linux/pci.h> + #include "../comedidev.h" #include "8255.h" @@ -222,11 +224,6 @@ static int cb_pcimdda_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &cb_pcimdda_driver); } -static void cb_pcimdda_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_ID_PCIM_DDA06_16) }, { 0 } @@ -237,7 +234,7 @@ static struct pci_driver cb_pcimdda_driver_pci_driver = { .name = "cb_pcimdda", .id_table = cb_pcimdda_pci_table, .probe = cb_pcimdda_pci_probe, - .remove = cb_pcimdda_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver); diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 31515999bb97..1bb53816eca3 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -245,10 +245,9 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } bdev = kmalloc(sizeof(*bdev), GFP_KERNEL); - if (!bdev) { - dev_err(dev->class_dev, "Out of memory\n"); + if (!bdev) return 0; - } + bdev->dev = d; bdev->minor = minor; bdev->subdev = sdev; diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index 01de996239f1..270fea5c6b51 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -62,15 +62,14 @@ zero volts). /* Data unique to this driver */ struct waveform_private { struct timer_list timer; - struct timeval last; /* time at which last timer interrupt occurred */ + struct timeval last; /* time last timer interrupt occurred */ unsigned int uvolt_amplitude; /* waveform amplitude in microvolts */ unsigned long usec_period; /* waveform period in microseconds */ - unsigned long usec_current; /* current time (modulo waveform period) */ - unsigned long usec_remainder; /* usec since last scan; */ - unsigned long ai_count; /* number of conversions remaining */ + unsigned long usec_current; /* current time (mod waveform period) */ + unsigned long usec_remainder; /* usec since last scan */ + unsigned long ai_count; /* number of conversions remaining */ unsigned int scan_period; /* scan period in usec */ unsigned int convert_period; /* conversion period in usec */ - unsigned timer_running:1; unsigned int ao_loopbacks[N_CHANS]; }; @@ -86,8 +85,9 @@ static const struct comedi_lrange waveform_ai_ranges = { } }; -static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) +static unsigned short fake_sawtooth(struct comedi_device *dev, + unsigned int range_index, + unsigned long current_time) { struct waveform_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -110,9 +110,9 @@ static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index, return offset + value; } -static short fake_squarewave(struct comedi_device *dev, - unsigned int range_index, - unsigned long current_time) +static unsigned short fake_squarewave(struct comedi_device *dev, + unsigned int range_index, + unsigned long current_time) { struct waveform_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -132,15 +132,17 @@ static short fake_squarewave(struct comedi_device *dev, return offset + value; } -static short fake_flatline(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) +static unsigned short fake_flatline(struct comedi_device *dev, + unsigned int range_index, + unsigned long current_time) { return dev->read_subdev->maxdata / 2; } /* generates a different waveform depending on what channel is read */ -static short fake_waveform(struct comedi_device *dev, unsigned int channel, - unsigned int range, unsigned long current_time) +static unsigned short fake_waveform(struct comedi_device *dev, + unsigned int channel, unsigned int range, + unsigned long current_time) { enum { SAWTOOTH_CHAN, @@ -176,6 +178,7 @@ static void waveform_ai_interrupt(unsigned long arg) unsigned long elapsed_time; unsigned int num_scans; struct timeval now; + bool stopping = false; do_gettimeofday(&now); @@ -189,37 +192,35 @@ static void waveform_ai_interrupt(unsigned long arg) (devpriv->usec_remainder + elapsed_time) % devpriv->scan_period; async->events = 0; + if (cmd->stop_src == TRIG_COUNT) { + unsigned int remaining = cmd->stop_arg - devpriv->ai_count; + if (num_scans >= remaining) { + /* about to finish */ + num_scans = remaining; + stopping = true; + } + } + for (i = 0; i < num_scans; i++) { for (j = 0; j < cmd->chanlist_len; j++) { - cfc_write_to_buffer(dev->read_subdev, - fake_waveform(dev, - CR_CHAN(cmd-> - chanlist[j]), - CR_RANGE(cmd-> - chanlist[j]), - devpriv-> - usec_current + - i * - devpriv->scan_period + - j * - devpriv-> - convert_period)); - } - devpriv->ai_count++; - if (cmd->stop_src == TRIG_COUNT - && devpriv->ai_count >= cmd->stop_arg) { - async->events |= COMEDI_CB_EOA; - break; + unsigned short sample; + sample = fake_waveform(dev, CR_CHAN(cmd->chanlist[j]), + CR_RANGE(cmd->chanlist[j]), + devpriv->usec_current + + i * devpriv->scan_period + + j * devpriv->convert_period); + cfc_write_to_buffer(dev->read_subdev, sample); } } + devpriv->ai_count += i; devpriv->usec_current += elapsed_time; devpriv->usec_current %= devpriv->usec_period; - if ((async->events & COMEDI_CB_EOA) == 0 && devpriv->timer_running) - mod_timer(&devpriv->timer, jiffies + 1); + if (stopping) + async->events |= COMEDI_CB_EOA; else - del_timer(&devpriv->timer); + mod_timer(&devpriv->timer, jiffies + 1); comedi_event(dev, dev->read_subdev); } @@ -317,7 +318,6 @@ static int waveform_ai_cmd(struct comedi_device *dev, return -1; } - devpriv->timer_running = 1; devpriv->ai_count = 0; devpriv->scan_period = cmd->scan_begin_arg / nano_per_micro; @@ -344,7 +344,6 @@ static int waveform_ai_cancel(struct comedi_device *dev, { struct waveform_private *devpriv = dev->private; - devpriv->timer_running = 0; del_timer_sync(&devpriv->timer); return 0; } diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 1a18fa37bfd0..182dea669ef2 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -30,6 +30,8 @@ Status: works Configuration Options: not applicable, uses comedi PCI auto config */ +#include <linux/pci.h> + #include "../comedidev.h" #define PCI_DEVICE_ID_PIO1616L 0x8172 @@ -130,11 +132,6 @@ static int contec_pci_dio_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &contec_pci_dio_driver); } -static void contec_pci_dio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) }, { 0 } @@ -145,7 +142,7 @@ static struct pci_driver contec_pci_dio_pci_driver = { .name = "contec_pci_dio", .id_table = contec_pci_dio_pci_table, .probe = contec_pci_dio_pci_probe, - .remove = contec_pci_dio_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver); diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 992e557e6ae1..50b450f09c65 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -107,12 +107,13 @@ Configuration options: not applicable, uses PCI auto config */ -#include "../comedidev.h" - +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/firmware.h> +#include "../comedidev.h" + #include "8255.h" #define DAQBOARD2000_FIRMWARE "daqboard2000_firmware.bin" @@ -485,7 +486,7 @@ static void daqboard2000_pulseProgPin(struct comedi_device *dev) writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c); udelay(10000); writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c); - udelay(10000); /* Not in the original code, but I like symmetry... */ + udelay(10000); /* Not in the original code, but I like symmetry... */ } static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) @@ -799,11 +800,6 @@ static int daqboard2000_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &daqboard2000_driver); } -static void daqboard2000_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_IOTECH, 0x0409) }, { 0 } @@ -814,7 +810,7 @@ static struct pci_driver daqboard2000_pci_driver = { .name = "daqboard2000", .id_table = daqboard2000_pci_table, .probe = daqboard2000_pci_probe, - .remove = daqboard2000_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver); diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index b15e05808cb0..9823aa06787a 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -1,6 +1,6 @@ /* * comedi/drivers/das08.c - * DAS08 driver + * comedi driver for common DAS08 support (used by ISA/PCI/PCMCIA drivers) * * COMEDI - Linux Control and Measurement Device Interface * Copyright (C) 2000 David A. Schleef <ds@schleef.org> @@ -27,57 +27,26 @@ /* * Driver: das08 * Description: DAS-08 compatible boards + * Devices: various, see das08_isa, das08_cs, and das08_pci drivers * Author: Warren Jasper, ds, Frank Hess - * Devices: [Keithley Metrabyte] DAS08 (isa-das08), - * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm), - * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh), - * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao), - * DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (pci-das08), - * PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16) * Updated: Fri, 31 Aug 2012 19:19:06 +0100 * Status: works * - * This is a rewrite of the das08 and das08jr drivers. + * This driver is used by the das08_isa, das08_cs, and das08_pci + * drivers to provide the common support for the DAS-08 hardware. * - * Options (for ISA cards): - * [0] - base io address - * - * Manual configuration of PCI cards is not supported; they are - * configured automatically. - * - * The das08 driver doesn't support asynchronous commands, since - * the cheap das08 hardware doesn't really support them. The - * comedi_rt_timer driver can be used to emulate commands for this - * driver. + * The driver doesn't support asynchronous commands, since the + * cheap das08 hardware doesn't really support them. */ -#include "../comedidev.h" - #include <linux/delay.h> +#include "../comedidev.h" + #include "8255.h" #include "8253.h" #include "das08.h" -#define DRV_NAME "das08" - -#define DO_ISA IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) -#define DO_PCI IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) -#define DO_COMEDI_DRIVER_REGISTER (DO_ISA || DO_PCI) - -#define PCI_DEVICE_ID_PCIDAS08 0x29 -#define PCIDAS08_SIZE 0x54 - -/* pci configuration registers */ -#define INTCSR 0x4c -#define INTR1_ENABLE 0x1 -#define INTR1_HIGH_POLARITY 0x2 -#define PCI_INTR_ENABLE 0x40 -#define INTR1_EDGE_TRIG 0x100 /* requires high polarity */ -#define CNTRL 0x50 -#define CNTRL_DIR 0x2 -#define CNTRL_INTR 0x4 - /* cio-das08.pdf @@ -235,16 +204,6 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; -static inline bool is_isa_board(const struct das08_board_struct *board) -{ - return DO_ISA && board->bustype == isa; -} - -static inline bool is_pci_board(const struct das08_board_struct *board) -{ - return DO_PCI && board->bustype == pci; -} - #define TIMEOUT 100000 static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -501,159 +460,6 @@ static int das08_counter_config(struct comedi_device *dev, return 2; } -#if DO_COMEDI_DRIVER_REGISTER -static const struct das08_board_struct das08_boards[] = { -#if DO_ISA - { - .name = "isa-das08", /* cio-das08.pdf */ - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode12, - .di_nchan = 3, - .do_nchan = 4, - .i8255_offset = 8, - .i8254_offset = 4, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-pgm", /* cio-das08pgx.pdf */ - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pgm, - .ai_encoding = das08_encode12, - .di_nchan = 3, - .do_nchan = 4, - .i8255_offset = 0, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-pgh", /* cio-das08pgx.pdf */ - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pgh, - .ai_encoding = das08_encode12, - .di_nchan = 3, - .do_nchan = 4, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-pgl", /* cio-das08pgx.pdf */ - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pgl, - .ai_encoding = das08_encode12, - .di_nchan = 3, - .do_nchan = 4, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-aoh", /* cio-das08_aox.pdf */ - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pgh, - .ai_encoding = das08_encode12, - .ao_nbits = 12, - .di_nchan = 3, - .do_nchan = 4, - .i8255_offset = 0x0c, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-aol", /* cio-das08_aox.pdf */ - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pgl, - .ai_encoding = das08_encode12, - .ao_nbits = 12, - .di_nchan = 3, - .do_nchan = 4, - .i8255_offset = 0x0c, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-aom", /* cio-das08_aox.pdf */ - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pgm, - .ai_encoding = das08_encode12, - .ao_nbits = 12, - .di_nchan = 3, - .do_nchan = 4, - .i8255_offset = 0x0c, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08/jr-ao", /* cio-das08-jr-ao.pdf */ - .bustype = isa, - .is_jr = true, - .ai_nbits = 12, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode12, - .ao_nbits = 12, - .di_nchan = 8, - .do_nchan = 8, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08jr-16-ao", /* cio-das08jr-16-ao.pdf */ - .bustype = isa, - .is_jr = true, - .ai_nbits = 16, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode16, - .ao_nbits = 16, - .di_nchan = 8, - .do_nchan = 8, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "pc104-das08", - .bustype = isa, - .ai_nbits = 12, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode12, - .di_nchan = 3, - .do_nchan = 4, - .i8254_offset = 4, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08jr/16", - .bustype = isa, - .is_jr = true, - .ai_nbits = 16, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode16, - .di_nchan = 8, - .do_nchan = 8, - .iosize = 16, /* unchecked */ - }, -#endif /* DO_ISA */ -#if DO_PCI - { - .name = "pci-das08", /* pci-das08 */ - .id = PCI_DEVICE_ID_PCIDAS08, - .bustype = pci, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_encode12, - .di_nchan = 3, - .do_nchan = 4, - .i8254_offset = 4, - .iosize = 8, - }, -#endif /* DO_PCI */ -}; -#endif /* DO_COMEDI_DRIVER_REGISTER */ - int das08_common_attach(struct comedi_device *dev, unsigned long iobase) { const struct das08_board_struct *thisboard = comedi_board(dev); @@ -760,84 +566,6 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) } EXPORT_SYMBOL_GPL(das08_common_attach); -static const struct das08_board_struct * -das08_find_pci_board(struct pci_dev *pdev) -{ -#if DO_COMEDI_DRIVER_REGISTER - unsigned int i; - for (i = 0; i < ARRAY_SIZE(das08_boards); i++) - if (is_pci_board(&das08_boards[i]) && - pdev->device == das08_boards[i].id) - return &das08_boards[i]; -#endif - return NULL; -} - -/* only called in the PCI probe path, via comedi_pci_auto_config() */ -static int __maybe_unused -das08_auto_attach(struct comedi_device *dev, unsigned long context_unused) -{ - struct pci_dev *pdev; - struct das08_private_struct *devpriv; - unsigned long iobase; - - if (!DO_PCI) - return -EINVAL; - - pdev = comedi_to_pci_dev(dev); - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - dev_info(dev->class_dev, "attach pci %s\n", pci_name(pdev)); - dev->board_ptr = das08_find_pci_board(pdev); - if (dev->board_ptr == NULL) { - dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); - return -EINVAL; - } - - /* enable PCI device and reserve I/O spaces */ - if (comedi_pci_enable(pdev, dev->driver->driver_name)) { - dev_err(dev->class_dev, - "Error enabling PCI device and requesting regions\n"); - return -EIO; - } - /* read base addresses */ - iobase = pci_resource_start(pdev, 2); - return das08_common_attach(dev, iobase); -} - -static int __maybe_unused -das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct das08_board_struct *thisboard = comedi_board(dev); - struct das08_private_struct *devpriv; - unsigned long iobase; - - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - dev_info(dev->class_dev, "attach\n"); - if (is_pci_board(thisboard)) { - dev_err(dev->class_dev, - "Manual configuration of PCI board '%s' is not supported\n", - thisboard->name); - return -EIO; - } else if (is_isa_board(thisboard)) { - iobase = it->options[0]; - dev_info(dev->class_dev, "iobase 0x%lx\n", iobase); - if (!request_region(iobase, thisboard->iosize, DRV_NAME)) { - dev_err(dev->class_dev, "I/O port conflict\n"); - return -EIO; - } - return das08_common_attach(dev, iobase); - } else - return -EIO; -} - void das08_common_detach(struct comedi_device *dev) { if (dev->subdevices) @@ -845,84 +573,16 @@ void das08_common_detach(struct comedi_device *dev) } EXPORT_SYMBOL_GPL(das08_common_detach); -static void __maybe_unused das08_detach(struct comedi_device *dev) -{ - const struct das08_board_struct *thisboard = comedi_board(dev); - - if (!thisboard) - return; - das08_common_detach(dev); - if (is_isa_board(thisboard)) { - if (dev->iobase) - release_region(dev->iobase, thisboard->iosize); - } else if (is_pci_board(thisboard)) { - struct pci_dev *pdev = comedi_to_pci_dev(dev); - if (pdev) { - if (dev->iobase) - comedi_pci_disable(pdev); - } - } -} - -#if DO_COMEDI_DRIVER_REGISTER -static struct comedi_driver das08_driver = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = das08_attach, - .auto_attach = das08_auto_attach, - .detach = das08_detach, - .board_name = &das08_boards[0].name, - .num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct), - .offset = sizeof(struct das08_board_struct), -}; -#endif - -#if DO_PCI -static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_PCIDAS08) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, das08_pci_table); - -static int das08_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, &das08_driver); -} - -static void das08_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver das08_pci_driver = { - .id_table = das08_pci_table, - .name = DRV_NAME, - .probe = &das08_pci_probe, - .remove = &das08_pci_remove -}; -#endif /* DO_PCI */ - -#if DO_COMEDI_DRIVER_REGISTER -#if DO_PCI -module_comedi_pci_driver(das08_driver, das08_pci_driver); -#else -module_comedi_driver(das08_driver); -#endif -#else /* DO_COMEDI_DRIVER_REGISTER */ static int __init das08_init(void) { return 0; } +module_init(das08_init); static void __exit das08_exit(void) { } - -module_init(das08_init); module_exit(das08_exit); -#endif /* DO_COMEDI_DRIVER_REGISTER */ MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index 0314baebae39..b102ad4918c4 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -24,7 +24,6 @@ #ifndef _DAS08_H #define _DAS08_H -enum das08_bustype { isa, pci, pcmcia }; /* different ways ai data is encoded in first two registers */ enum das08_ai_encoding { das08_encode12, das08_encode16, das08_pcm_encode12 }; enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl, @@ -34,7 +33,6 @@ enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl, struct das08_board_struct { const char *name; unsigned int id; /* id for pci/pcmcia boards */ - enum das08_bustype bustype; bool is_jr; /* true for 'JR' boards */ unsigned int ai_nbits; enum das08_lrange ai_pg; diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 024262375e3c..cfeebe4d1ddd 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -46,125 +46,70 @@ Options (for pcm-das08): Command support does not exist, but could be added for this board. */ -#include "../comedidev.h" - #include <linux/delay.h> -#include <linux/pci.h> #include <linux/slab.h> -#include "das08.h" +#include "../comedidev.h" -/* pcmcia includes */ #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> +#include "das08.h" + static const struct das08_board_struct das08_cs_boards[] = { { - .name = "pcm-das08", - .id = 0x0, /* XXX */ - .bustype = pcmcia, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_pcm_encode12, - .di_nchan = 3, - .do_nchan = 3, - .iosize = 16, - }, - /* duplicate so driver name can be used also */ - { - .name = "das08_cs", - .id = 0x0, /* XXX */ - .bustype = pcmcia, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_pcm_encode12, - .di_nchan = 3, - .do_nchan = 3, - .iosize = 16, + .name = "pcm-das08", + .id = 0x0, /* XXX */ + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_pcm_encode12, + .di_nchan = 3, + .do_nchan = 3, + .iosize = 16, }, }; -static struct pcmcia_device *cur_dev; - -static int das08_cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int das08_cs_auto_attach(struct comedi_device *dev, + unsigned long context) { - const struct das08_board_struct *thisboard = comedi_board(dev); + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); struct das08_private_struct *devpriv; unsigned long iobase; - struct pcmcia_device *link = cur_dev; /* XXX hack */ + int ret; + + /* The das08 driver needs the board_ptr */ + dev->board_ptr = &das08_cs_boards[0]; + + link->config_flags |= CONF_AUTO_SET_IO; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + iobase = link->resource[0]->start; devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); if (!devpriv) return -ENOMEM; dev->private = devpriv; - dev_info(dev->class_dev, "das08_cs: attach\n"); - /* deal with a pci board */ - - if (thisboard->bustype == pcmcia) { - if (link == NULL) { - dev_err(dev->class_dev, "no pcmcia cards found\n"); - return -EIO; - } - iobase = link->resource[0]->start; - } else { - dev_err(dev->class_dev, - "bug! board does not have PCMCIA bustype\n"); - return -EINVAL; - } - 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, - .attach = das08_cs_attach, - .detach = das08_common_detach, - .board_name = &das08_cs_boards[0].name, - .num_names = ARRAY_SIZE(das08_cs_boards), - .offset = sizeof(struct das08_board_struct), + .auto_attach = das08_cs_auto_attach, + .detach = das08_cs_detach, }; -static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - static int das08_pcmcia_attach(struct pcmcia_device *link) { - int ret; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - cur_dev = link; - return 0; - -failed: - pcmcia_disable_device(link); - return ret; -} - -static void das08_pcmcia_detach(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); - cur_dev = NULL; + return comedi_pcmcia_auto_config(link, &driver_das08_cs); } static const struct pcmcia_device_id das08_cs_id_table[] = { @@ -176,36 +121,11 @@ MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table); static struct pcmcia_driver das08_cs_driver = { .name = "pcm-das08", .owner = THIS_MODULE, - .probe = das08_pcmcia_attach, - .remove = das08_pcmcia_detach, .id_table = das08_cs_id_table, + .probe = das08_pcmcia_attach, + .remove = comedi_pcmcia_auto_unconfig, }; - -static int __init das08_cs_init_module(void) -{ - int ret; - - ret = comedi_driver_register(&driver_das08_cs); - if (ret < 0) - return ret; - - ret = pcmcia_register_driver(&das08_cs_driver); - if (ret < 0) { - comedi_driver_unregister(&driver_das08_cs); - return ret; - } - - return 0; - -} -module_init(das08_cs_init_module); - -static void __exit das08_cs_exit_module(void) -{ - pcmcia_unregister_driver(&das08_cs_driver); - comedi_driver_unregister(&driver_das08_cs); -} -module_exit(das08_cs_exit_module); +module_comedi_pcmcia_driver(driver_das08_cs, das08_cs_driver); MODULE_AUTHOR("David A. Schleef <ds@schleef.org>, " "Frank Mori Hess <fmhess@users.sourceforge.net>"); diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c new file mode 100644 index 000000000000..f12078247163 --- /dev/null +++ b/drivers/staging/comedi/drivers/das08_isa.c @@ -0,0 +1,217 @@ +/* + * das08_isa.c + * comedi driver for DAS08 ISA/PC-104 boards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2001,2002,2003 Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2004 Salvador E. Tropea <set@users.sf.net> <set@ieee.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Driver: das08_isa + * Description: DAS-08 ISA/PC-104 compatible boards + * Devices: (Keithley Metrabyte) DAS08 [isa-das08], + * (ComputerBoards) DAS08 [isa-das08] + * (ComputerBoards) DAS08-PGM [das08-pgm] + * (ComputerBoards) DAS08-PGH [das08-pgh] + * (ComputerBoards) DAS08-PGL [das08-pgl] + * (ComputerBoards) DAS08-AOH [das08-aoh] + * (ComputerBoards) DAS08-AOL [das08-aol] + * (ComputerBoards) DAS08-AOM [das08-aom] + * (ComputerBoards) DAS08/JR-AO [das08/jr-ao] + * (ComputerBoards) DAS08/JR-16-AO [das08jr-16-ao] + * (ComputerBoards) PC104-DAS08 [pc104-das08] + * (ComputerBoards) DAS08/JR/16 [das08jr/16] + * Author: Warren Jasper, ds, Frank Hess + * Updated: Fri, 31 Aug 2012 19:19:06 +0100 + * Status: works + * + * This is the ISA/PC-104-specific support split off from the das08 driver. + * + * Configuration Options: + * [0] - base io address + */ + +#include "../comedidev.h" + +#include "das08.h" + +static const struct das08_board_struct das08_isa_boards[] = { + { + /* cio-das08.pdf */ + .name = "isa-das08", + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 8, + .i8254_offset = 4, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08pgx.pdf */ + .name = "das08-pgm", + .ai_nbits = 12, + .ai_pg = das08_pgm, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08pgx.pdf */ + .name = "das08-pgh", + .ai_nbits = 12, + .ai_pg = das08_pgh, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08pgx.pdf */ + .name = "das08-pgl", + .ai_nbits = 12, + .ai_pg = das08_pgl, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08_aox.pdf */ + .name = "das08-aoh", + .ai_nbits = 12, + .ai_pg = das08_pgh, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08_aox.pdf */ + .name = "das08-aol", + .ai_nbits = 12, + .ai_pg = das08_pgl, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08_aox.pdf */ + .name = "das08-aom", + .ai_nbits = 12, + .ai_pg = das08_pgm, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08-jr-ao.pdf */ + .name = "das08/jr-ao", + .is_jr = true, + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 8, + .do_nchan = 8, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08jr-16-ao.pdf */ + .name = "das08jr-16-ao", + .is_jr = true, + .ai_nbits = 16, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode16, + .ao_nbits = 16, + .di_nchan = 8, + .do_nchan = 8, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + .name = "pc104-das08", + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 4, + .iosize = 16, /* unchecked */ + }, { + .name = "das08jr/16", + .is_jr = true, + .ai_nbits = 16, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode16, + .di_nchan = 8, + .do_nchan = 8, + .iosize = 16, /* unchecked */ + }, +}; + +static int das08_isa_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + const struct das08_board_struct *thisboard = comedi_board(dev); + struct das08_private_struct *devpriv; + + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + + if (!request_region(it->options[0], thisboard->iosize, + thisboard->name)) + return -EIO; + + return das08_common_attach(dev, it->options[0]); +} + +static void das08_isa_detach(struct comedi_device *dev) +{ + const struct das08_board_struct *thisboard = comedi_board(dev); + + das08_common_detach(dev); + if (dev->iobase) + release_region(dev->iobase, thisboard->iosize); +} + +static struct comedi_driver das08_isa_driver = { + .driver_name = "isa-das08", + .module = THIS_MODULE, + .attach = das08_isa_attach, + .detach = das08_isa_detach, + .board_name = &das08_isa_boards[0].name, + .num_names = ARRAY_SIZE(das08_isa_boards), + .offset = sizeof(das08_isa_boards[0]), +}; +module_comedi_driver(das08_isa_driver); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c new file mode 100644 index 000000000000..c405876ddcf7 --- /dev/null +++ b/drivers/staging/comedi/drivers/das08_pci.c @@ -0,0 +1,121 @@ +/* + * das08_pci.c + * comedi driver for DAS08 PCI boards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2001,2002,2003 Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2004 Salvador E. Tropea <set@users.sf.net> <set@ieee.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Driver: das08_pci + * Description: DAS-08 PCI compatible boards + * Devices: (ComputerBoards) PCI-DAS08 [pci-das08] + * Author: Warren Jasper, ds, Frank Hess + * Updated: Fri, 31 Aug 2012 19:19:06 +0100 + * Status: works + * + * This is the PCI-specific support split off from the das08 driver. + * + * Configuration Options: not applicable, uses PCI auto config + */ + +#include <linux/pci.h> + +#include "../comedidev.h" + +#include "das08.h" + +#define PCI_DEVICE_ID_PCIDAS08 0x0029 + +static const struct das08_board_struct das08_pci_boards[] = { + { + .name = "pci-das08", + .id = PCI_DEVICE_ID_PCIDAS08, + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 4, + .iosize = 8, + }, +}; + +static int das08_pci_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pdev = comedi_to_pci_dev(dev); + struct das08_private_struct *devpriv; + int ret; + + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + + /* The das08 driver needs the board_ptr */ + dev->board_ptr = &das08_pci_boards[0]; + + ret = comedi_pci_enable(pdev, dev->driver->driver_name); + if (ret) + return ret; + dev->iobase = pci_resource_start(pdev, 2); + + return das08_common_attach(dev, dev->iobase); +} + +static void das08_pci_detach(struct comedi_device *dev) +{ + struct pci_dev *pdev = comedi_to_pci_dev(dev); + + das08_common_detach(dev); + if (dev->iobase) + comedi_pci_disable(pdev); +} + +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, +}; + +static int das08_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &das08_pci_comedi_driver); +} + +static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_PCIDAS08) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, das08_pci_table); + +static struct pci_driver das08_pci_driver = { + .name = "pci-das08", + .id_table = das08_pci_table, + .probe = das08_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(das08_pci_comedi_driver, das08_pci_driver); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index b159f44d694f..f238a1fbccbf 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -82,7 +82,9 @@ www.measurementcomputing.com #include <linux/pci.h> #include <linux/slab.h> #include <linux/interrupt.h> + #include <asm/dma.h> + #include "../comedidev.h" #include "8253.h" diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 960da8debe17..3ce499fa5dbf 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -55,9 +55,11 @@ AO commands are not supported. #define DEBUG 1 +#include <linux/pci.h> +#include <linux/delay.h> #include <linux/interrupt.h> + #include "../comedidev.h" -#include <linux/delay.h> #include "comedi_fc.h" @@ -856,11 +858,6 @@ static int dt3000_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &dt3000_driver); } -static void dt3000_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001) }, { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001_PGL) }, @@ -877,7 +874,7 @@ static struct pci_driver dt3000_pci_driver = { .name = "dt3000", .id_table = dt3000_pci_table, .probe = dt3000_pci_probe, - .remove = dt3000_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 176799849d20..192cf088f834 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -702,10 +702,9 @@ static int dt9812_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (dev == NULL) goto error; - } + kref_init(&dev->kref); dev->udev = usb_get_dev(interface_to_usbdev(interface)); @@ -1133,7 +1132,7 @@ static struct comedi_driver dt9812_comedi_driver = { static int __init usb_dt9812_init(void) { - int result, i; + int i; /* Initialize all driver slots */ for (i = 0; i < DT9812_NUM_SLOTS; i++) { @@ -1144,30 +1143,13 @@ static int __init usb_dt9812_init(void) } dt9812[12].serial = 0x0; - /* register with the USB subsystem */ - result = usb_register(&dt9812_usb_driver); - if (result) { - pr_err("usb_register failed. Error number %d\n", result); - return result; - } - /* register with comedi */ - result = comedi_driver_register(&dt9812_comedi_driver); - if (result) { - usb_deregister(&dt9812_usb_driver); - pr_err("comedi_driver_register failed. Error number %d\n", - result); - } - - return result; + return comedi_usb_driver_register(&dt9812_comedi_driver, + &dt9812_usb_driver); } static void __exit usb_dt9812_exit(void) { - /* unregister with comedi */ - comedi_driver_unregister(&dt9812_comedi_driver); - - /* deregister this driver with the USB subsystem */ - usb_deregister(&dt9812_usb_driver); + comedi_usb_driver_unregister(&dt9812_comedi_driver, &dt9812_usb_driver); } module_init(usb_dt9812_init); diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index 8497a36db7db..decc17f1867e 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -37,9 +37,11 @@ their cards in their manuals. */ -#include "../comedidev.h" +#include <linux/pci.h> #include <linux/mutex.h> +#include "../comedidev.h" + #define READ_TIMEOUT 50 static const struct comedi_lrange range_pci1050_ai = { 3, { @@ -276,11 +278,6 @@ static int dyna_pci10xx_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &dyna_pci10xx_driver); } -static void dyna_pci10xx_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_PLX, 0x1050) }, { 0 } @@ -291,7 +288,7 @@ static struct pci_driver dyna_pci10xx_pci_driver = { .name = "dyna_pci10xx", .id_table = dyna_pci10xx_pci_table, .probe = dyna_pci10xx_pci_probe, - .remove = dyna_pci10xx_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(dyna_pci10xx_driver, dyna_pci10xx_pci_driver); diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 154598f6d5e3..b60c97562676 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -47,9 +47,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/pci.h> +#include <linux/delay.h> #include <linux/interrupt.h> + #include "../comedidev.h" -#include <linux/delay.h> #include "plx9080.h" #include "comedi_fc.h" @@ -946,11 +948,6 @@ static int gsc_hpdi_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &gsc_hpdi_driver); } -static void gsc_hpdi_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX, 0x2400, 0, 0, 0}, @@ -962,7 +959,7 @@ static struct pci_driver gsc_hpdi_pci_driver = { .name = "gsc_hpdi", .id_table = gsc_hpdi_pci_table, .probe = gsc_hpdi_pci_probe, - .remove = gsc_hpdi_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(gsc_hpdi_driver, gsc_hpdi_pci_driver); diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index a91a448ba0f0..1e08f9141fad 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -47,11 +47,11 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V Configuration options: not applicable, uses PCI auto config */ +#include <linux/pci.h> +#include <linux/delay.h> #include <linux/interrupt.h> -#include "../comedidev.h" -#include <linux/delay.h> -#include <linux/pci.h> +#include "../comedidev.h" #define PCI_DEVICE_ID_ICP_MULTI 0x8000 @@ -623,11 +623,6 @@ static int icp_multi_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &icp_multi_driver); } -static void icp_multi_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) }, { 0 } @@ -638,7 +633,7 @@ static struct pci_driver icp_multi_pci_driver = { .name = "icp_multi", .id_table = icp_multi_pci_table, .probe = icp_multi_pci_probe, - .remove = icp_multi_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver); diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index c756a35ce31a..17ba75e0ab89 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -42,15 +42,17 @@ * comedi_nonfree_firmware tarball. The file is called "jr3pci.idm". */ -#include "../comedidev.h" - +#include <linux/kernel.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/ctype.h> #include <linux/firmware.h> #include <linux/jiffies.h> #include <linux/slab.h> #include <linux/timer.h> -#include <linux/kernel.h> + +#include "../comedidev.h" + #include "jr3_pci.h" #define PCI_VENDOR_ID_JR3 0x1762 @@ -844,11 +846,6 @@ static int jr3_pci_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &jr3_pci_driver); } -static void jr3_pci_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) }, { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) }, @@ -863,7 +860,7 @@ static struct pci_driver jr3_pci_pci_driver = { .name = "jr3_pci", .id_table = jr3_pci_pci_table, .probe = jr3_pci_pci_probe, - .remove = jr3_pci_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver); diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 19c94282ac3f..8c09c026508a 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -34,6 +34,8 @@ This driver is a simple driver to read the counter values from Kolter Electronic PCI Counter Card. */ +#include <linux/pci.h> + #include "../comedidev.h" #define CNT_CARD_DEVICE_ID 0x0014 @@ -152,11 +154,6 @@ static int ke_counter_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ke_counter_driver); } -static void ke_counter_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, { 0 } @@ -167,7 +164,7 @@ static struct pci_driver ke_counter_pci_driver = { .name = "ke_counter", .id_table = ke_counter_pci_table, .probe = ke_counter_pci_probe, - .remove = ke_counter_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 3c4b0228e8dc..b766bb93efd6 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -45,13 +45,14 @@ broken. */ -#include <linux/interrupt.h> -#include "../comedidev.h" - +#include <linux/pci.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <linux/list.h> #include <linux/spinlock.h> +#include "../comedidev.h" + #include "comedi_fc.h" #include "8253.h" @@ -1734,11 +1735,6 @@ static int me4000_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &me4000_driver); } -static void me4000_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650)}, {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660)}, @@ -1761,7 +1757,7 @@ static struct pci_driver me4000_pci_driver = { .name = "me4000", .id_table = me4000_pci_table, .probe = me4000_pci_probe, - .remove = me4000_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(me4000_driver, me4000_pci_driver); diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index ce8e3d3f135c..06490ebc8cc8 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -34,9 +34,11 @@ * Analog Input, Analog Output, Digital I/O */ +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/firmware.h> + #include "../comedidev.h" #define ME2600_FIRMWARE "me2600_firmware.bin" @@ -619,11 +621,6 @@ static int me_daq_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &me_daq_driver); } -static void me_daq_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) }, { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) }, @@ -635,7 +632,7 @@ static struct pci_driver me_daq_pci_driver = { .name = "me_daq", .id_table = me_daq_pci_table, .probe = me_daq_pci_probe, - .remove = me_daq_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver); diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index e27850f628ce..be2c15f84614 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -51,11 +51,12 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "mite.h" +#include <linux/pci.h> -#include "comedi_fc.h" #include "../comedidev.h" +#include "comedi_fc.h" +#include "mite.h" #define PCI_MITE_SIZE 4096 #define PCI_DAQ_SIZE 4096 diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 5196b460ce11..bcd4df290ec4 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -41,7 +41,9 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800 #define DEBUG 1 #define DEBUG_FLAGS +#include <linux/pci.h> #include <linux/interrupt.h> + #include "../comedidev.h" #include "comedi_fc.h" @@ -452,16 +454,11 @@ static int ni6527_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni6527_driver); } -static void ni6527_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver ni6527_pci_driver = { .name = DRIVER_NAME, .id_table = ni6527_pci_table, .probe = ni6527_pci_probe, - .remove = ni6527_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver); diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 2fb4b7790aeb..bfa790ecf41d 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -50,8 +50,11 @@ except maybe the 6514. #define DEBUG 1 #define DEBUG_FLAGS + +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/slab.h> + #include "../comedidev.h" #include "comedi_fc.h" @@ -787,16 +790,11 @@ static int ni_65xx_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_65xx_driver); } -static void ni_65xx_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver ni_65xx_pci_driver = { .name = "ni_65xx", .id_table = ni_65xx_pci_table, .probe = ni_65xx_pci_probe, - .remove = ni_65xx_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(ni_65xx_driver, ni_65xx_pci_driver); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 26baf9c96fff..e46dd7a1a724 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -40,8 +40,11 @@ DAQ 6601/6602 User Manual (NI 322137B-01) */ +#include <linux/pci.h> #include <linux/interrupt.h> + #include "../comedidev.h" + #include "mite.h" #include "ni_tio.h" @@ -1327,11 +1330,6 @@ static int ni_660x_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_660x_driver); } -static void ni_660x_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(ni_660x_pci_table) = { {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c60)}, {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1310)}, @@ -1345,7 +1343,7 @@ static struct pci_driver ni_660x_pci_driver = { .name = "ni_660x", .id_table = ni_660x_pci_table, .probe = ni_660x_pci_probe, - .remove = ni_660x_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(ni_660x_driver, ni_660x_pci_driver); diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 272caeb6ecee..2faf86c83dc5 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -41,8 +41,10 @@ Commands are not supported. */ +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/slab.h> + #include "../comedidev.h" #include "mite.h" @@ -309,11 +311,6 @@ static int ni_670x_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_670x_driver); } -static void ni_670x_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c90) }, { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1920) }, @@ -325,7 +322,7 @@ static struct pci_driver ni_670x_pci_driver = { .name = "ni_670x", .id_table = ni_670x_pci_table, .probe = ni_670x_pci_probe, - .remove = ni_670x_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(ni_670x_driver, ni_670x_pci_driver); diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 68d7c6a5db7d..9cc6092eacdd 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -50,22 +50,15 @@ Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf User Manual: http://www.ni.com/pdf/manuals/320676d.pdf */ +#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/slab.h> -#include "../comedidev.h" -#include <linux/ioport.h> +#include "../comedidev.h" #include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -static struct pcmcia_device *pcmcia_cur_dev; - -struct daq700_board { - const char *name; -}; - /* daqcard700 registers */ #define DIO_W 0x04 /* WO 8bit */ #define DIO_R 0x05 /* RO 8bit */ @@ -202,24 +195,20 @@ static void daq700_ai_config(struct comedi_device *dev, inw(iobase + ADFIFO_R); /* read 16bit junk from FIFO to clear */ } -static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int daq700_auto_attach(struct comedi_device *dev, + unsigned long context) { - const struct daq700_board *thisboard = comedi_board(dev); + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); struct comedi_subdevice *s; - struct pcmcia_device *link; int ret; - link = pcmcia_cur_dev; /* XXX hack */ - if (!link) - return -EIO; + dev->board_name = dev->driver->driver_name; + link->config_flags |= CONF_AUTO_SET_IO; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; dev->iobase = link->resource[0]->start; - if (!dev->iobase) { - dev_err(dev->class_dev, "io base address is zero!\n"); - return -EINVAL; - } - - dev->board_name = thisboard->name; ret = comedi_alloc_subdevices(dev, 2); if (ret) @@ -256,68 +245,16 @@ static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static void daq700_detach(struct comedi_device *dev) -{ - /* nothing to cleanup */ -} - -static const struct daq700_board daq700_boards[] = { - { - .name = "daqcard-700", - }, { - .name = "ni_daq_700", - }, -}; - static struct comedi_driver daq700_driver = { .driver_name = "ni_daq_700", .module = THIS_MODULE, - .attach = daq700_attach, - .detach = daq700_detach, - .board_name = &daq700_boards[0].name, - .num_names = ARRAY_SIZE(daq700_boards), - .offset = sizeof(struct daq700_board), + .auto_attach = daq700_auto_attach, + .detach = comedi_pcmcia_disable, }; -static int daq700_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - static int daq700_cs_attach(struct pcmcia_device *link) { - int ret; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | - CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, daq700_pcmcia_config_loop, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - pcmcia_cur_dev = link; - return 0; - -failed: - pcmcia_disable_device(link); - return ret; -} - -static void daq700_cs_detach(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); - pcmcia_cur_dev = NULL; + return comedi_pcmcia_auto_config(link, &daq700_driver); } static const struct pcmcia_device_id daq700_cs_ids[] = { @@ -329,35 +266,11 @@ MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids); static struct pcmcia_driver daq700_cs_driver = { .name = "ni_daq_700", .owner = THIS_MODULE, - .probe = daq700_cs_attach, - .remove = daq700_cs_detach, .id_table = daq700_cs_ids, + .probe = daq700_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, }; - -static int __init daq700_cs_init(void) -{ - int ret; - - ret = comedi_driver_register(&daq700_driver); - if (ret < 0) - return ret; - - ret = pcmcia_register_driver(&daq700_cs_driver); - if (ret < 0) { - comedi_driver_unregister(&daq700_driver); - return ret; - } - - return 0; -} -module_init(daq700_cs_init); - -static void __exit daq700_cs_exit(void) -{ - pcmcia_unregister_driver(&daq700_cs_driver); - comedi_driver_unregister(&daq700_driver); -} -module_exit(daq700_cs_exit); +module_comedi_pcmcia_driver(daq700_driver, daq700_cs_driver); MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>"); MODULE_DESCRIPTION( diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 7b333353c5d9..e1cc9d01f200 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -37,127 +37,28 @@ This is just a wrapper around the 8255.o driver to properly handle the PCMCIA interface. */ - /* #define LABPC_DEBUG *//* enable debugging messages */ -#undef LABPC_DEBUG - -#include <linux/interrupt.h> -#include <linux/slab.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#include "8255.h" - #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -static struct pcmcia_device *pcmcia_cur_dev; - -#define DIO24_SIZE 4 /* size of io region used by board */ - -static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static void dio24_detach(struct comedi_device *dev); - -enum dio24_bustype { pcmcia_bustype }; - -struct dio24_board_struct { - const char *name; - int device_id; /* device id for pcmcia board */ - enum dio24_bustype bustype; /* PCMCIA */ - int have_dio; /* have 8255 chip */ - /* function pointers so we can use inb/outb or readb/writeb as appropriate */ - unsigned int (*read_byte) (unsigned int address); - void (*write_byte) (unsigned int byte, unsigned int address); -}; - -static const struct dio24_board_struct dio24_boards[] = { - { - .name = "daqcard-dio24", - .device_id = 0x475c, /* 0x10b is manufacturer id, 0x475c is device id */ - .bustype = pcmcia_bustype, - .have_dio = 1, - }, - { - .name = "ni_daq_dio24", - .device_id = 0x475c, /* 0x10b is manufacturer id, 0x475c is device id */ - .bustype = pcmcia_bustype, - .have_dio = 1, - }, -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct dio24_board_struct *)dev->board_ptr) - -struct dio24_private { - - int data; /* number of data points left to be taken */ -}; - -static struct comedi_driver driver_dio24 = { - .driver_name = "ni_daq_dio24", - .module = THIS_MODULE, - .attach = dio24_attach, - .detach = dio24_detach, - .num_names = ARRAY_SIZE(dio24_boards), - .board_name = &dio24_boards[0].name, - .offset = sizeof(struct dio24_board_struct), -}; +#include "8255.h" -static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int dio24_auto_attach(struct comedi_device *dev, + unsigned long context) { - struct dio24_private *devpriv; + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); struct comedi_subdevice *s; - unsigned long iobase = 0; -#ifdef incomplete - unsigned int irq = 0; -#endif - struct pcmcia_device *link; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - /* get base address, irq etc. based on bustype */ - switch (thisboard->bustype) { - case pcmcia_bustype: - link = pcmcia_cur_dev; /* XXX hack */ - if (!link) - return -EIO; - iobase = link->resource[0]->start; -#ifdef incomplete - irq = link->irq; -#endif - break; - default: - pr_err("bug! couldn't determine board type\n"); - return -EINVAL; - break; - } - pr_debug("comedi%d: ni_daq_dio24: %s, io 0x%lx", dev->minor, - thisboard->name, iobase); -#ifdef incomplete - if (irq) - pr_debug("irq %u\n", irq); -#endif - - if (iobase == 0) { - pr_err("io base address is zero!\n"); - return -EINVAL; - } + dev->board_name = dev->driver->driver_name; - dev->iobase = iobase; - -#ifdef incomplete - /* grab our IRQ */ - dev->irq = irq; -#endif - - dev->board_name = thisboard->name; + link->config_flags |= CONF_AUTO_SET_IO; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + dev->iobase = link->resource[0]->start; ret = comedi_alloc_subdevices(dev, 1); if (ret) @@ -165,184 +66,48 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* 8255 dio */ s = &dev->subdevices[0]; - subdev_8255_init(dev, s, NULL, dev->iobase); + ret = subdev_8255_init(dev, s, NULL, dev->iobase); + if (ret) + return ret; return 0; -}; +} static void dio24_detach(struct comedi_device *dev) { - struct comedi_subdevice *s; - - if (dev->subdevices) { - s = &dev->subdevices[0]; - subdev_8255_cleanup(dev, s); - } - if (thisboard->bustype != pcmcia_bustype && dev->iobase) - release_region(dev->iobase, DIO24_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); -}; - -static void dio24_config(struct pcmcia_device *link); -static void dio24_release(struct pcmcia_device *link); -static int dio24_cs_suspend(struct pcmcia_device *p_dev); -static int dio24_cs_resume(struct pcmcia_device *p_dev); - -static int dio24_cs_attach(struct pcmcia_device *); -static void dio24_cs_detach(struct pcmcia_device *); + if (dev->subdevices) + subdev_8255_cleanup(dev, &dev->subdevices[0]); + comedi_pcmcia_disable(dev); +} -struct local_info_t { - struct pcmcia_device *link; - int stop; - struct bus_operations *bus; +static struct comedi_driver driver_dio24 = { + .driver_name = "ni_daq_dio24", + .module = THIS_MODULE, + .auto_attach = dio24_auto_attach, + .detach = dio24_detach, }; static int dio24_cs_attach(struct pcmcia_device *link) { - struct local_info_t *local; - - dev_info(&link->dev, "ni_daq_dio24: HOLA SOY YO - CS-attach!\n"); - - dev_dbg(&link->dev, "dio24_cs_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->link = link; - link->priv = local; - - pcmcia_cur_dev = link; - - dio24_config(link); - - return 0; -} /* dio24_cs_attach */ - -static void dio24_cs_detach(struct pcmcia_device *link) -{ - ((struct local_info_t *)link->priv)->stop = 1; - dio24_release(link); - - /* This points to the parent local_info_t struct */ - kfree(link->priv); + return comedi_pcmcia_auto_config(link, &driver_dio24); } -static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static void dio24_config(struct pcmcia_device *link) -{ - int ret; - - dev_info(&link->dev, "ni_daq_dio24: HOLA SOY YO! - config\n"); - - dev_dbg(&link->dev, "dio24_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | - CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - return; - -failed: - dev_info(&link->dev, "Fallo"); - dio24_release(link); - -} /* dio24_config */ - -static void dio24_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "dio24_release\n"); - - pcmcia_disable_device(link); -} /* dio24_release */ - -static int dio24_cs_suspend(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - /* Mark the device as stopped, to block IO until later */ - local->stop = 1; - return 0; -} /* dio24_cs_suspend */ - -static int dio24_cs_resume(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - local->stop = 0; - return 0; -} /* dio24_cs_resume */ - -/*====================================================================*/ - static const struct pcmcia_device_id dio24_cs_ids[] = { - /* N.B. These IDs should match those in dio24_boards */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x475c), /* daqcard-dio24 */ PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, dio24_cs_ids); -MODULE_AUTHOR("Daniel Vecino Castel <dvecino@able.es>"); -MODULE_DESCRIPTION("Comedi driver for National Instruments " - "PCMCIA DAQ-Card DIO-24"); -MODULE_LICENSE("GPL"); static struct pcmcia_driver dio24_cs_driver = { - .probe = dio24_cs_attach, - .remove = dio24_cs_detach, - .suspend = dio24_cs_suspend, - .resume = dio24_cs_resume, - .id_table = dio24_cs_ids, - .owner = THIS_MODULE, - .name = "ni_daq_dio24", + .name = "ni_daq_dio24", + .owner = THIS_MODULE, + .id_table = dio24_cs_ids, + .probe = dio24_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, }; +module_comedi_pcmcia_driver(driver_dio24, dio24_cs_driver); -static int __init init_dio24_cs(void) -{ - printk("ni_daq_dio24: HOLA SOY YO!\n"); - pcmcia_register_driver(&dio24_cs_driver); - return 0; -} - -static void __exit exit_dio24_cs(void) -{ - pcmcia_unregister_driver(&dio24_cs_driver); -} - -int __init init_module(void) -{ - int ret; - - ret = init_dio24_cs(); - if (ret < 0) - return ret; - - return comedi_driver_register(&driver_dio24); -} - -void __exit cleanup_module(void) -{ - exit_dio24_cs(); - comedi_driver_unregister(&driver_dio24); -} +MODULE_AUTHOR("Daniel Vecino Castel <dvecino@able.es>"); +MODULE_DESCRIPTION( + "Comedi driver for National Instruments PCMCIA DAQ-Card DIO-24"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index d29c4d761bac..f957b8859b3d 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -73,12 +73,14 @@ NI manuals: */ +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/delay.h> + #include "../comedidev.h" -#include <linux/delay.h> #include <asm/dma.h> #include "8253.h" @@ -568,13 +570,11 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, return -EINVAL; } else if (dma_chan) { /* allocate dma buffer */ - devpriv->dma_buffer = - kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); - if (devpriv->dma_buffer == NULL) { - dev_err(dev->class_dev, - "failed to allocate dma buffer\n"); + devpriv->dma_buffer = kmalloc(dma_buffer_size, + GFP_KERNEL | GFP_DMA); + if (devpriv->dma_buffer == NULL) return -ENOMEM; - } + if (request_dma(dma_chan, DRV_NAME)) { dev_err(dev->class_dev, "failed to allocate dma channel %u\n", @@ -1202,7 +1202,8 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) else channel = CR_CHAN(cmd->chanlist[0]); /* munge channel bits for differential / scan disabled mode */ - if (mode != MODE_SINGLE_CHAN && aref == AREF_DIFF) + if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) && + aref == AREF_DIFF) channel *= 2; devpriv->command1_bits |= ADC_CHAN_BITS(channel); devpriv->command1_bits |= thisboard->ai_range_code[range]; @@ -1217,21 +1218,6 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); } - /* setup any external triggering/pacing (command4 register) */ - devpriv->command4_bits = 0; - if (cmd->convert_src != TRIG_EXT) - devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; - /* XXX should discard first scan when using interval scanning - * since manual says it is not synced with scan clock */ - if (labpc_use_continuous_mode(cmd, mode) == 0) { - devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT; - if (cmd->scan_begin_src == TRIG_EXT) - devpriv->command4_bits |= EXT_SCAN_EN_BIT; - } - /* single-ended/differential */ - if (aref == AREF_DIFF) - devpriv->command4_bits |= ADC_DIFF_BIT; - devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); devpriv->write_byte(cmd->chanlist_len, dev->iobase + INTERVAL_COUNT_REG); @@ -1311,6 +1297,22 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT; devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); + /* setup any external triggering/pacing (command4 register) */ + devpriv->command4_bits = 0; + if (cmd->convert_src != TRIG_EXT) + devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; + /* XXX should discard first scan when using interval scanning + * since manual says it is not synced with scan clock */ + if (labpc_use_continuous_mode(cmd, mode) == 0) { + devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT; + if (cmd->scan_begin_src == TRIG_EXT) + devpriv->command4_bits |= EXT_SCAN_EN_BIT; + } + /* single-ended/differential */ + if (aref == AREF_DIFF) + devpriv->command4_bits |= ADC_DIFF_BIT; + devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); + /* startup acquisition */ /* command2 reg */ @@ -2116,16 +2118,11 @@ static int labpc_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &labpc_driver); } -static void labpc_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver labpc_pci_driver = { .name = DRV_NAME, .id_table = labpc_pci_table, .probe = labpc_pci_probe, - .remove = labpc_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(labpc_driver, labpc_pci_driver); #else diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index bfe19fa7d66f..be7d1413b2e5 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -59,8 +59,6 @@ NI manuals: */ -#undef LABPC_DEBUG /* debugging messages */ - #include "../comedidev.h" #include <linux/delay.h> @@ -75,240 +73,81 @@ NI manuals: #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -static struct pcmcia_device *pcmcia_cur_dev; - -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it); - static const struct labpc_board_struct labpc_cs_boards[] = { { - .name = "daqcard-1200", - .device_id = 0x103, /* 0x10b is manufacturer id, - 0x103 is device id */ - .ai_speed = 10000, - .bustype = pcmcia_bustype, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, - .ai_range_is_unipolar = labpc_1200_is_unipolar, - .ai_scan_up = 0, - .memory_mapped_io = 0, - }, - /* duplicate entry, to support using alternate name */ - { - .name = "ni_labpc_cs", - .device_id = 0x103, - .ai_speed = 10000, - .bustype = pcmcia_bustype, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, - .ai_range_is_unipolar = labpc_1200_is_unipolar, - .ai_scan_up = 0, - .memory_mapped_io = 0, - }, + .name = "daqcard-1200", + .device_id = 0x103, + .ai_speed = 10000, + .bustype = pcmcia_bustype, + .register_layout = labpc_1200_layout, + .has_ao = 1, + .ai_range_table = &range_labpc_1200_ai, + .ai_range_code = labpc_1200_ai_gain_bits, + .ai_range_is_unipolar = labpc_1200_is_unipolar, + }, }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct labpc_board_struct *)dev->board_ptr) - -static struct comedi_driver driver_labpc_cs = { - .driver_name = "ni_labpc_cs", - .module = THIS_MODULE, - .attach = &labpc_attach, - .detach = &labpc_common_detach, - .num_names = ARRAY_SIZE(labpc_cs_boards), - .board_name = &labpc_cs_boards[0].name, - .offset = sizeof(struct labpc_board_struct), -}; - -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int labpc_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); struct labpc_private *devpriv; - unsigned long iobase = 0; - unsigned int irq = 0; - struct pcmcia_device *link; + int ret; + + /* The ni_labpc driver needs the board_ptr */ + dev->board_ptr = &labpc_cs_boards[0]; + + link->config_flags |= CONF_AUTO_SET_IO | + CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + dev->iobase = link->resource[0]->start; + + if (!link->irq) + return -EINVAL; devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); if (!devpriv) return -ENOMEM; dev->private = devpriv; - /* get base address, irq etc. based on bustype */ - switch (thisboard->bustype) { - case pcmcia_bustype: - link = pcmcia_cur_dev; /* XXX hack */ - if (!link) - return -EIO; - iobase = link->resource[0]->start; - irq = link->irq; - break; - default: - pr_err("bug! couldn't determine board type\n"); - return -EINVAL; - break; - } - return labpc_common_attach(dev, iobase, irq, 0); + return labpc_common_attach(dev, dev->iobase, link->irq, 0); } -static void labpc_config(struct pcmcia_device *link); -static void labpc_release(struct pcmcia_device *link); -static int labpc_cs_suspend(struct pcmcia_device *p_dev); -static int labpc_cs_resume(struct pcmcia_device *p_dev); - -static int labpc_cs_attach(struct pcmcia_device *); -static void labpc_cs_detach(struct pcmcia_device *); +static void labpc_detach(struct comedi_device *dev) +{ + labpc_common_detach(dev); + comedi_pcmcia_disable(dev); +} -struct local_info_t { - struct pcmcia_device *link; - int stop; - struct bus_operations *bus; +static struct comedi_driver driver_labpc_cs = { + .driver_name = "ni_labpc_cs", + .module = THIS_MODULE, + .auto_attach = labpc_auto_attach, + .detach = labpc_detach, }; static int labpc_cs_attach(struct pcmcia_device *link) { - struct local_info_t *local; - - dev_dbg(&link->dev, "labpc_cs_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->link = link; - link->priv = local; - - pcmcia_cur_dev = link; - - labpc_config(link); - - return 0; -} /* labpc_cs_attach */ - -static void labpc_cs_detach(struct pcmcia_device *link) -{ - ((struct local_info_t *)link->priv)->stop = 1; - labpc_release(link); - - /* This points to the parent local_info_t struct (may be null) */ - kfree(link->priv); - + return comedi_pcmcia_auto_config(link, &driver_labpc_cs); } -static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - - -static void labpc_config(struct pcmcia_device *link) -{ - int ret; - - dev_dbg(&link->dev, "labpc_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - return; - -failed: - labpc_release(link); - -} /* labpc_config */ - -static void labpc_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "labpc_release\n"); - - pcmcia_disable_device(link); -} /* labpc_release */ - -static int labpc_cs_suspend(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - /* Mark the device as stopped, to block IO until later */ - local->stop = 1; - return 0; -} /* labpc_cs_suspend */ - -static int labpc_cs_resume(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - local->stop = 0; - return 0; -} /* labpc_cs_resume */ - static const struct pcmcia_device_id labpc_cs_ids[] = { - /* N.B. These IDs should match those in labpc_cs_boards (ni_labpc.c) */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0103), /* daqcard-1200 */ PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, labpc_cs_ids); -MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); -MODULE_DESCRIPTION("Comedi driver for National Instruments Lab-PC"); -MODULE_LICENSE("GPL"); static struct pcmcia_driver labpc_cs_driver = { - .probe = labpc_cs_attach, - .remove = labpc_cs_detach, - .suspend = labpc_cs_suspend, - .resume = labpc_cs_resume, - .id_table = labpc_cs_ids, - .owner = THIS_MODULE, - .name = "daqcard-1200", + .name = "daqcard-1200", + .owner = THIS_MODULE, + .id_table = labpc_cs_ids, + .probe = labpc_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, }; +module_comedi_pcmcia_driver(driver_labpc_cs, labpc_cs_driver); -static int __init init_labpc_cs(void) -{ - pcmcia_register_driver(&labpc_cs_driver); - return 0; -} - -static void __exit exit_labpc_cs(void) -{ - pcmcia_unregister_driver(&labpc_cs_driver); -} - -static int __init labpc_init_module(void) -{ - int ret; - - ret = init_labpc_cs(); - if (ret < 0) - return ret; - - return comedi_driver_register(&driver_labpc_cs); -} - -static void __exit labpc_exit_module(void) -{ - exit_labpc_cs(); - comedi_driver_unregister(&driver_labpc_cs); -} - -module_init(labpc_init_module); -module_exit(labpc_exit_module); +MODULE_DESCRIPTION("Comedi driver for National Instruments Lab-PC"); +MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 56dc59908d36..b7403597e905 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -986,7 +986,7 @@ static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s) if (s-> async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | COMEDI_CB_EOA)) { - switch (s - dev->subdevices) { + switch (s->index) { case NI_AI_SUBDEV: ni_ai_reset(dev, s); break; @@ -1086,7 +1086,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, ("ni_mio_common: a_status=0xffff. Card removed?\n"); /* we probably aren't even running a command now, * so it's a good idea to be careful. */ - if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) { + if (comedi_is_subdevice_running(s)) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; ni_event(dev, s); diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index 76c6a13ea9d6..888be7b89d2d 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -65,112 +65,90 @@ See the notes in the ni_atmio.o driver. #define MAX_N_CALDACS 32 static const struct ni_board_struct ni_boards[] = { - {.device_id = 0x010d, - .name = "DAQCard-ai-16xe-50", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_8, - .ai_speed = 5000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {dac8800, dac8043}, - }, - {.device_id = 0x010c, - .name = "DAQCard-ai-16e-4", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_16, - .ai_speed = 4000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {mb88341}, /* verified */ - }, - {.device_id = 0x02c4, - .name = "DAQCard-6062E", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 8192, - .alwaysdither = 0, - .gainlkup = ai_gain_16, - .ai_speed = 2000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 2048, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 1176, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {ad8804_debug}, /* verified */ - }, - {.device_id = 0x075e, - .name = "DAQCard-6024E", /* specs incorrect! */ - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 1000000, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {ad8804_debug}, - }, - {.device_id = 0x0245, - .name = "DAQCard-6036E", /* specs incorrect! */ - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 1024, - .alwaysdither = 1, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 1000000, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {ad8804_debug}, + { + .device_id = 0x010d, + .name = "DAQCard-ai-16xe-50", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_8, + .ai_speed = 5000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043 }, + }, { + .device_id = 0x010c, + .name = "DAQCard-ai-16e-4", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_16, + .ai_speed = 4000, + .num_p0_dio_channels = 8, + .caldac = { mb88341 }, /* verified */ + }, { + .device_id = 0x02c4, + .name = "DAQCard-6062E", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 8192, + .gainlkup = ai_gain_16, + .ai_speed = 2000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, + .ao_range_table = &range_bipolar10, + .ao_speed = 1176, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, /* verified */ + }, { + /* specs incorrect! */ + .device_id = 0x075e, + .name = "DAQCard-6024E", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 12, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, { + /* specs incorrect! */ + .device_id = 0x0245, + .name = "DAQCard-6036E", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 1024, + .alwaysdither = 1, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 16, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, }, #if 0 - {.device_id = 0x0000, /* unknown */ - .name = "DAQCard-6715", - .n_adchan = 0, - .n_aochan = 8, - .aobits = 12, - .ao_671x = 8192, - .num_p0_dio_channels = 8, - .caldac = {mb88341, mb88341}, - }, + { + .device_id = 0x0000, /* unknown */ + .name = "DAQCard-6715", + .n_aochan = 8, + .aobits = 12, + .ao_671x = 8192, + .num_p0_dio_channels = 8, + .caldac = { mb88341, mb88341 }, + }, #endif - /* N.B. Update ni_mio_cs_ids[] when entries added above. */ }; #define interrupt_pin(a) 0 #define IRQ_POLARITY 1 -#define NI_E_IRQ_FLAGS IRQF_SHARED - struct ni_private { struct pcmcia_device *link; @@ -225,67 +203,22 @@ static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr) return ret; } -static int mio_cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static void mio_cs_detach(struct comedi_device *dev); -static struct comedi_driver driver_ni_mio_cs = { - .driver_name = "ni_mio_cs", - .module = THIS_MODULE, - .attach = mio_cs_attach, - .detach = mio_cs_detach, -}; - #include "ni_mio_common.c" -static int ni_getboardtype(struct comedi_device *dev, - struct pcmcia_device *link); - -static void mio_cs_detach(struct comedi_device *dev) -{ - mio_common_detach(dev); - if (dev->irq) - free_irq(dev->irq, dev); -} - -static void mio_cs_config(struct pcmcia_device *link); -static void cs_release(struct pcmcia_device *link); -static void cs_detach(struct pcmcia_device *); - -static struct pcmcia_device *cur_dev; - -static int cs_attach(struct pcmcia_device *link) +static const void *ni_getboardtype(struct comedi_device *dev, + struct pcmcia_device *link) { - cur_dev = link; - - mio_cs_config(link); - - return 0; -} - -static void cs_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static void cs_detach(struct pcmcia_device *link) -{ - cs_release(link); -} - -static int mio_cs_suspend(struct pcmcia_device *link) -{ - DPRINTK("pm suspend\n"); - - return 0; -} + static const struct ni_board_struct *board; + int i; -static int mio_cs_resume(struct pcmcia_device *link) -{ - DPRINTK("pm resume\n"); - return 0; + for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { + board = &ni_boards[i]; + if (board->device_id == link->card_id) + return board; + } + return NULL; } - static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) { int base, ret; @@ -302,114 +235,63 @@ static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) return -ENODEV; } - -static void mio_cs_config(struct pcmcia_device *link) -{ - int ret; - - DPRINTK("mio_cs_config(link=%p)\n", link); - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, mio_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - return; - } - - if (!link->irq) - dev_info(&link->dev, "no IRQ available\n"); - - ret = pcmcia_enable_device(link); -} - -static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int mio_cs_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + static const struct ni_board_struct *board; struct ni_private *devpriv; - struct pcmcia_device *link; - unsigned int irq; int ret; - DPRINTK("mio_cs_attach(dev=%p,it=%p)\n", dev, it); - - link = cur_dev; /* XXX hack */ - if (!link) - return -EIO; + board = ni_getboardtype(dev, link); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - dev->driver = &driver_ni_mio_cs; + link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + ret = comedi_pcmcia_enable(dev, mio_pcmcia_config_loop); + if (ret) + return ret; dev->iobase = link->resource[0]->start; - irq = link->irq; - - dev->board_ptr = ni_boards + ni_getboardtype(dev, link); - -#if 0 - { - int i; - - printk("comedi%d: %s: DAQCard: io 0x%04lx, irq %u, ", - dev->minor, dev->driver->driver_name, dev->iobase, irq); - - printk(" board fingerprint:"); - for (i = 0; i < 32; i += 2) { - printk(" %04x %02x", inw(dev->iobase + i), - inb(dev->iobase + i + 1)); - } - printk("\n"); - printk(" board fingerprint (windowed):"); - for (i = 0; i < 10; i++) - printk(" 0x%04x", win_in(i)); - printk("\n"); - - printk("boardtype.name: %s\n", boardtype.name); - } -#endif - - dev->board_name = boardtype.name; - - ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, - "ni_mio_cs", dev); - if (ret < 0) { - dev_err(dev->class_dev, "irq not available\n"); - return -EINVAL; - } - dev->irq = irq; + link->priv = dev; + ret = pcmcia_request_irq(link, ni_E_interrupt); + if (ret) + return ret; + dev->irq = link->irq; ret = ni_alloc_private(dev); if (ret) return ret; - devpriv = dev->private; - - devpriv->stc_writew = &mio_cs_win_out; - devpriv->stc_readw = &mio_cs_win_in; - devpriv->stc_writel = &win_out2; - devpriv->stc_readl = &win_in2; - - ret = ni_E_init(dev); - if (ret < 0) - return ret; + devpriv = dev->private; + devpriv->stc_writew = mio_cs_win_out; + devpriv->stc_readw = mio_cs_win_in; + devpriv->stc_writel = win_out2; + devpriv->stc_readl = win_in2; - return 0; + return ni_E_init(dev); } -static int ni_getboardtype(struct comedi_device *dev, - struct pcmcia_device *link) +static void mio_cs_detach(struct comedi_device *dev) { - int i; - - for (i = 0; i < n_ni_boards; i++) { - if (ni_boards[i].device_id == link->card_id) - return i; - } + mio_common_detach(dev); + comedi_pcmcia_disable(dev); +} - dev_err(dev->class_dev, - "unknown board 0x%04x -- pretend it is a ", link->card_id); +static struct comedi_driver driver_ni_mio_cs = { + .driver_name = "ni_mio_cs", + .module = THIS_MODULE, + .auto_attach = mio_cs_auto_attach, + .detach = mio_cs_detach, +}; - return 0; +static int cs_attach(struct pcmcia_device *link) +{ + return comedi_pcmcia_auto_config(link, &driver_ni_mio_cs); } -#ifdef MODULE - static const struct pcmcia_device_id ni_mio_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010d), /* DAQCard-ai-16xe-50 */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010c), /* DAQCard-ai-16e-4 */ @@ -418,36 +300,17 @@ static const struct pcmcia_device_id ni_mio_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0245), /* DAQCard-6036E */ PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, ni_mio_cs_ids); -MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); -MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series"); -MODULE_LICENSE("GPL"); static struct pcmcia_driver ni_mio_cs_driver = { - .probe = &cs_attach, - .remove = &cs_detach, - .suspend = &mio_cs_suspend, - .resume = &mio_cs_resume, - .id_table = ni_mio_cs_ids, - .owner = THIS_MODULE, - .name = "ni_mio_cs", + .name = "ni_mio_cs", + .owner = THIS_MODULE, + .id_table = ni_mio_cs_ids, + .probe = cs_attach, + .remove = comedi_pcmcia_auto_unconfig, }; +module_comedi_pcmcia_driver(driver_ni_mio_cs, ni_mio_cs_driver); -int init_module(void) -{ - pcmcia_register_driver(&ni_mio_cs_driver); - comedi_driver_register(&driver_ni_mio_cs); - return 0; -} - -void cleanup_module(void) -{ - pcmcia_unregister_driver(&ni_mio_cs_driver); -#if 0 - while (cur_dev != NULL) - cs_detach(cur_dev->handle); -#endif - comedi_driver_unregister(&driver_ni_mio_cs); -} -#endif +MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series"); +MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 084ebea33ab9..0a00260d11f3 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -55,9 +55,11 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org /* #define DEBUG 1 */ /* #define DEBUG_FLAGS */ +#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/firmware.h> + #include "../comedidev.h" #include "comedi_fc.h" @@ -1224,11 +1226,6 @@ static int ni_pcidio_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_pcidio_driver); } -static void ni_pcidio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) }, { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) }, @@ -1241,7 +1238,7 @@ static struct pci_driver ni_pcidio_pci_driver = { .name = "ni_pcidio", .id_table = ni_pcidio_pci_table, .probe = ni_pcidio_pci_probe, - .remove = ni_pcidio_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(ni_pcidio_driver, ni_pcidio_pci_driver); diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index fd1662b4175d..98b43f2fc65d 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -110,10 +110,12 @@ Bugs: */ +#include <linux/delay.h> +#include <linux/delay.h> + #include "../comedidev.h" #include <asm/byteorder.h> -#include <linux/delay.h> #include "ni_stc.h" #include "mite.h" @@ -1791,11 +1793,6 @@ static int ni_pcimio_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_pcimio_driver); } -static void ni_pcimio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162) }, { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170) }, @@ -1858,7 +1855,7 @@ static struct pci_driver ni_pcimio_pci_driver = { .name = "ni_pcimio", .id_table = ni_pcimio_pci_table, .probe = ni_pcimio_pci_probe, - .remove = ni_pcimio_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver); diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c index 98f87897e2a8..225287769dc1 100644 --- a/drivers/staging/comedi/drivers/ni_tio.c +++ b/drivers/staging/comedi/drivers/ni_tio.c @@ -276,7 +276,7 @@ static inline unsigned NI_660x_RTSI_Second_Gate_Select(unsigned n) } static const unsigned int counter_status_mask = - COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; + COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; static int __init ni_tio_init_module(void) { diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 0c991b99da13..13747f324936 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -159,6 +159,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) async->inttrig = NULL; mite_dma_arm(counter->mite_chan); retval = ni_tio_arm(counter, 1, cmd->start_arg); + break; case TRIG_OTHER: async->inttrig = NULL; mite_dma_arm(counter->mite_chan); diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index 06127a5f62a0..b5af22eb7c37 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -243,8 +243,8 @@ static const struct comedi_lrange range_pcl818l_h_ai = { 4, { }; static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} }; -static const struct comedi_lrange range718_bipolar0_5 = - { 1, {BIP_RANGE(0.5),} }; +static const struct comedi_lrange range718_bipolar0_5 = { + 1, {BIP_RANGE(0.5),} }; static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} }; static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} }; @@ -1005,17 +1005,14 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, switch (devpriv->dma) { case 1: /* DMA */ case 3: - if (devpriv->dma_rtc == 0) { + if (devpriv->dma_rtc == 0) pcl818_ai_mode13dma_int(mode, dev, s); - } #ifdef unused - else { + else pcl818_ai_mode13dma_rtc(mode, dev, s); - } #else - else { + else return -EINVAL; - } #endif break; case 0: @@ -1069,7 +1066,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, */ #ifdef PCL818_MODE13_AO static int pcl818_ao_mode13(int mode, struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) + struct comedi_subdevice *s, comedi_trig *it) { struct pcl818_private *devpriv = dev->private; int divisor1 = 0, divisor2 = 0; @@ -1124,7 +1121,7 @@ static int pcl818_ao_mode13(int mode, struct comedi_device *dev, ANALOG OUTPUT MODE 1, 818 cards */ static int pcl818_ao_mode1(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) + struct comedi_subdevice *s, comedi_trig *it) { return pcl818_ao_mode13(1, dev, s, it); } @@ -1134,7 +1131,7 @@ static int pcl818_ao_mode1(struct comedi_device *dev, ANALOG OUTPUT MODE 3, 818 cards */ static int pcl818_ao_mode3(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) + struct comedi_subdevice *s, comedi_trig *it) { return pcl818_ao_mode13(3, dev, s, it); } diff --git a/drivers/staging/comedi/drivers/pcm_common.c b/drivers/staging/comedi/drivers/pcm_common.c deleted file mode 100644 index 8a718aea6f3c..000000000000 --- a/drivers/staging/comedi/drivers/pcm_common.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "../comedidev.h" - -#include "comedi_fc.h" -#include "pcm_common.h" - -int comedi_pcm_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - int err = 0; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->start_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - /* if (err) return 4; */ - - return 0; -} -EXPORT_SYMBOL(comedi_pcm_cmdtest); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcm_common.h b/drivers/staging/comedi/drivers/pcm_common.h deleted file mode 100644 index cd4840c11444..000000000000 --- a/drivers/staging/comedi/drivers/pcm_common.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _comedi_common_H -#define _comedi_common_H - -extern int comedi_pcm_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -#endif diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 0882dafaf57b..13f79f49748a 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -53,9 +53,6 @@ Configuration Options: #include "../comedidev.h" -#include <linux/pci.h> /* for PCI devices */ - -#define SDEV_NO ((int)(s - dev->subdevices)) #define CHANS 8 #define IOSIZE 16 #define LSB(x) ((unsigned char)((x) & 0xff)) diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 7522bfb6db08..5fa1fe08eb97 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -78,9 +78,10 @@ Configuration Options: #include <linux/interrupt.h> #include <linux/slab.h> + #include "../comedidev.h" -#include "pcm_common.h" -#include <linux/pci.h> /* for PCI devices */ + +#include "comedi_fc.h" /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */ #define CHANS_PER_PORT 8 @@ -93,7 +94,6 @@ Configuration Options: #define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) #define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT) #define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) -#define SDEV_NO ((int)(s - dev->subdevices)) #define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) /* IO Memory sizes */ #define ASIC_IOSIZE (0x0B) @@ -802,11 +802,59 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -static int -pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int pcmmio_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - return comedi_pcm_cmdtest(dev, s, cmd); + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + switch (cmd->stop_src) { + case TRIG_COUNT: + /* any count allowed */ + break; + case TRIG_NONE: + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + break; + default: + break; + } + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* if (err) return 4; */ + + return 0; } static int adc_wait_ready(unsigned long iobase) diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 31ea20c2d39e..433270ceda4f 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -77,10 +77,10 @@ Configuration Options: #include <linux/interrupt.h> #include <linux/slab.h> + #include "../comedidev.h" -#include "pcm_common.h" -#include <linux/pci.h> /* for PCI devices */ +#include "comedi_fc.h" #define CHANS_PER_PORT 8 #define PORTS_PER_ASIC 6 @@ -92,7 +92,6 @@ Configuration Options: #define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) #define MAX_DIO_CHANS (PORTS_PER_ASIC*2*CHANS_PER_PORT) #define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) -#define SDEV_NO ((int)(s - dev->subdevices)) #define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) /* IO Memory sizes */ #define ASIC_IOSIZE (0x10) @@ -740,11 +739,59 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -static int -pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int pcmuio_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - return comedi_pcm_cmdtest(dev, s, cmd); + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + switch (cmd->stop_src) { + case TRIG_COUNT: + /* any count allowed */ + break; + case TRIG_NONE: + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + break; + default: + break; + } + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* if (err) return 4; */ + + return 0; } static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -791,14 +838,11 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) 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); - if (!devpriv->sprivs) { - dev_warn(dev->class_dev, - "cannot allocate subdevice private data structures\n"); + devpriv->sprivs = kcalloc(n_subdevs, + sizeof(struct pcmuio_subdev_private), + GFP_KERNEL); + if (!devpriv->sprivs) return -ENOMEM; - } ret = comedi_alloc_subdevices(dev, n_subdevs); if (ret) diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index ef0cdaa7f02e..911eb6b32296 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -47,8 +47,6 @@ Status: works Devices: [Quatech] DAQP-208 (daqp), DAQP-308 */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include "../comedidev.h" #include <linux/semaphore.h> @@ -60,28 +58,16 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308 #include "comedi_fc.h" -/* Maximum number of separate DAQP devices we'll allow */ -#define MAX_DEV 4 - -struct local_info_t { - struct pcmcia_device *link; +struct daqp_private { int stop; - int table_index; - char board_name[32]; enum { semaphore, buffer } interrupt_mode; struct completion eos; - struct comedi_device *dev; - struct comedi_subdevice *s; int count; }; -/* A list of "instances" of the device. */ - -static struct local_info_t *dev_table[MAX_DEV] = { NULL, /* ... */ }; - /* The DAQP communicates with the system through a 16 byte I/O window. */ #define DAQP_FIFO_SIZE 4096 @@ -165,84 +151,38 @@ static struct local_info_t *dev_table[MAX_DEV] = { NULL, /* ... */ }; #define DAQP_AUX_FIFO_NEARFULL 0x02 #define DAQP_AUX_FIFO_EMPTY 0x01 -/* These range structures tell COMEDI how the sample values map to - * voltages. The A/D converter has four .ranges = +/- 10V through - * +/- 1.25V, and the D/A converter has only .one = +/- 5V. - */ - -static const struct comedi_lrange range_daqp_ai = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25) - } -}; - -static const struct comedi_lrange range_daqp_ao = { 1, {BIP_RANGE(5)} }; - -/*====================================================================*/ - -/* comedi interface code */ - -static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static void daqp_detach(struct comedi_device *dev); -static struct comedi_driver driver_daqp = { - .driver_name = "quatech_daqp_cs", - .module = THIS_MODULE, - .attach = daqp_attach, - .detach = daqp_detach, -}; - -#ifdef DAQP_DEBUG - -static void daqp_dump(struct comedi_device *dev) -{ - dev_info(dev->class_dev, "status %02x; aux status %02x\n", - inb(dev->iobase + DAQP_STATUS), inb(dev->iobase + DAQP_AUX)); -} - -static void hex_dump(char *str, void *ptr, int len) -{ - unsigned char *cptr = ptr; - int i; - - printk(str); - - for (i = 0; i < len; i++) { - if (i % 16 == 0) - printk("\n%p:", cptr); - - printk(" %02x", *(cptr++)); +static const struct comedi_lrange range_daqp_ai = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) } - printk("\n"); -} - -#endif +}; /* Cancel a running acquisition */ static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; - if (local->stop) + if (devpriv->stop) return -EIO; - outb(DAQP_COMMAND_STOP, dev->iobase + DAQP_COMMAND); /* flush any linguring data in FIFO - superfluous here */ /* outb(DAQP_COMMAND_RSTF, dev->iobase+DAQP_COMMAND); */ - local->interrupt_mode = semaphore; + devpriv->interrupt_mode = semaphore; return 0; } /* Interrupt handler * - * Operates in one of two modes. If local->interrupt_mode is - * 'semaphore', just signal the local->eos completion and return + * Operates in one of two modes. If devpriv->interrupt_mode is + * 'semaphore', just signal the devpriv->eos completion and return * (one-shot mode). Otherwise (continuous mode), read data in from * the card, transfer it to the buffer provided by the higher-level * comedi kernel module, and signal various comedi callback routines, @@ -250,48 +190,21 @@ static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) */ static enum irqreturn daqp_interrupt(int irq, void *dev_id) { - struct local_info_t *local = (struct local_info_t *)dev_id; - struct comedi_device *dev; - struct comedi_subdevice *s; + struct comedi_device *dev = dev_id; + struct daqp_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; int loop_limit = 10000; int status; - if (local == NULL) { - pr_warn("irq %d for unknown device.\n", irq); + if (!dev->attached) return IRQ_NONE; - } - - dev = local->dev; - if (dev == NULL) { - pr_warn("NULL comedi_device.\n"); - return IRQ_NONE; - } - - if (!dev->attached) { - pr_warn("struct comedi_device not yet attached.\n"); - return IRQ_NONE; - } - - s = local->s; - if (s == NULL) { - pr_warn("NULL comedi_subdevice.\n"); - return IRQ_NONE; - } - - if ((struct local_info_t *)s->private != local) { - pr_warn("invalid comedi_subdevice.\n"); - return IRQ_NONE; - } - - switch (local->interrupt_mode) { + switch (devpriv->interrupt_mode) { case semaphore: - - complete(&local->eos); + complete(&devpriv->eos); break; case buffer: - while (!((status = inb(dev->iobase + DAQP_STATUS)) & DAQP_STATUS_FIFO_EMPTY)) { @@ -315,9 +228,9 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) * and stop conversion if zero */ - if (local->count > 0) { - local->count--; - if (local->count == 0) { + if (devpriv->count > 0) { + devpriv->count--; + if (devpriv->count == 0) { daqp_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; break; @@ -342,21 +255,41 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void daqp_ai_set_one_scanlist_entry(struct comedi_device *dev, + unsigned int chanspec, + int start) +{ + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int val; + + val = DAQP_SCANLIST_CHANNEL(chan) | DAQP_SCANLIST_GAIN(range); + + if (aref == AREF_DIFF) + val |= DAQP_SCANLIST_DIFFERENTIAL; + + if (start) + val |= DAQP_SCANLIST_START; + + outb(val & 0xff, dev->iobase + DAQP_SCANLIST); + outb((val >> 8) & 0xff, dev->iobase + DAQP_SCANLIST); +} + /* One-shot analog data acquisition routine */ static int daqp_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; int i; int v; int counter = 10000; - if (local->stop) + if (devpriv->stop) return -EIO; - /* Stop any running conversion */ daqp_ai_cancel(dev, s); @@ -366,18 +299,7 @@ static int daqp_ai_insn_read(struct comedi_device *dev, outb(DAQP_COMMAND_RSTQ, dev->iobase + DAQP_COMMAND); /* Program one scan list entry */ - - v = DAQP_SCANLIST_CHANNEL(CR_CHAN(insn->chanspec)) - | DAQP_SCANLIST_GAIN(CR_RANGE(insn->chanspec)); - - if (CR_AREF(insn->chanspec) == AREF_DIFF) - v |= DAQP_SCANLIST_DIFFERENTIAL; - - - v |= DAQP_SCANLIST_START; - - outb(v & 0xff, dev->iobase + DAQP_SCANLIST); - outb(v >> 8, dev->iobase + DAQP_SCANLIST); + daqp_ai_set_one_scanlist_entry(dev, insn->chanspec, 1); /* Reset data FIFO (see page 28 of DAQP User's Manual) */ @@ -403,10 +325,8 @@ static int daqp_ai_insn_read(struct comedi_device *dev, return -1; } - init_completion(&local->eos); - local->interrupt_mode = semaphore; - local->dev = dev; - local->s = s; + init_completion(&devpriv->eos); + devpriv->interrupt_mode = semaphore; for (i = 0; i < insn->n; i++) { @@ -416,7 +336,7 @@ static int daqp_ai_insn_read(struct comedi_device *dev, /* Wait for interrupt service routine to unblock completion */ /* Maybe could use a timeout here, but it's interruptible */ - if (wait_for_completion_interruptible(&local->eos)) + if (wait_for_completion_interruptible(&devpriv->eos)) return -EINTR; data[i] = inb(dev->iobase + DAQP_FIFO); @@ -541,7 +461,7 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int counter; int scanlist_start_on_every_entry; @@ -550,10 +470,9 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) int i; int v; - if (local->stop) + if (devpriv->stop) return -EIO; - /* Stop any running conversion */ daqp_ai_cancel(dev, s); @@ -592,24 +511,10 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Program scan list */ - for (i = 0; i < cmd->chanlist_len; i++) { + int start = (i == 0 || scanlist_start_on_every_entry); - int chanspec = cmd->chanlist[i]; - - /* Program one scan list entry */ - - v = DAQP_SCANLIST_CHANNEL(CR_CHAN(chanspec)) - | DAQP_SCANLIST_GAIN(CR_RANGE(chanspec)); - - if (CR_AREF(chanspec) == AREF_DIFF) - v |= DAQP_SCANLIST_DIFFERENTIAL; - - if (i == 0 || scanlist_start_on_every_entry) - v |= DAQP_SCANLIST_START; - - outb(v & 0xff, dev->iobase + DAQP_SCANLIST); - outb(v >> 8, dev->iobase + DAQP_SCANLIST); + daqp_ai_set_one_scanlist_entry(dev, cmd->chanlist[i], start); } /* Now it's time to program the FIFO threshold, basically the @@ -675,16 +580,16 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* Save away the number of conversions we should perform, and * compute the FIFO threshold (in bytes, not samples - that's - * why we multiple local->count by 2 = sizeof(sample)) + * why we multiple devpriv->count by 2 = sizeof(sample)) */ if (cmd->stop_src == TRIG_COUNT) { - local->count = cmd->stop_arg * cmd->scan_end_arg; - threshold = 2 * local->count; + devpriv->count = cmd->stop_arg * cmd->scan_end_arg; + threshold = 2 * devpriv->count; while (threshold > DAQP_FIFO_SIZE * 3 / 4) threshold /= 2; } else { - local->count = -1; + devpriv->count = -1; threshold = DAQP_FIFO_SIZE / 2; } @@ -726,9 +631,7 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return -1; } - local->interrupt_mode = buffer; - local->dev = dev; - local->s = s; + devpriv->interrupt_mode = buffer; /* Start conversion */ outb(DAQP_COMMAND_ARM | DAQP_COMMAND_FIFO_DATA, @@ -737,341 +640,193 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* Single-shot analog output routine */ - static int daqp_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct local_info_t *local = (struct local_info_t *)s->private; - int d; - unsigned int chan; + struct daqp_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - if (local->stop) + if (devpriv->stop) return -EIO; - chan = CR_CHAN(insn->chanspec); - d = data[0]; - d &= 0x0fff; - d ^= 0x0800; /* Flip the sign */ - d |= chan << 12; - /* Make sure D/A update mode is direct update */ outb(0, dev->iobase + DAQP_AUX); - outw(d, dev->iobase + DAQP_DA); + for (i = 0; i > insn->n; i++) { + val = data[0]; + val &= 0x0fff; + val ^= 0x0800; /* Flip the sign */ + val |= (chan << 12); - return 1; -} + outw(val, dev->iobase + DAQP_DA); + } -/* Digital input routine */ + return insn->n; +} -static int daqp_di_insn_read(struct comedi_device *dev, +static int daqp_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; - if (local->stop) + if (devpriv->stop) return -EIO; data[0] = inb(dev->iobase + DAQP_DIGITAL_IO); - return 1; + return insn->n; } -/* Digital output routine */ - -static int daqp_do_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int daqp_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; + unsigned int mask = data[0]; + unsigned int bits = data[1]; - if (local->stop) + if (devpriv->stop) return -EIO; - outw(data[0] & 0xf, dev->iobase + DAQP_DIGITAL_IO); + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); - return 1; -} + outb(s->state, dev->iobase + DAQP_DIGITAL_IO); + } -/* daqp_attach is called via comedi_config to attach a comedi device - * to a /dev/comedi*. Note that this is different from daqp_cs_attach() - * which is called by the pcmcia subsystem to attach the PCMCIA card - * when it is inserted. - */ + data[1] = s->state; -static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) + return insn->n; +} + +static int daqp_auto_attach(struct comedi_device *dev, + unsigned long context) { - int ret; - struct local_info_t *local = dev_table[it->options[0]]; + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + struct daqp_private *devpriv; struct comedi_subdevice *s; + int ret; - if (it->options[0] < 0 || it->options[0] >= MAX_DEV || !local) { - dev_err(dev->class_dev, "No such daqp device %d\n", - it->options[0]); - return -EIO; - } + dev->board_name = dev->driver->driver_name; - /* Typically brittle code that I don't completely understand, - * but "it works on my card". The intent is to pull the model - * number of the card out the PCMCIA CIS and stash it away as - * the COMEDI board_name. Looks like the third field in - * CISTPL_VERS_1 (offset 2) holds what we're looking for. If - * it doesn't work, who cares, just leave it as "DAQP". - */ + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; - strcpy(local->board_name, "DAQP"); - dev->board_name = local->board_name; - if (local->link->prod_id[2]) { - if (strncmp(local->link->prod_id[2], "DAQP", 4) == 0) { - strncpy(local->board_name, local->link->prod_id[2], - sizeof(local->board_name)); - } - } + link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + dev->iobase = link->resource[0]->start; - dev->iobase = local->link->resource[0]->start; + link->priv = dev; + ret = pcmcia_request_irq(link, daqp_interrupt); + if (ret) + return ret; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - dev_info(dev->class_dev, "attaching daqp%d (io 0x%04lx)\n", - it->options[0], dev->iobase); - s = &dev->subdevices[0]; dev->read_subdev = s; - s->private = local; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; - s->n_chan = 8; - s->len_chanlist = 2048; - s->maxdata = 0xffff; - s->range_table = &range_daqp_ai; - s->insn_read = daqp_ai_insn_read; - s->do_cmdtest = daqp_ai_cmdtest; - s->do_cmd = daqp_ai_cmd; - s->cancel = daqp_ai_cancel; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + s->n_chan = 8; + s->len_chanlist = 2048; + s->maxdata = 0xffff; + s->range_table = &range_daqp_ai; + s->insn_read = daqp_ai_insn_read; + s->do_cmdtest = daqp_ai_cmdtest; + s->do_cmd = daqp_ai_cmd; + s->cancel = daqp_ai_cancel; s = &dev->subdevices[1]; - dev->write_subdev = s; - s->private = local; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 2; - s->len_chanlist = 1; - s->maxdata = 0x0fff; - s->range_table = &range_daqp_ao; - s->insn_write = daqp_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_bipolar5; + s->insn_write = daqp_ao_insn_write; s = &dev->subdevices[2]; - s->private = local; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 1; - s->len_chanlist = 1; - s->insn_read = daqp_di_insn_read; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 1; + s->maxdata = 1; + s->insn_bits = daqp_di_insn_bits; s = &dev->subdevices[3]; - s->private = local; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 1; - s->len_chanlist = 1; - s->insn_write = daqp_do_insn_write; - - return 1; -} - -static void daqp_detach(struct comedi_device *dev) -{ - /* Nothing to cleanup */ -} - -/*==================================================================== - - PCMCIA interface code - - The rest of the code in this file is based on dummy_cs.c v1.24 - from the Linux pcmcia_cs distribution v3.1.8 and is subject - to the following license agreement. - - The remaining contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -static void daqp_cs_config(struct pcmcia_device *link); -static void daqp_cs_release(struct pcmcia_device *link); -static int daqp_cs_suspend(struct pcmcia_device *p_dev); -static int daqp_cs_resume(struct pcmcia_device *p_dev); - -static int daqp_cs_attach(struct pcmcia_device *); -static void daqp_cs_detach(struct pcmcia_device *); - -static int daqp_cs_attach(struct pcmcia_device *link) -{ - struct local_info_t *local; - int i; - - dev_dbg(&link->dev, "daqp_cs_attach()\n"); - - for (i = 0; i < MAX_DEV; i++) - if (dev_table[i] == NULL) - break; - if (i == MAX_DEV) { - dev_notice(&link->dev, "no devices available\n"); - return -ENODEV; - } - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - - local->table_index = i; - dev_table[i] = local; - local->link = link; - link->priv = local; - - daqp_cs_config(link); + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 1; + s->maxdata = 1; + s->insn_bits = daqp_do_insn_bits; return 0; -} /* daqp_cs_attach */ - -static void daqp_cs_detach(struct pcmcia_device *link) -{ - struct local_info_t *dev = link->priv; - - dev->stop = 1; - daqp_cs_release(link); - - /* Unlink device structure, and free it */ - dev_table[dev->table_index] = NULL; - kfree(dev); - } -static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static void daqp_cs_config(struct pcmcia_device *link) -{ - int ret; - - dev_dbg(&link->dev, "daqp_cs_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, daqp_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } - - ret = pcmcia_request_irq(link, daqp_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - return; - -failed: - daqp_cs_release(link); - -} /* daqp_cs_config */ - -static void daqp_cs_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "daqp_cs_release\n"); - - pcmcia_disable_device(link); -} /* daqp_cs_release */ +static struct comedi_driver driver_daqp = { + .driver_name = "quatech_daqp_cs", + .module = THIS_MODULE, + .auto_attach = daqp_auto_attach, + .detach = comedi_pcmcia_disable, +}; static int daqp_cs_suspend(struct pcmcia_device *link) { - struct local_info_t *local = link->priv; + struct comedi_device *dev = link->priv; + struct daqp_private *devpriv = dev ? dev->private : NULL; /* Mark the device as stopped, to block IO until later */ - local->stop = 1; + if (devpriv) + devpriv->stop = 1; + return 0; } static int daqp_cs_resume(struct pcmcia_device *link) { - struct local_info_t *local = link->priv; + struct comedi_device *dev = link->priv; + struct daqp_private *devpriv = dev ? dev->private : NULL; - local->stop = 0; + if (devpriv) + devpriv->stop = 0; return 0; } -/*====================================================================*/ - -#ifdef MODULE +static int daqp_cs_attach(struct pcmcia_device *link) +{ + return comedi_pcmcia_auto_config(link, &driver_daqp); +} static const struct pcmcia_device_id daqp_cs_id_table[] = { PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0027), PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, daqp_cs_id_table); -MODULE_AUTHOR("Brent Baccala <baccala@freesoft.org>"); -MODULE_DESCRIPTION("Comedi driver for Quatech DAQP PCMCIA data capture cards"); -MODULE_LICENSE("GPL"); static struct pcmcia_driver daqp_cs_driver = { - .probe = daqp_cs_attach, - .remove = daqp_cs_detach, - .suspend = daqp_cs_suspend, - .resume = daqp_cs_resume, - .id_table = daqp_cs_id_table, - .owner = THIS_MODULE, - .name = "quatech_daqp_cs", + .name = "quatech_daqp_cs", + .owner = THIS_MODULE, + .id_table = daqp_cs_id_table, + .probe = daqp_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, + .suspend = daqp_cs_suspend, + .resume = daqp_cs_resume, }; +module_comedi_pcmcia_driver(driver_daqp, daqp_cs_driver); -int __init init_module(void) -{ - pcmcia_register_driver(&daqp_cs_driver); - comedi_driver_register(&driver_daqp); - return 0; -} - -void __exit cleanup_module(void) -{ - comedi_driver_unregister(&driver_daqp); - pcmcia_unregister_driver(&daqp_cs_driver); -} - -#endif +MODULE_DESCRIPTION("Comedi driver for Quatech DAQP PCMCIA data capture cards"); +MODULE_AUTHOR("Brent Baccala <baccala@freesoft.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 8d7c948a919c..6a5c914fa501 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -101,8 +101,9 @@ Configuration options: */ -#include <linux/interrupt.h> +#include <linux/pci.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include "../comedidev.h" @@ -1420,11 +1421,6 @@ static int rtd520_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &rtd520_driver); } -static void rtd520_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) }, { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) }, @@ -1436,7 +1432,7 @@ static struct pci_driver rtd520_pci_driver = { .name = "rtd520", .id_table = rtd520_pci_table, .probe = rtd520_pci_probe, - .remove = rtd520_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver); diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 6dc1d2812865..81a1fe661579 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -64,6 +64,7 @@ INSN_CONFIG instructions: comedi_do_insn(cf,&insn); //executing configuration */ +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/types.h> @@ -2836,11 +2837,6 @@ static int s626_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &s626_driver); } -static void s626_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - /* * For devices with vendor:device id == 0x1131:0x7146 you must specify * also subvendor:subdevice ids, because otherwise it will conflict with @@ -2857,7 +2853,7 @@ static struct pci_driver s626_pci_driver = { .name = "s626", .id_table = s626_pci_table, .probe = s626_pci_probe, - .remove = s626_pci_remove, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(s626_driver, s626_pci_driver); diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index e2d79700a615..cb83f6ae48b9 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -72,9 +72,9 @@ Configuration Options: * options that are used with comedi_config. */ -#include "../comedidev.h" +#include <linux/pci.h> -#include <linux/pci.h> /* for PCI devices */ +#include "../comedidev.h" #include "comedi_fc.h" @@ -707,15 +707,11 @@ static int skel_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &skel_driver); } -static void skel_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - static struct pci_driver skel_pci_driver = { + .name = "dummy", .id_table = skel_pci_table, .probe = &skel_pci_probe, - .remove = &skel_pci_remove + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(skel_driver, skel_pci_driver); #else diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c index c9ded938314f..74b974bf1032 100644 --- a/drivers/staging/comedi/drivers/unioxx5.c +++ b/drivers/staging/comedi/drivers/unioxx5.c @@ -380,12 +380,8 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, } usp = kzalloc(sizeof(*usp), GFP_KERNEL); - - if (usp == NULL) { - dev_err(subdev->class_dev, - "comedi%d: error! --> out of memory!\n", minor); + if (usp == NULL) return -1; - } usp->usp_iobase = subdev_iobase; dev_info(subdev->class_dev, "comedi%d: |", minor); diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 17b45ebb0553..1a0062a04456 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -2388,7 +2388,7 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, "Could not upload firmware (err=%d)\n", ret); goto out; } - comedi_usb_auto_config(uinterf, &usbdux_driver); + comedi_usb_auto_config(uinterf, &usbdux_driver, 0); out: release_firmware(fw); } @@ -2445,8 +2445,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, /* create space for the commands of the DA converter */ usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); if (!usbduxsub[index].dac_commands) { - dev_err(dev, "comedi_: usbdux: " - "error alloc space for dac commands\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2454,8 +2452,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, /* create space for the commands going to the usb device */ usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); if (!usbduxsub[index].dux_commands) { - dev_err(dev, "comedi_: usbdux: " - "error alloc space for dux commands\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2463,8 +2459,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, /* create space for the in buffer and set it to zero */ usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL); if (!(usbduxsub[index].inBuffer)) { - dev_err(dev, "comedi_: usbdux: " - "could not alloc space for inBuffer\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2472,8 +2466,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, /* create space of the instruction buffer */ usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL); if (!(usbduxsub[index].insnBuffer)) { - dev_err(dev, "comedi_: usbdux: " - "could not alloc space for insnBuffer\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2481,8 +2473,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, /* create space for the outbuffer */ usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); if (!(usbduxsub[index].outBuffer)) { - dev_err(dev, "comedi_: usbdux: " - "could not alloc space for outBuffer\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2504,10 +2494,9 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL; usbduxsub[index].urbIn = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers, - GFP_KERNEL); + kcalloc(usbduxsub[index].numOfInBuffers, sizeof(struct urb *), + GFP_KERNEL); if (!(usbduxsub[index].urbIn)) { - dev_err(dev, "comedi_: usbdux: Could not alloc. urbIn array\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2532,8 +2521,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, usbduxsub[index].urbIn[i]->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) { - dev_err(dev, "comedi_: usbdux%d: " - "could not alloc. transb.\n", index); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2552,11 +2539,9 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL; usbduxsub[index].urbOut = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers, - GFP_KERNEL); + kcalloc(usbduxsub[index].numOfOutBuffers, sizeof(struct urb *), + GFP_KERNEL); if (!(usbduxsub[index].urbOut)) { - dev_err(dev, "comedi_: usbdux: " - "Could not alloc. urbOut array\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2581,8 +2566,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, usbduxsub[index].urbOut[i]->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) { - dev_err(dev, "comedi_: usbdux%d: " - "could not alloc. transb.\n", index); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2617,8 +2600,6 @@ static int usbdux_usb_probe(struct usb_interface *uinterf, usbduxsub[index].urbPwm->transfer_buffer = kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL); if (!(usbduxsub[index].urbPwm->transfer_buffer)) { - dev_err(dev, "comedi_: usbdux%d: " - "could not alloc. transb. for pwm\n", index); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 4e19f6186f28..4bf5dd094dc9 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -1490,7 +1490,7 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware goto out; } - comedi_usb_auto_config(uinterf, &usbduxfast_driver); + comedi_usb_auto_config(uinterf, &usbduxfast_driver, 0); out: release_firmware(fw); } @@ -1556,8 +1556,6 @@ static int usbduxfast_usb_probe(struct usb_interface *uinterf, usbduxfastsub[index].dux_commands = kmalloc(SIZEOFDUXBUFFER, GFP_KERNEL); if (!usbduxfastsub[index].dux_commands) { - dev_err(&uinterf->dev, - "error alloc space for dac commands\n"); tidy_up(&(usbduxfastsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -1565,8 +1563,6 @@ static int usbduxfast_usb_probe(struct usb_interface *uinterf, /* create space of the instruction buffer */ usbduxfastsub[index].insnBuffer = kmalloc(SIZEINSNBUF, GFP_KERNEL); if (!usbduxfastsub[index].insnBuffer) { - dev_err(&uinterf->dev, - "could not alloc space for insnBuffer\n"); tidy_up(&(usbduxfastsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -1592,8 +1588,6 @@ static int usbduxfast_usb_probe(struct usb_interface *uinterf, } usbduxfastsub[index].transfer_buffer = kmalloc(SIZEINBUF, GFP_KERNEL); if (!usbduxfastsub[index].transfer_buffer) { - dev_err(&uinterf->dev, - "usbduxfast%d: could not alloc. transb.\n", index); tidy_up(&(usbduxfastsub[index])); up(&start_stop_sem); return -ENOMEM; diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index cdd279b1f61e..d066351a71b2 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -2374,7 +2374,7 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, "Could not upload firmware (err=%d)\n", ret); goto out; } - comedi_usb_auto_config(uinterf, &usbduxsigma_driver); + comedi_usb_auto_config(uinterf, &usbduxsigma_driver, 0); out: release_firmware(fw); } @@ -2431,8 +2431,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, /* create space for the commands of the DA converter */ usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); if (!usbduxsub[index].dac_commands) { - dev_err(dev, "comedi_: usbduxsigma: " - "error alloc space for dac commands\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2440,8 +2438,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, /* create space for the commands going to the usb device */ usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); if (!usbduxsub[index].dux_commands) { - dev_err(dev, "comedi_: usbduxsigma: " - "error alloc space for dux commands\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2449,8 +2445,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, /* create space for the in buffer and set it to zero */ usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL); if (!(usbduxsub[index].inBuffer)) { - dev_err(dev, "comedi_: usbduxsigma: " - "could not alloc space for inBuffer\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2458,8 +2452,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, /* create space of the instruction buffer */ usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL); if (!(usbduxsub[index].insnBuffer)) { - dev_err(dev, "comedi_: usbduxsigma: " - "could not alloc space for insnBuffer\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2467,8 +2459,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, /* create space for the outbuffer */ usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); if (!(usbduxsub[index].outBuffer)) { - dev_err(dev, "comedi_: usbduxsigma: " - "could not alloc space for outBuffer\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2489,12 +2479,10 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, else usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL; - usbduxsub[index].urbIn = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers, - GFP_KERNEL); + usbduxsub[index].urbIn = kcalloc(usbduxsub[index].numOfInBuffers, + sizeof(struct urb *), + GFP_KERNEL); if (!(usbduxsub[index].urbIn)) { - dev_err(dev, "comedi_: usbduxsigma: " - "Could not alloc. urbIn array\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2519,8 +2507,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, usbduxsub[index].urbIn[i]->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) { - dev_err(dev, "comedi_: usbduxsigma%d: " - "could not alloc. transb.\n", index); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2539,12 +2525,9 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, else usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL; - usbduxsub[index].urbOut = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers, - GFP_KERNEL); + usbduxsub[index].urbOut = kcalloc(usbduxsub[index].numOfOutBuffers, + sizeof(struct urb *), GFP_KERNEL); if (!(usbduxsub[index].urbOut)) { - dev_err(dev, "comedi_: usbduxsigma: " - "Could not alloc. urbOut array\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2569,8 +2552,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, usbduxsub[index].urbOut[i]->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) { - dev_err(dev, "comedi_: usbduxsigma%d: " - "could not alloc. transb.\n", index); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; @@ -2606,8 +2587,6 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf, usbduxsub[index].urbPwm->transfer_buffer = kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL); if (!(usbduxsub[index].urbPwm->transfer_buffer)) { - dev_err(dev, "comedi_: usbduxsigma%d: " - "could not alloc. transb. for pwm\n", index); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 609dc6915997..2be5087414f6 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -38,19 +38,6 @@ Supports: - counter - pwm */ -/* -Changelog: - -0.8.81 -3- code completely rewritten (adjust driver logic) -0.8.81 -2- full support for K8061 -0.8.81 -1- fix some mistaken among others the number of - supported boards and I/O handling - -0.7.76 -4- renamed to vmk80xx -0.7.76 -3- detect K8061 (only theoretically supported) -0.7.76 -2- code completely rewritten (adjust driver logic) -0.7.76 -1- support for digital and counter subdevice -*/ #include <linux/kernel.h> #include <linux/module.h> @@ -113,30 +100,9 @@ enum { #define VMK8061_CMD_RD_AO 0x0f #define VMK8061_CMD_RD_PWM 0x10 -#define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS - -#define TRANS_OUT_BUSY 1 -#define TRANS_IN_BUSY 2 -#define TRANS_IN_RUNNING 3 - #define IC3_VERSION (1 << 0) #define IC6_VERSION (1 << 1) -#define URB_RCV_FLAG (1 << 0) -#define URB_SND_FLAG (1 << 1) - -#ifdef CONFIG_COMEDI_DEBUG -static int dbgcm = 1; -#else -static int dbgcm; -#endif - -#define dbgcm(fmt, arg...) \ -do { \ - if (dbgcm) \ - printk(KERN_DEBUG fmt, ##arg); \ -} while (0) - enum vmk80xx_model { VMK8055_MODEL, VMK8061_MODEL @@ -147,130 +113,73 @@ struct firmware_version { unsigned char ic6_vers[32]; /* CPU */ }; -static const struct comedi_lrange vmk8055_range = { - 1, {UNI_RANGE(5)} -}; - static const struct comedi_lrange vmk8061_range = { - 2, {UNI_RANGE(5), UNI_RANGE(10)} + 2, { + UNI_RANGE(5), + UNI_RANGE(10) + } }; struct vmk80xx_board { const char *name; enum vmk80xx_model model; const struct comedi_lrange *range; - __u8 ai_chans; - __le16 ai_bits; - __u8 ao_chans; - __le16 ao_bits; - __u8 di_chans; - __le16 di_bits; - __u8 do_chans; - __le16 do_bits; - __u8 cnt_chans; - __le16 cnt_bits; - __u8 pwm_chans; - __le16 pwm_bits; + int ai_nchans; + unsigned int ai_maxdata; + int ao_nchans; + int di_nchans; + unsigned int cnt_maxdata; + int pwm_nchans; + unsigned int pwm_maxdata; }; -enum { - VMK80XX_SUBD_AI, - VMK80XX_SUBD_AO, - VMK80XX_SUBD_DI, - VMK80XX_SUBD_DO, - VMK80XX_SUBD_CNT, - VMK80XX_SUBD_PWM, +static const struct vmk80xx_board vmk80xx_boardinfo[] = { + [DEVICE_VMK8055] = { + .name = "K8055 (VM110)", + .model = VMK8055_MODEL, + .range = &range_unipolar5, + .ai_nchans = 2, + .ai_maxdata = 0x00ff, + .ao_nchans = 2, + .di_nchans = 6, + .cnt_maxdata = 0xffff, + }, + [DEVICE_VMK8061] = { + .name = "K8061 (VM140)", + .model = VMK8061_MODEL, + .range = &vmk8061_range, + .ai_nchans = 8, + .ai_maxdata = 0x03ff, + .ao_nchans = 8, + .di_nchans = 8, + .cnt_maxdata = 0, /* unknown, device is not writeable */ + .pwm_nchans = 1, + .pwm_maxdata = 0x03ff, + }, }; -struct vmk80xx_usb { - struct usb_device *udev; +struct vmk80xx_private { + struct usb_device *usb; struct usb_interface *intf; struct usb_endpoint_descriptor *ep_rx; struct usb_endpoint_descriptor *ep_tx; - struct usb_anchor rx_anchor; - struct usb_anchor tx_anchor; - struct vmk80xx_board board; struct firmware_version fw; struct semaphore limit_sem; - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; unsigned char *usb_rx_buf; unsigned char *usb_tx_buf; - unsigned long flags; - int probed; - int attached; - int count; + enum vmk80xx_model model; }; -static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS]; - -static DEFINE_MUTEX(glb_mutex); - -static void vmk80xx_tx_callback(struct urb *urb) -{ - struct vmk80xx_usb *dev = urb->context; - int stat = urb->status; - - if (stat && !(stat == -ENOENT - || stat == -ECONNRESET || stat == -ESHUTDOWN)) - dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", - __func__, stat); - - if (!test_bit(TRANS_OUT_BUSY, &dev->flags)) - return; - - clear_bit(TRANS_OUT_BUSY, &dev->flags); - - wake_up_interruptible(&dev->write_wait); -} - -static void vmk80xx_rx_callback(struct urb *urb) -{ - struct vmk80xx_usb *dev = urb->context; - int stat = urb->status; - - switch (stat) { - case 0: - break; - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - break; - default: - dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", - __func__, stat); - goto resubmit; - } - - goto exit; -resubmit: - if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) { - usb_anchor_urb(urb, &dev->rx_anchor); - - if (!usb_submit_urb(urb, GFP_KERNEL)) - goto exit; - - dev_err(&urb->dev->dev, - "comedi#: vmk80xx: %s - submit urb failed\n", - __func__); - - usb_unanchor_urb(urb); - } -exit: - clear_bit(TRANS_IN_BUSY, &dev->flags); - - wake_up_interruptible(&dev->read_wait); -} - -static int vmk80xx_check_data_link(struct vmk80xx_usb *dev) +static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv) { + struct usb_device *usb = devpriv->usb; unsigned int tx_pipe; unsigned int rx_pipe; unsigned char tx[1]; unsigned char rx[2]; - tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); - rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); + tx_pipe = usb_sndbulkpipe(usb, 0x01); + rx_pipe = usb_rcvbulkpipe(usb, 0x81); tx[0] = VMK8061_CMD_RD_PWR_STAT; @@ -279,22 +188,23 @@ static int vmk80xx_check_data_link(struct vmk80xx_usb *dev) * running and the data link between IC3 and * IC6 is working properly */ - usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval); - usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10); + usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval); + usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10); return (int)rx[1]; } -static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag) +static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag) { + struct usb_device *usb = devpriv->usb; unsigned int tx_pipe; unsigned int rx_pipe; unsigned char tx[1]; unsigned char rx[64]; int cnt; - tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); - rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); + tx_pipe = usb_sndbulkpipe(usb, 0x01); + rx_pipe = usb_rcvbulkpipe(usb, 0x81); tx[0] = VMK8061_CMD_RD_VERSION; @@ -302,243 +212,116 @@ static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag) * Read the firmware version info of IC3 and * IC6 from the internal EEPROM of the IC */ - usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval); - usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10); + usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval); + usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10); rx[cnt] = '\0'; if (flag & IC3_VERSION) - strncpy(dev->fw.ic3_vers, rx + 1, 24); + strncpy(devpriv->fw.ic3_vers, rx + 1, 24); else /* IC6_VERSION */ - strncpy(dev->fw.ic6_vers, rx + 25, 24); + strncpy(devpriv->fw.ic6_vers, rx + 25, 24); } -static int vmk80xx_reset_device(struct vmk80xx_usb *dev) -{ - struct urb *urb; - unsigned int tx_pipe; - int ival; - size_t size; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - tx_pipe = usb_sndintpipe(dev->udev, 0x01); - - ival = dev->ep_tx->bInterval; - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - - dev->usb_tx_buf[0] = VMK8055_CMD_RST; - dev->usb_tx_buf[1] = 0x00; - dev->usb_tx_buf[2] = 0x00; - dev->usb_tx_buf[3] = 0x00; - dev->usb_tx_buf[4] = 0x00; - dev->usb_tx_buf[5] = 0x00; - dev->usb_tx_buf[6] = 0x00; - dev->usb_tx_buf[7] = 0x00; - - usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf, - size, vmk80xx_tx_callback, dev, ival); - - usb_anchor_urb(urb, &dev->tx_anchor); - - return usb_submit_urb(urb, GFP_KERNEL); -} - -static void vmk80xx_build_int_urb(struct urb *urb, int flag) -{ - struct vmk80xx_usb *dev = urb->context; - __u8 rx_addr; - __u8 tx_addr; - unsigned int pipe; - unsigned char *buf; - size_t size; - void (*callback) (struct urb *); - int ival; - - if (flag & URB_RCV_FLAG) { - rx_addr = dev->ep_rx->bEndpointAddress; - pipe = usb_rcvintpipe(dev->udev, rx_addr); - buf = dev->usb_rx_buf; - size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); - callback = vmk80xx_rx_callback; - ival = dev->ep_rx->bInterval; - } else { /* URB_SND_FLAG */ - tx_addr = dev->ep_tx->bEndpointAddress; - pipe = usb_sndintpipe(dev->udev, tx_addr); - buf = dev->usb_tx_buf; - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - callback = vmk80xx_tx_callback; - ival = dev->ep_tx->bInterval; - } - - usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival); -} - -static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev) +static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv) { + struct usb_device *usb = devpriv->usb; __u8 tx_addr; __u8 rx_addr; unsigned int tx_pipe; unsigned int rx_pipe; size_t size; - set_bit(TRANS_IN_BUSY, &dev->flags); - set_bit(TRANS_OUT_BUSY, &dev->flags); - - tx_addr = dev->ep_tx->bEndpointAddress; - rx_addr = dev->ep_rx->bEndpointAddress; - tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr); - rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr); + tx_addr = devpriv->ep_tx->bEndpointAddress; + rx_addr = devpriv->ep_rx->bEndpointAddress; + tx_pipe = usb_sndbulkpipe(usb, tx_addr); + rx_pipe = usb_rcvbulkpipe(usb, rx_addr); /* * The max packet size attributes of the K8061 * input/output endpoints are identical */ - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - - usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf, - size, NULL, dev->ep_tx->bInterval); - usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10); + size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize); - clear_bit(TRANS_OUT_BUSY, &dev->flags); - clear_bit(TRANS_IN_BUSY, &dev->flags); + usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf, + size, NULL, devpriv->ep_tx->bInterval); + usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10); } -static int vmk80xx_read_packet(struct vmk80xx_usb *dev) +static int vmk80xx_read_packet(struct vmk80xx_private *devpriv) { - struct urb *urb; - int retval; + struct usb_device *usb; + struct usb_endpoint_descriptor *ep; + unsigned int pipe; - if (!dev->intf) + if (!devpriv->intf) return -ENODEV; - /* Only useful for interrupt transfers */ - if (test_bit(TRANS_IN_BUSY, &dev->flags)) - if (wait_event_interruptible(dev->read_wait, - !test_bit(TRANS_IN_BUSY, - &dev->flags))) - return -ERESTART; - - if (dev->board.model == VMK8061_MODEL) { - vmk80xx_do_bulk_msg(dev); - + if (devpriv->model == VMK8061_MODEL) { + vmk80xx_do_bulk_msg(devpriv); return 0; } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - urb->context = dev; - vmk80xx_build_int_urb(urb, URB_RCV_FLAG); - - set_bit(TRANS_IN_RUNNING, &dev->flags); - set_bit(TRANS_IN_BUSY, &dev->flags); - - usb_anchor_urb(urb, &dev->rx_anchor); - - retval = usb_submit_urb(urb, GFP_KERNEL); - if (!retval) - goto exit; - - clear_bit(TRANS_IN_RUNNING, &dev->flags); - usb_unanchor_urb(urb); - -exit: - usb_free_urb(urb); - - return retval; + usb = devpriv->usb; + ep = devpriv->ep_rx; + pipe = usb_rcvintpipe(usb, ep->bEndpointAddress); + return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf, + le16_to_cpu(ep->wMaxPacketSize), NULL, + HZ * 10); } -static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd) +static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd) { - struct urb *urb; - int retval; + struct usb_device *usb; + struct usb_endpoint_descriptor *ep; + unsigned int pipe; - if (!dev->intf) + if (!devpriv->intf) return -ENODEV; - if (test_bit(TRANS_OUT_BUSY, &dev->flags)) - if (wait_event_interruptible(dev->write_wait, - !test_bit(TRANS_OUT_BUSY, - &dev->flags))) - return -ERESTART; - - if (dev->board.model == VMK8061_MODEL) { - dev->usb_tx_buf[0] = cmd; - vmk80xx_do_bulk_msg(dev); + devpriv->usb_tx_buf[0] = cmd; + if (devpriv->model == VMK8061_MODEL) { + vmk80xx_do_bulk_msg(devpriv); return 0; } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - urb->context = dev; - vmk80xx_build_int_urb(urb, URB_SND_FLAG); - - set_bit(TRANS_OUT_BUSY, &dev->flags); - - usb_anchor_urb(urb, &dev->tx_anchor); - - dev->usb_tx_buf[0] = cmd; - - retval = usb_submit_urb(urb, GFP_KERNEL); - if (!retval) - goto exit; - - clear_bit(TRANS_OUT_BUSY, &dev->flags); - usb_unanchor_urb(urb); - -exit: - usb_free_urb(urb); - - return retval; + usb = devpriv->usb; + ep = devpriv->ep_tx; + pipe = usb_sndintpipe(usb, ep->bEndpointAddress); + return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf, + le16_to_cpu(ep->wMaxPacketSize), NULL, + HZ * 10); } -#define DIR_IN 1 -#define DIR_OUT 2 - -static int rudimentary_check(struct vmk80xx_usb *dev, int dir) +static int vmk80xx_reset_device(struct vmk80xx_private *devpriv) { - if (!dev) - return -EFAULT; - if (!dev->probed) - return -ENODEV; - if (!dev->attached) - return -ENODEV; - if (dir & DIR_IN) { - if (test_bit(TRANS_IN_BUSY, &dev->flags)) - return -EBUSY; - } - if (dir & DIR_OUT) { - if (test_bit(TRANS_OUT_BUSY, &dev->flags)) - return -EBUSY; - } + size_t size; + int retval; - return 0; + size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize); + memset(devpriv->usb_tx_buf, 0, size); + retval = vmk80xx_write_packet(devpriv, 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); } -static int vmk80xx_ai_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int reg[2]; int n; - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); - switch (dev->board.model) { + switch (devpriv->model) { case VMK8055_MODEL: if (!chan) reg[0] = VMK8055_AI1_REG; @@ -549,48 +332,45 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev, default: reg[0] = VMK8061_AI_REG1; reg[1] = VMK8061_AI_REG2; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI; - dev->usb_tx_buf[VMK8061_CH_REG] = chan; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI; + devpriv->usb_tx_buf[VMK8061_CH_REG] = chan; break; } for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) + if (vmk80xx_read_packet(devpriv)) break; - if (dev->board.model == VMK8055_MODEL) { - data[n] = dev->usb_rx_buf[reg[0]]; + if (devpriv->model == VMK8055_MODEL) { + data[n] = devpriv->usb_rx_buf[reg[0]]; continue; } /* VMK8061_MODEL */ - data[n] = dev->usb_rx_buf[reg[0]] + 256 * - dev->usb_rx_buf[reg[1]]; + data[n] = devpriv->usb_rx_buf[reg[0]] + 256 * + devpriv->usb_rx_buf[reg[1]]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_ao_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int cmd; int reg; int n; - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); - switch (dev->board.model) { + switch (devpriv->model) { case VMK8055_MODEL: cmd = VMK8055_CMD_WRT_AD; if (!chan) @@ -601,82 +381,76 @@ static int vmk80xx_ao_winsn(struct comedi_device *cdev, default: /* NOTE: avoid compiler warnings */ cmd = VMK8061_CMD_SET_AO; reg = VMK8061_AO_REG; - dev->usb_tx_buf[VMK8061_CH_REG] = chan; + devpriv->usb_tx_buf[VMK8061_CH_REG] = chan; break; } for (n = 0; n < insn->n; n++) { - dev->usb_tx_buf[reg] = data[n]; + devpriv->usb_tx_buf[reg] = data[n]; - if (vmk80xx_write_packet(dev, cmd)) + if (vmk80xx_write_packet(devpriv, cmd)) break; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_ao_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int reg; int n; - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); reg = VMK8061_AO_REG - 1; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO; for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) + if (vmk80xx_read_packet(devpriv)) break; - data[n] = dev->usb_rx_buf[reg + chan]; + data[n] = devpriv->usb_rx_buf[reg + chan]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_di_bits(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned char *rx_buf; int reg; int retval; - retval = rudimentary_check(dev, DIR_IN); - if (retval) - return retval; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); - rx_buf = dev->usb_rx_buf; + rx_buf = devpriv->usb_rx_buf; - if (dev->board.model == VMK8061_MODEL) { + if (devpriv->model == VMK8061_MODEL) { reg = VMK8061_DI_REG; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI; } else { reg = VMK8055_DI_REG; } - retval = vmk80xx_read_packet(dev); + retval = vmk80xx_read_packet(devpriv); if (!retval) { - if (dev->board.model == VMK8055_MODEL) + if (devpriv->model == VMK8055_MODEL) data[1] = (((rx_buf[reg] >> 4) & 0x03) | ((rx_buf[reg] << 2) & 0x04) | ((rx_buf[reg] >> 3) & 0x18)); @@ -686,185 +460,48 @@ static int vmk80xx_di_bits(struct comedi_device *cdev, retval = 2; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return retval; } -static int vmk80xx_di_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; - int chan; - unsigned char *rx_buf; - int reg; - int inp; - int n; - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); - chan = CR_CHAN(insn->chanspec); - - rx_buf = dev->usb_rx_buf; - - if (dev->board.model == VMK8061_MODEL) { - reg = VMK8061_DI_REG; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; - } else { - reg = VMK8055_DI_REG; - } - for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) - break; - - if (dev->board.model == VMK8055_MODEL) - inp = (((rx_buf[reg] >> 4) & 0x03) | - ((rx_buf[reg] << 2) & 0x04) | - ((rx_buf[reg] >> 3) & 0x18)); - else - inp = rx_buf[reg]; - - data[n] = (inp >> chan) & 1; - } - - up(&dev->limit_sem); - - return n; -} - -static int vmk80xx_do_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct vmk80xx_usb *dev = cdev->private; - int chan; - unsigned char *tx_buf; - int reg; - int cmd; - int n; - - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); - chan = CR_CHAN(insn->chanspec); - - tx_buf = dev->usb_tx_buf; - - for (n = 0; n < insn->n; n++) { - if (dev->board.model == VMK8055_MODEL) { - reg = VMK8055_DO_REG; - cmd = VMK8055_CMD_WRT_AD; - if (data[n] == 1) - tx_buf[reg] |= (1 << chan); - else - tx_buf[reg] ^= (1 << chan); - } else { /* VMK8061_MODEL */ - reg = VMK8061_DO_REG; - if (data[n] == 1) { - cmd = VMK8061_CMD_SET_DO; - tx_buf[reg] = 1 << chan; - } else { - cmd = VMK8061_CMD_CLR_DO; - tx_buf[reg] = 0xff - (1 << chan); - } - } - - if (vmk80xx_write_packet(dev, cmd)) - break; - } - - up(&dev->limit_sem); - - return n; -} - -static int vmk80xx_do_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct vmk80xx_usb *dev = cdev->private; - int chan; - int reg; - int n; - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); - chan = CR_CHAN(insn->chanspec); - - reg = VMK8061_DO_REG; - - dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO; - - for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) - break; - - data[n] = (dev->usb_rx_buf[reg] >> chan) & 1; - } - - up(&dev->limit_sem); - - return n; -} - -static int vmk80xx_do_bits(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned char *rx_buf, *tx_buf; - int dir, reg, cmd; + int reg, cmd; int retval; - dir = 0; - - if (data[0]) - dir |= DIR_OUT; - - if (dev->board.model == VMK8061_MODEL) - dir |= DIR_IN; - - retval = rudimentary_check(dev, dir); - if (retval) - return retval; + if (devpriv->model == VMK8061_MODEL) { + reg = VMK8061_DO_REG; + cmd = VMK8061_CMD_DO; + } else { /* VMK8055_MODEL */ + reg = VMK8055_DO_REG; + cmd = VMK8055_CMD_WRT_AD; + } - down(&dev->limit_sem); + down(&devpriv->limit_sem); - rx_buf = dev->usb_rx_buf; - tx_buf = dev->usb_tx_buf; + rx_buf = devpriv->usb_rx_buf; + tx_buf = devpriv->usb_tx_buf; if (data[0]) { - if (dev->board.model == VMK8055_MODEL) { - reg = VMK8055_DO_REG; - cmd = VMK8055_CMD_WRT_AD; - } else { /* VMK8061_MODEL */ - reg = VMK8061_DO_REG; - cmd = VMK8061_CMD_DO; - } - tx_buf[reg] &= ~data[0]; tx_buf[reg] |= (data[0] & data[1]); - retval = vmk80xx_write_packet(dev, cmd); + retval = vmk80xx_write_packet(devpriv, cmd); if (retval) goto out; } - if (dev->board.model == VMK8061_MODEL) { - reg = VMK8061_DO_REG; + if (devpriv->model == VMK8061_MODEL) { tx_buf[0] = VMK8061_CMD_RD_DO; - retval = vmk80xx_read_packet(dev); + retval = vmk80xx_read_packet(devpriv); if (!retval) { data[1] = rx_buf[reg]; @@ -876,28 +513,25 @@ static int vmk80xx_do_bits(struct comedi_device *cdev, } out: - up(&dev->limit_sem); + up(&devpriv->limit_sem); return retval; } -static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_cnt_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int reg[2]; int n; - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); - switch (dev->board.model) { + switch (devpriv->model) { case VMK8055_MODEL: if (!chan) reg[0] = VMK8055_CNT1_REG; @@ -908,50 +542,47 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, default: reg[0] = VMK8061_CNT_REG; reg[1] = VMK8061_CNT_REG; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT; break; } for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) + if (vmk80xx_read_packet(devpriv)) break; - if (dev->board.model == VMK8055_MODEL) - data[n] = dev->usb_rx_buf[reg[0]]; + if (devpriv->model == VMK8055_MODEL) + data[n] = devpriv->usb_rx_buf[reg[0]]; else /* VMK8061_MODEL */ - data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1] - + 256 * dev->usb_rx_buf[reg[1] * 2 + 2]; + data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1] + + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_cnt_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned int insn_cmd; int chan; int cmd; int reg; int n; - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - insn_cmd = data[0]; if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET) return -EINVAL; - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); - if (dev->board.model == VMK8055_MODEL) { + if (devpriv->model == VMK8055_MODEL) { if (!chan) { cmd = VMK8055_CMD_RST_CNT1; reg = VMK8055_CNT1_REG; @@ -960,36 +591,33 @@ static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, reg = VMK8055_CNT2_REG; } - dev->usb_tx_buf[reg] = 0x00; + devpriv->usb_tx_buf[reg] = 0x00; } else { cmd = VMK8061_CMD_RST_CNT; } for (n = 0; n < insn->n; n++) - if (vmk80xx_write_packet(dev, cmd)) + if (vmk80xx_write_packet(devpriv, cmd)) break; - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_cnt_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_cnt_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned long debtime; unsigned long val; int chan; int cmd; int n; - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); if (!chan) @@ -1010,65 +638,64 @@ static int vmk80xx_cnt_winsn(struct comedi_device *cdev, if (((val + 1) * val) < debtime * 1000 / 115) val += 1; - dev->usb_tx_buf[6 + chan] = val; + devpriv->usb_tx_buf[6 + chan] = val; - if (vmk80xx_write_packet(dev, cmd)) + if (vmk80xx_write_packet(devpriv, cmd)) break; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_pwm_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_pwm_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; + unsigned char *tx_buf; + unsigned char *rx_buf; int reg[2]; int n; - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; + down(&devpriv->limit_sem); - down(&dev->limit_sem); + tx_buf = devpriv->usb_tx_buf; + rx_buf = devpriv->usb_rx_buf; reg[0] = VMK8061_PWM_REG1; reg[1] = VMK8061_PWM_REG2; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM; + tx_buf[0] = VMK8061_CMD_RD_PWM; for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) + if (vmk80xx_read_packet(devpriv)) break; - data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]]; + data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_pwm_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_pwm_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned char *tx_buf; int reg[2]; int cmd; int n; - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); - tx_buf = dev->usb_tx_buf; + tx_buf = devpriv->usb_tx_buf; reg[0] = VMK8061_PWM_REG1; reg[1] = VMK8061_PWM_REG2; @@ -1092,341 +719,236 @@ static int vmk80xx_pwm_winsn(struct comedi_device *cdev, tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03); tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff; - if (vmk80xx_write_packet(dev, cmd)) + if (vmk80xx_write_packet(devpriv, cmd)) break; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_attach_common(struct comedi_device *cdev, - struct vmk80xx_usb *dev) +static int vmk80xx_find_usb_endpoints(struct comedi_device *dev) { - int n_subd; - struct comedi_subdevice *s; - int ret; + struct vmk80xx_private *devpriv = dev->private; + struct usb_interface *intf = devpriv->intf; + struct usb_host_interface *iface_desc = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_desc; + int i; - down(&dev->limit_sem); - cdev->board_name = dev->board.name; - cdev->private = dev; - if (dev->board.model == VMK8055_MODEL) - n_subd = 5; - else - n_subd = 6; - ret = comedi_alloc_subdevices(cdev, n_subd); - if (ret) { - up(&dev->limit_sem); - return ret; - } - /* Analog input subdevice */ - s = &cdev->subdevices[VMK80XX_SUBD_AI]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = dev->board.ai_chans; - s->maxdata = (1 << dev->board.ai_bits) - 1; - s->range_table = dev->board.range; - s->insn_read = vmk80xx_ai_rinsn; - /* Analog output subdevice */ - s = &cdev->subdevices[VMK80XX_SUBD_AO]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; - s->n_chan = dev->board.ao_chans; - s->maxdata = (1 << dev->board.ao_bits) - 1; - s->range_table = dev->board.range; - s->insn_write = vmk80xx_ao_winsn; - if (dev->board.model == VMK8061_MODEL) { - s->subdev_flags |= SDF_READABLE; - s->insn_read = vmk80xx_ao_rinsn; - } - /* Digital input subdevice */ - s = &cdev->subdevices[VMK80XX_SUBD_DI]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = dev->board.di_chans; - s->maxdata = 1; - s->insn_read = vmk80xx_di_rinsn; - s->insn_bits = vmk80xx_di_bits; - /* Digital output subdevice */ - s = &cdev->subdevices[VMK80XX_SUBD_DO]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; - s->n_chan = dev->board.do_chans; - s->maxdata = 1; - s->insn_write = vmk80xx_do_winsn; - s->insn_bits = vmk80xx_do_bits; - if (dev->board.model == VMK8061_MODEL) { - s->subdev_flags |= SDF_READABLE; - s->insn_read = vmk80xx_do_rinsn; - } - /* Counter subdevice */ - s = &cdev->subdevices[VMK80XX_SUBD_CNT]; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE; - s->n_chan = dev->board.cnt_chans; - s->insn_read = vmk80xx_cnt_rinsn; - s->insn_config = vmk80xx_cnt_cinsn; - if (dev->board.model == VMK8055_MODEL) { - s->subdev_flags |= SDF_WRITEABLE; - s->maxdata = (1 << dev->board.cnt_bits) - 1; - s->insn_write = vmk80xx_cnt_winsn; - } - /* PWM subdevice */ - if (dev->board.model == VMK8061_MODEL) { - s = &cdev->subdevices[VMK80XX_SUBD_PWM]; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; - s->n_chan = dev->board.pwm_chans; - s->maxdata = (1 << dev->board.pwm_bits) - 1; - s->insn_read = vmk80xx_pwm_rinsn; - s->insn_write = vmk80xx_pwm_winsn; - } - dev->attached = 1; - dev_info(cdev->class_dev, "vmk80xx: board #%d [%s] attached\n", - dev->count, dev->board.name); - up(&dev->limit_sem); - return 0; -} + if (iface_desc->desc.bNumEndpoints != 2) + return -ENODEV; -/* called for COMEDI_DEVCONFIG ioctl for board_name "vmk80xx" */ -static int vmk80xx_attach(struct comedi_device *cdev, - struct comedi_devconfig *it) -{ - int i; - int ret; + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + ep_desc = &iface_desc->endpoint[i].desc; - mutex_lock(&glb_mutex); - for (i = 0; i < VMK80XX_MAX_BOARDS; i++) - if (vmb[i].probed && !vmb[i].attached) - break; - if (i == VMK80XX_MAX_BOARDS) - ret = -ENODEV; - else - ret = vmk80xx_attach_common(cdev, &vmb[i]); - mutex_unlock(&glb_mutex); - return ret; -} + if (usb_endpoint_is_int_in(ep_desc) || + usb_endpoint_is_bulk_in(ep_desc)) { + if (!devpriv->ep_rx) + devpriv->ep_rx = ep_desc; + continue; + } -/* called via comedi_usb_auto_config() */ -static int vmk80xx_auto_attach(struct comedi_device *cdev, - unsigned long context_unused) -{ - struct usb_interface *intf = comedi_to_usb_interface(cdev); - int i; - int ret; + if (usb_endpoint_is_int_out(ep_desc) || + usb_endpoint_is_bulk_out(ep_desc)) { + if (!devpriv->ep_tx) + devpriv->ep_tx = ep_desc; + continue; + } + } - mutex_lock(&glb_mutex); - for (i = 0; i < VMK80XX_MAX_BOARDS; i++) - if (vmb[i].probed && vmb[i].intf == intf) - break; - if (i == VMK80XX_MAX_BOARDS) - ret = -ENODEV; - else if (vmb[i].attached) - ret = -EBUSY; - else - ret = vmk80xx_attach_common(cdev, &vmb[i]); - mutex_unlock(&glb_mutex); - return ret; + if (!devpriv->ep_rx || !devpriv->ep_tx) + return -ENODEV; + + return 0; } -static void vmk80xx_detach(struct comedi_device *dev) +static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev) { - struct vmk80xx_usb *usb = dev->private; + struct vmk80xx_private *devpriv = dev->private; + size_t size; + + size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize); + devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL); + if (!devpriv->usb_rx_buf) + return -ENOMEM; - if (usb) { - down(&usb->limit_sem); - dev->private = NULL; - usb->attached = 0; - up(&usb->limit_sem); + size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize); + devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL); + if (!devpriv->usb_tx_buf) { + kfree(devpriv->usb_rx_buf); + return -ENOMEM; } -} -static struct comedi_driver vmk80xx_driver = { - .module = THIS_MODULE, - .driver_name = "vmk80xx", - .attach = vmk80xx_attach, - .detach = vmk80xx_detach, - .auto_attach = vmk80xx_auto_attach, -}; + return 0; +} -static int vmk80xx_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int vmk80xx_init_subdevices(struct comedi_device *dev) { - int i; - struct vmk80xx_usb *dev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *ep_desc; - size_t size; - - mutex_lock(&glb_mutex); + const struct vmk80xx_board *boardinfo = comedi_board(dev); + struct vmk80xx_private *devpriv = dev->private; + struct comedi_subdevice *s; + int n_subd; + int ret; - for (i = 0; i < VMK80XX_MAX_BOARDS; i++) - if (!vmb[i].probed) - break; + down(&devpriv->limit_sem); - if (i == VMK80XX_MAX_BOARDS) { - mutex_unlock(&glb_mutex); - return -EMFILE; + if (devpriv->model == VMK8055_MODEL) + n_subd = 5; + else + n_subd = 6; + ret = comedi_alloc_subdevices(dev, n_subd); + if (ret) { + up(&devpriv->limit_sem); + return ret; } - dev = &vmb[i]; + /* Analog input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = boardinfo->ai_nchans; + s->maxdata = boardinfo->ai_maxdata; + s->range_table = boardinfo->range; + s->insn_read = vmk80xx_ai_insn_read; - memset(dev, 0x00, sizeof(struct vmk80xx_usb)); - dev->count = i; + /* Analog output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->n_chan = boardinfo->ao_nchans; + s->maxdata = 0x00ff; + s->range_table = boardinfo->range; + s->insn_write = vmk80xx_ao_insn_write; + if (devpriv->model == VMK8061_MODEL) { + s->subdev_flags |= SDF_READABLE; + s->insn_read = vmk80xx_ao_insn_read; + } - iface_desc = intf->cur_altsetting; - if (iface_desc->desc.bNumEndpoints != 2) - goto error; + /* Digital input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = boardinfo->di_nchans; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = vmk80xx_di_insn_bits; - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - ep_desc = &iface_desc->endpoint[i].desc; + /* Digital output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = vmk80xx_do_insn_bits; - if (usb_endpoint_is_int_in(ep_desc)) { - dev->ep_rx = ep_desc; - continue; - } + /* Counter subdevice */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 2; + s->maxdata = boardinfo->cnt_maxdata; + s->insn_read = vmk80xx_cnt_insn_read; + s->insn_config = vmk80xx_cnt_insn_config; + if (devpriv->model == VMK8055_MODEL) { + s->subdev_flags |= SDF_WRITEABLE; + s->insn_write = vmk80xx_cnt_insn_write; + } - if (usb_endpoint_is_int_out(ep_desc)) { - dev->ep_tx = ep_desc; - continue; - } + /* PWM subdevice */ + if (devpriv->model == VMK8061_MODEL) { + s = &dev->subdevices[5]; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->n_chan = boardinfo->pwm_nchans; + s->maxdata = boardinfo->pwm_maxdata; + s->insn_read = vmk80xx_pwm_insn_read; + s->insn_write = vmk80xx_pwm_insn_write; + } - if (usb_endpoint_is_bulk_in(ep_desc)) { - dev->ep_rx = ep_desc; - continue; - } + up(&devpriv->limit_sem); - if (usb_endpoint_is_bulk_out(ep_desc)) { - dev->ep_tx = ep_desc; - continue; - } - } + return 0; +} - if (!dev->ep_rx || !dev->ep_tx) - goto error; +static int vmk80xx_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + const struct vmk80xx_board *boardinfo; + struct vmk80xx_private *devpriv; + int ret; - size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); - dev->usb_rx_buf = kmalloc(size, GFP_KERNEL); - if (!dev->usb_rx_buf) { - mutex_unlock(&glb_mutex); - return -ENOMEM; - } + boardinfo = &vmk80xx_boardinfo[context]; + dev->board_ptr = boardinfo; + dev->board_name = boardinfo->name; - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - dev->usb_tx_buf = kmalloc(size, GFP_KERNEL); - if (!dev->usb_tx_buf) { - kfree(dev->usb_rx_buf); - mutex_unlock(&glb_mutex); + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) return -ENOMEM; - } - - dev->udev = interface_to_usbdev(intf); - dev->intf = intf; - - sema_init(&dev->limit_sem, 8); - init_waitqueue_head(&dev->read_wait); - init_waitqueue_head(&dev->write_wait); - - init_usb_anchor(&dev->rx_anchor); - init_usb_anchor(&dev->tx_anchor); - - usb_set_intfdata(intf, dev); - - switch (id->driver_info) { - case DEVICE_VMK8055: - dev->board.name = "K8055 (VM110)"; - dev->board.model = VMK8055_MODEL; - dev->board.range = &vmk8055_range; - dev->board.ai_chans = 2; - dev->board.ai_bits = 8; - dev->board.ao_chans = 2; - dev->board.ao_bits = 8; - dev->board.di_chans = 5; - dev->board.di_bits = 1; - dev->board.do_chans = 8; - dev->board.do_bits = 1; - dev->board.cnt_chans = 2; - dev->board.cnt_bits = 16; - dev->board.pwm_chans = 0; - dev->board.pwm_bits = 0; - break; - case DEVICE_VMK8061: - dev->board.name = "K8061 (VM140)"; - dev->board.model = VMK8061_MODEL; - dev->board.range = &vmk8061_range; - dev->board.ai_chans = 8; - dev->board.ai_bits = 10; - dev->board.ao_chans = 8; - dev->board.ao_bits = 8; - dev->board.di_chans = 8; - dev->board.di_bits = 1; - dev->board.do_chans = 8; - dev->board.do_bits = 1; - dev->board.cnt_chans = 2; - dev->board.cnt_bits = 0; - dev->board.pwm_chans = 1; - dev->board.pwm_bits = 10; - break; - } + dev->private = devpriv; - if (dev->board.model == VMK8061_MODEL) { - vmk80xx_read_eeprom(dev, IC3_VERSION); - dev_info(&intf->dev, "%s\n", dev->fw.ic3_vers); + devpriv->usb = interface_to_usbdev(intf); + devpriv->intf = intf; + devpriv->model = boardinfo->model; - if (vmk80xx_check_data_link(dev)) { - vmk80xx_read_eeprom(dev, IC6_VERSION); - dev_info(&intf->dev, "%s\n", dev->fw.ic6_vers); - } else { - dbgcm("comedi#: vmk80xx: no conn. to CPU\n"); - } - } + ret = vmk80xx_find_usb_endpoints(dev); + if (ret) + return ret; - if (dev->board.model == VMK8055_MODEL) - vmk80xx_reset_device(dev); + ret = vmk80xx_alloc_usb_buffers(dev); + if (ret) + return ret; - dev->probed = 1; + sema_init(&devpriv->limit_sem, 8); - dev_info(&intf->dev, "board #%d [%s] now attached\n", - dev->count, dev->board.name); + usb_set_intfdata(intf, devpriv); - mutex_unlock(&glb_mutex); + if (devpriv->model == VMK8061_MODEL) { + vmk80xx_read_eeprom(devpriv, IC3_VERSION); + dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers); - comedi_usb_auto_config(intf, &vmk80xx_driver); + if (vmk80xx_check_data_link(devpriv)) { + vmk80xx_read_eeprom(devpriv, IC6_VERSION); + dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers); + } + } - return 0; -error: - mutex_unlock(&glb_mutex); + if (devpriv->model == VMK8055_MODEL) + vmk80xx_reset_device(devpriv); - return -ENODEV; + return vmk80xx_init_subdevices(dev); } -static void vmk80xx_usb_disconnect(struct usb_interface *intf) +static void vmk80xx_detach(struct comedi_device *dev) { - struct vmk80xx_usb *dev = usb_get_intfdata(intf); + struct vmk80xx_private *devpriv = dev->private; - if (!dev) + if (!devpriv) return; - comedi_usb_auto_unconfig(intf); - - mutex_lock(&glb_mutex); - down(&dev->limit_sem); + down(&devpriv->limit_sem); - dev->probed = 0; - usb_set_intfdata(dev->intf, NULL); + usb_set_intfdata(devpriv->intf, NULL); - usb_kill_anchored_urbs(&dev->rx_anchor); - usb_kill_anchored_urbs(&dev->tx_anchor); + kfree(devpriv->usb_rx_buf); + kfree(devpriv->usb_tx_buf); - kfree(dev->usb_rx_buf); - kfree(dev->usb_tx_buf); + up(&devpriv->limit_sem); +} - dev_info(&intf->dev, "board #%d [%s] now detached\n", - dev->count, dev->board.name); +static struct comedi_driver vmk80xx_driver = { + .module = THIS_MODULE, + .driver_name = "vmk80xx", + .auto_attach = vmk80xx_auto_attach, + .detach = vmk80xx_detach, +}; - up(&dev->limit_sem); - mutex_unlock(&glb_mutex); +static int vmk80xx_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info); } static const struct usb_device_id vmk80xx_usb_id_table[] = { @@ -1446,13 +968,11 @@ static const struct usb_device_id vmk80xx_usb_id_table[] = { }; MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table); -/* TODO: Add support for suspend, resume, pre_reset, - * post_reset and flush */ static struct usb_driver vmk80xx_usb_driver = { .name = "vmk80xx", - .probe = vmk80xx_usb_probe, - .disconnect = vmk80xx_usb_disconnect, .id_table = vmk80xx_usb_id_table, + .probe = vmk80xx_usb_probe, + .disconnect = comedi_usb_auto_unconfig, }; module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver); diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index 4dc09a210883..8932a510d96c 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -42,7 +42,6 @@ MODULE_LICENSE("GPL"); struct comedi_device *comedi_open(const char *filename) { - struct comedi_device_file_info *dev_file_info; struct comedi_device *dev; unsigned int minor; @@ -54,12 +53,9 @@ struct comedi_device *comedi_open(const char *filename) if (minor >= COMEDI_NUM_BOARD_MINORS) return NULL; - dev_file_info = comedi_get_device_file_info(minor); - if (dev_file_info == NULL) - return NULL; - dev = dev_file_info->device; + dev = comedi_dev_from_minor(minor); - if (dev == NULL || !dev->attached) + if (!dev || !dev->attached) return NULL; if (!try_module_get(dev->driver->module)) diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c index 01acbe97653c..362c214bcc0b 100644 --- a/drivers/staging/comedi/proc.c +++ b/drivers/staging/comedi/proc.c @@ -33,7 +33,6 @@ #include <linux/proc_fs.h> #include <linux/string.h> -#ifdef CONFIG_PROC_FS static int comedi_read(char *buf, char **start, off_t offset, int len, int *eof, void *data) { @@ -49,13 +48,10 @@ static int comedi_read(char *buf, char **start, off_t offset, int len, "driver_name, board_name, n_subdevices"); for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(i); - struct comedi_device *dev; + struct comedi_device *dev = comedi_dev_from_minor(i); - if (dev_file_info == NULL) + if (!dev) continue; - dev = dev_file_info->device; if (dev->attached) { devices_q = 1; @@ -95,4 +91,3 @@ void comedi_proc_cleanup(void) { remove_proc_entry("comedi", NULL); } -#endif |