diff options
Diffstat (limited to 'drivers/staging/comedi')
176 files changed, 19990 insertions, 44757 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 8c8a5513225..a2f6957e7ee 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -96,11 +96,19 @@ config COMEDI_SKEL To compile this driver as a module, choose M here: the module will be called skel. +config COMEDI_SSV_DNP + tristate "SSV Embedded Systems DIL/Net-PC support" + depends on X86_32 || COMPILE_TEST + ---help--- + Enable support for SSV Embedded Systems DIL/Net-PC + + To compile this driver as a module, choose M here: the module will be + called ssv_dnp. + endif # COMEDI_MISC_DRIVERS menuconfig COMEDI_ISA_DRIVERS bool "Comedi ISA and PC/104 drivers" - depends on ISA ---help--- Enable comedi ISA and PC/104 drivers to be built @@ -122,8 +130,18 @@ config COMEDI_PCL724 tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO" select COMEDI_8255 ---help--- - Enable support for Advantech PCL-724, PCL-722, PCL-731 and - ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards + Enable support for ISA and PC/104 based 8255 digital i/o boards. This + driver provides a legacy comedi driver wrapper for the generic 8255 + support driver. + + Supported boards include: + Advantech PCL-724 24 channels + Advantech PCL-722 144 (or 96) channels + Advantech PCL-731 48 channels + ADlink ACL-7122 144 (or 96) channels + ADlink ACL-7124 24 channels + ADlink PET-48DIO 48 channels + WinSystems PCM-IO48 48 channels (PC/104) To compile this driver as a module, choose M here: the module will be called pcl724. @@ -142,16 +160,18 @@ config COMEDI_PCL730 Enable support for various simple ISA or PC/104 Digital I/O boards. These boards all use 8-bit I/O ports. - Advantech PCL-730 isolated - 16 in/16 out ttl - 16 in/16 out - ICP ISO-730 isolated - 16 in/16 out ttl - 16 in/16 out - ADlink ACL-7130 isolated - 16 in/16 out ttl - 16 in/16 out - Advantech PCM-3730 isolated - 8 in/8 out ttl - 16 in/16 out - Advantech PCL-725 isolated - 8 in/8 out - ICP P8R8-DIO isolated - 8 in/8 out - ADlink ACL-7225b isolated - 16 in/16 out - ICP P16R16-DIO isolated - 16 in/16 out - Advantech PCL-733 isolated - 32 in - Advantech PCL-734 isolated - 32 out + Advantech PCL-730 iso - 16 in/16 out ttl - 16 in/16 out + ICP ISO-730 iso - 16 in/16 out ttl - 16 in/16 out + ADlink ACL-7130 iso - 16 in/16 out ttl - 16 in/16 out + Advantech PCM-3730 iso - 8 in/8 out ttl - 16 in/16 out + Advantech PCL-725 iso - 8 in/8 out + ICP P8R8-DIO iso - 8 in/8 out + ADlink ACL-7225b iso - 16 in/16 out + ICP P16R16-DIO iso - 16 in/16 out + Advantech PCL-733 iso - 32 in + Advantech PCL-734 iso - 32 out + Diamond Systems OPMM-1616-XT iso - 16 in/16 out + Diamond Systems PEARL-MM-P iso - 16 out To compile this driver as a module, choose M here: the module will be called pcl730. @@ -159,6 +179,7 @@ config COMEDI_PCL730 config COMEDI_PCL812 tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" depends on VIRT_TO_BUS && ISA_DMA_API + select COMEDI_FC ---help--- Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, @@ -170,6 +191,7 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" depends on VIRT_TO_BUS && ISA_DMA_API + select COMEDI_FC ---help--- Enable support for Advantech PCL-814 and PCL-816 ISA cards @@ -179,6 +201,7 @@ config COMEDI_PCL816 config COMEDI_PCL818 tristate "Advantech PCL-718 and PCL-818 ISA card support" depends on VIRT_TO_BUS && ISA_DMA_API + select COMEDI_FC ---help--- Enable support for Advantech PCL-818 ISA cards PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 @@ -239,6 +262,14 @@ config COMEDI_RTI802 To compile this driver as a module, choose M here: the module will be called rti802. +config COMEDI_DAC02 + tristate "Keithley Metrabyte DAC02 compatible ISA card support" + ---help--- + Enable support for Keithley Metrabyte DAC02 compatible ISA cards. + + To compile this driver as a module, choose M here: the module will be + called dac02. + config COMEDI_DAS16M1 tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" select COMEDI_8255 @@ -377,6 +408,14 @@ config COMEDI_DMM32AT To compile this driver as a module, choose M here: the module will be called dmm32at. +config COMEDI_UNIOXX5 + tristate "Fastwel UNIOxx-5 analog and digital io board support" + ---help--- + Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards + + To compile this driver as a module, choose M here: the module will be + called unioxx5. + config COMEDI_FL512 tristate "FL512 ISA card support" ---help--- @@ -403,6 +442,15 @@ config COMEDI_AIO_IIRO_16 To compile this driver as a module, choose M here: the module will be called aio_iiro_16. +config COMEDI_II_PCI20KC + tristate "Intelligent Instruments PCI-20001C carrier support" + ---help--- + Enable support for Intelligent Instruments PCI-20001C carrier + PCI-20001, PCI-20006 and PCI-20341 + + To compile this driver as a module, choose M here: the module will be + called ii_pci20kc. + config COMEDI_C6XDIGIO tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support" ---help--- @@ -448,9 +496,9 @@ config COMEDI_NI_AT_AO config COMEDI_NI_ATMIO tristate "NI AT-MIO E series ISA-PNP card support" - depends on ISAPNP select COMEDI_8255 select COMEDI_NI_TIO + select COMEDI_FC ---help--- Enable support for National Instruments AT-MIO E series cards National Instruments AT-MIO-16E-1 (ni_atmio), @@ -461,11 +509,10 @@ config COMEDI_NI_ATMIO called ni_atmio. config COMEDI_NI_ATMIO16D - tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support" - depends on ISAPNP + tristate "NI AT-MIO-16/AT-MIO-16D series ISA card support" select COMEDI_8255 ---help--- - Enable support for National Instruments AT-MIO16/AT-MIO16D cards. + Enable support for National Instruments AT-MIO-16/AT-MIO-16D cards. To compile this driver as a module, choose M here: the module will be called ni_atmio16d. @@ -473,7 +520,7 @@ config COMEDI_NI_ATMIO16D config COMEDI_NI_LABPC_ISA tristate "NI Lab-PC and compatibles ISA support" select COMEDI_NI_LABPC - depends on VIRT_TO_BUS + select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API && VIRT_TO_BUS ---help--- Enable support for National Instruments Lab-PC and compatibles Lab-PC-1200, Lab-PC-1200AI, Lab-PC+. @@ -525,15 +572,6 @@ config COMEDI_MULTIQ3 To compile this driver as a module, choose M here: the module will be called multiq3. -config COMEDI_POC - tristate "Generic driver for very simple devices" - ---help--- - Enable generic support for very simple / POC (Piece of Crap) boards, - Keithley Metrabyte DAC-02 (dac02). - - To compile this driver as a module, choose M here: the module will be - called poc. - config COMEDI_S526 tristate "Sensoray s526 support" ---help--- @@ -613,6 +651,7 @@ config COMEDI_ADDI_APCI_1516 config COMEDI_ADDI_APCI_1564 tristate "ADDI-DATA APCI_1564 support" + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI_1564 cards @@ -719,6 +758,7 @@ config COMEDI_ADL_PCI9118 config COMEDI_ADV_PCI1710 tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support" + select COMEDI_FC ---help--- Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720 and PCI-1731 @@ -822,6 +862,7 @@ config COMEDI_DAS08_PCI config COMEDI_DT3000 tristate "Data Translation DT3000 series support" + select COMEDI_FC ---help--- Enable support for Data Translation DT3000 series DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and @@ -839,14 +880,6 @@ config COMEDI_DYNA_PCI10XX To compile this driver as a module, choose M here: the module will be called dyna_pci10xx. -config COMEDI_UNIOXX5 - tristate "Fastwel UNIOxx-5 analog and digital io board support" - ---help--- - Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards - - To compile this driver as a module, choose M here: the module will be - called unioxx5. - config COMEDI_GSC_HPDI tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support" select COMEDI_FC @@ -858,6 +891,12 @@ config COMEDI_GSC_HPDI To compile this driver as a module, choose M here: the module will be called gsc_hpdi. +config COMEDI_MF6X4 + tristate "Humusoft MF634 and MF624 DAQ Card support" + ---help--- + This driver supports both Humusoft MF634 and MF624 Data acquisition + cards. The legacy Humusoft MF614 card is not supported. + config COMEDI_ICP_MULTI tristate "Inova ICP_MULTI support" ---help--- @@ -866,15 +905,6 @@ config COMEDI_ICP_MULTI To compile this driver as a module, choose M here: the module will be called icp_multi. -config COMEDI_II_PCI20KC - tristate "Intelligent Instruments PCI-20001C carrier support" - ---help--- - Enable support for Intelligent Instruments PCI-20001C carrier - PCI-20001, PCI-20006 and PCI-20341 - - To compile this driver as a module, choose M here: the module will be - called ii_pci20kc. - config COMEDI_DAQBOARD2000 tristate "IOtech DAQboard/2000 support" select COMEDI_8255 @@ -974,8 +1004,6 @@ config COMEDI_ME_DAQ config COMEDI_NI_6527 tristate "NI 6527 support" - depends on HAS_DMA - select COMEDI_MITE ---help--- Enable support for the National Instruments 6527 PCI card @@ -1078,16 +1106,9 @@ config COMEDI_S626 To compile this driver as a module, choose M here: the module will be called s626. -config COMEDI_SSV_DNP - tristate "SSV Embedded Systems DIL/Net-PC support" - ---help--- - Enable support for SSV Embedded Systems DIL/Net-PC - - To compile this driver as a module, choose M here: the module will be - called ssv_dnp. - config COMEDI_MITE depends on HAS_DMA + select COMEDI_FC tristate config COMEDI_NI_TIOCMD @@ -1166,6 +1187,7 @@ config COMEDI_NI_MIO_CS config COMEDI_QUATECH_DAQP_CS tristate "Quatech DAQP PCMCIA data capture card support" + select COMEDI_FC ---help--- Enable support for the Quatech DAQP PCMCIA data capture cards DAQP-208 and DAQP-308 @@ -1262,6 +1284,9 @@ config COMEDI_NI_LABPC select COMEDI_8255 select COMEDI_FC +config COMEDI_NI_LABPC_ISADMA + tristate + config COMEDI_NI_TIO tristate diff --git a/drivers/staging/comedi/Makefile b/drivers/staging/comedi/Makefile index e6dfc98f8c8..fae2d909000 100644 --- a/drivers/staging/comedi/Makefile +++ b/drivers/staging/comedi/Makefile @@ -1,3 +1,5 @@ +ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG + comedi-y := comedi_fops.o range.o drivers.o \ comedi_buf.o comedi-$(CONFIG_COMEDI_PCI_DRIVERS) += comedi_pci.o diff --git a/drivers/staging/comedi/TODO b/drivers/staging/comedi/TODO index b10f739b7e3..b68fbdb5eeb 100644 --- a/drivers/staging/comedi/TODO +++ b/drivers/staging/comedi/TODO @@ -3,10 +3,9 @@ TODO: - Lindent - remove all wrappers - audit userspace interface - - reserve major number - cleanup the individual comedi drivers as well Please send patches to Greg Kroah-Hartman <greg@kroah.com> and copy: Ian Abbott <abbotti@mev.co.uk> - Frank Mori Hess <fmhess@users.sourceforge.net> + H Hartley Sweeten <hsweeten@visionengravers.com> diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index b4c001b6f88..df4a9c4bca3 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -15,6 +15,9 @@ * GNU General Public License for more details. */ +#include <linux/vmalloc.h> +#include <linux/slab.h> + #include "comedidev.h" #include "comedi_internal.h" @@ -24,31 +27,21 @@ #define COMEDI_PAGE_PROTECTION PAGE_KERNEL #endif -static void __comedi_buf_free(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned n_pages) +static void comedi_buf_map_kref_release(struct kref *kref) { - struct comedi_async *async = s->async; + struct comedi_buf_map *bm = + container_of(kref, struct comedi_buf_map, refcount); struct comedi_buf_page *buf; - unsigned i; + unsigned int 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) { + if (bm->page_list) { + for (i = 0; i < bm->n_pages; i++) { + buf = &bm->page_list[i]; clear_bit(PG_reserved, &(virt_to_page(buf->virt_addr)->flags)); - if (s->async_dma_dir != DMA_NONE) { + if (bm->dma_dir != DMA_NONE) { #ifdef CONFIG_HAS_DMA - dma_free_coherent(dev->hw_dev, + dma_free_coherent(bm->dma_hw_dev, PAGE_SIZE, buf->virt_addr, buf->dma_addr); @@ -57,10 +50,31 @@ static void __comedi_buf_free(struct comedi_device *dev, free_page((unsigned long)buf->virt_addr); } } + vfree(bm->page_list); } - vfree(async->buf_page_list); - async->buf_page_list = NULL; - async->n_buf_pages = 0; + if (bm->dma_dir != DMA_NONE) + put_device(bm->dma_hw_dev); + kfree(bm); +} + +static void __comedi_buf_free(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + struct comedi_buf_map *bm; + unsigned long flags; + + if (async->prealloc_buf) { + vunmap(async->prealloc_buf); + async->prealloc_buf = NULL; + async->prealloc_bufsz = 0; + } + + spin_lock_irqsave(&s->spin_lock, flags); + bm = async->buf_map; + async->buf_map = NULL; + spin_unlock_irqrestore(&s->spin_lock, flags); + comedi_buf_map_put(bm); } static void __comedi_buf_alloc(struct comedi_device *dev, @@ -69,7 +83,9 @@ static void __comedi_buf_alloc(struct comedi_device *dev, { struct comedi_async *async = s->async; struct page **pages = NULL; + struct comedi_buf_map *bm; struct comedi_buf_page *buf; + unsigned long flags; unsigned i; if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) { @@ -78,18 +94,31 @@ static void __comedi_buf_alloc(struct comedi_device *dev, return; } - async->buf_page_list = vzalloc(sizeof(*buf) * n_pages); - if (async->buf_page_list) + bm = kzalloc(sizeof(*async->buf_map), GFP_KERNEL); + if (!bm) + return; + + kref_init(&bm->refcount); + spin_lock_irqsave(&s->spin_lock, flags); + async->buf_map = bm; + spin_unlock_irqrestore(&s->spin_lock, flags); + bm->dma_dir = s->async_dma_dir; + if (bm->dma_dir != DMA_NONE) + /* Need ref to hardware device to free buffer later. */ + bm->dma_hw_dev = get_device(dev->hw_dev); + + bm->page_list = vzalloc(sizeof(*buf) * n_pages); + if (bm->page_list) pages = vmalloc(sizeof(struct page *) * n_pages); if (!pages) return; for (i = 0; i < n_pages; i++) { - buf = &async->buf_page_list[i]; - if (s->async_dma_dir != DMA_NONE) + buf = &bm->page_list[i]; + if (bm->dma_dir != DMA_NONE) #ifdef CONFIG_HAS_DMA - buf->virt_addr = dma_alloc_coherent(dev->hw_dev, + buf->virt_addr = dma_alloc_coherent(bm->dma_hw_dev, PAGE_SIZE, &buf->dma_addr, GFP_KERNEL | @@ -106,6 +135,9 @@ static void __comedi_buf_alloc(struct comedi_device *dev, pages[i] = virt_to_page(buf->virt_addr); } + spin_lock_irqsave(&s->spin_lock, flags); + bm->n_pages = i; + spin_unlock_irqrestore(&s->spin_lock, flags); /* vmap the prealloc_buf if all the pages were allocated */ if (i == n_pages) @@ -115,6 +147,49 @@ static void __comedi_buf_alloc(struct comedi_device *dev, vfree(pages); } +void comedi_buf_map_get(struct comedi_buf_map *bm) +{ + if (bm) + kref_get(&bm->refcount); +} + +int comedi_buf_map_put(struct comedi_buf_map *bm) +{ + if (bm) + return kref_put(&bm->refcount, comedi_buf_map_kref_release); + return 1; +} + +/* returns s->async->buf_map and increments its kref refcount */ +struct comedi_buf_map * +comedi_buf_map_from_subdev_get(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + struct comedi_buf_map *bm = NULL; + unsigned long flags; + + if (!async) + return NULL; + + spin_lock_irqsave(&s->spin_lock, flags); + bm = async->buf_map; + /* only want it if buffer pages allocated */ + if (bm && bm->n_pages) + comedi_buf_map_get(bm); + else + bm = NULL; + spin_unlock_irqrestore(&s->spin_lock, flags); + + return bm; +} + +bool comedi_buf_is_mmapped(struct comedi_subdevice *s) +{ + struct comedi_buf_map *bm = s->async->buf_map; + + return bm && (atomic_read(&bm->refcount.refcount) > 1); +} + int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { @@ -128,7 +203,7 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, return 0; /* deallocate old buffer */ - __comedi_buf_free(dev, s, async->n_buf_pages); + __comedi_buf_free(dev, s); /* allocate new buffer */ if (new_size) { @@ -138,18 +213,19 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, if (!async->prealloc_buf) { /* allocation failed */ - __comedi_buf_free(dev, s, n_pages); + __comedi_buf_free(dev, s); return -ENOMEM; } - async->n_buf_pages = n_pages; } async->prealloc_bufsz = new_size; return 0; } -void comedi_buf_reset(struct comedi_async *async) +void comedi_buf_reset(struct comedi_subdevice *s) { + struct comedi_async *async = s->async; + async->buf_write_alloc_count = 0; async->buf_write_count = 0; async->buf_read_alloc_count = 0; @@ -167,18 +243,20 @@ void comedi_buf_reset(struct comedi_async *async) async->events = 0; } -static unsigned int comedi_buf_write_n_available(struct comedi_async *async) +static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) { + struct comedi_async *async = s->async; unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; return free_end - async->buf_write_alloc_count; } -static unsigned int __comedi_buf_write_alloc(struct comedi_async *async, +static unsigned int __comedi_buf_write_alloc(struct comedi_subdevice *s, unsigned int nbytes, int strict) { - unsigned int available = comedi_buf_write_n_available(async); + struct comedi_async *async = s->async; + unsigned int available = comedi_buf_write_n_available(s); if (nbytes > available) nbytes = strict ? 0 : available; @@ -195,10 +273,10 @@ static unsigned int __comedi_buf_write_alloc(struct comedi_async *async, } /* allocates chunk for the writer from free buffer space */ -unsigned int comedi_buf_write_alloc(struct comedi_async *async, +unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, unsigned int nbytes) { - return __comedi_buf_write_alloc(async, nbytes, 0); + return __comedi_buf_write_alloc(s, nbytes, 0); } EXPORT_SYMBOL_GPL(comedi_buf_write_alloc); @@ -206,10 +284,10 @@ EXPORT_SYMBOL_GPL(comedi_buf_write_alloc); * munging is applied to data by core as it passes between user * and kernel space */ -static unsigned int comedi_buf_munge(struct comedi_async *async, +static unsigned int comedi_buf_munge(struct comedi_subdevice *s, unsigned int num_bytes) { - struct comedi_subdevice *s = async->subdevice; + struct comedi_async *async = s->async; unsigned int count = 0; const unsigned num_sample_bytes = bytes_per_sample(s); @@ -249,23 +327,26 @@ static unsigned int comedi_buf_munge(struct comedi_async *async, return count; } -unsigned int comedi_buf_write_n_allocated(struct comedi_async *async) +unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s) { + struct comedi_async *async = s->async; + return async->buf_write_alloc_count - async->buf_write_count; } /* transfers a chunk from writer to filled buffer space */ -unsigned int comedi_buf_write_free(struct comedi_async *async, +unsigned int comedi_buf_write_free(struct comedi_subdevice *s, unsigned int nbytes) { - unsigned int allocated = comedi_buf_write_n_allocated(async); + struct comedi_async *async = s->async; + unsigned int allocated = comedi_buf_write_n_allocated(s); if (nbytes > allocated) nbytes = allocated; async->buf_write_count += nbytes; async->buf_write_ptr += nbytes; - comedi_buf_munge(async, async->buf_write_count - async->munge_count); + comedi_buf_munge(s, async->buf_write_count - async->munge_count); if (async->buf_write_ptr >= async->prealloc_bufsz) async->buf_write_ptr %= async->prealloc_bufsz; @@ -273,8 +354,9 @@ unsigned int comedi_buf_write_free(struct comedi_async *async, } EXPORT_SYMBOL_GPL(comedi_buf_write_free); -unsigned int comedi_buf_read_n_available(struct comedi_async *async) +unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) { + struct comedi_async *async = s->async; unsigned num_bytes; if (!async) @@ -293,9 +375,10 @@ unsigned int comedi_buf_read_n_available(struct comedi_async *async) EXPORT_SYMBOL_GPL(comedi_buf_read_n_available); /* allocates a chunk for the reader from filled (and munged) buffer space */ -unsigned int comedi_buf_read_alloc(struct comedi_async *async, +unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, unsigned int nbytes) { + struct comedi_async *async = s->async; unsigned int available; available = async->munge_count - async->buf_read_alloc_count; @@ -320,9 +403,10 @@ static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async) } /* transfers control of a chunk from reader to free buffer space */ -unsigned int comedi_buf_read_free(struct comedi_async *async, +unsigned int comedi_buf_read_free(struct comedi_subdevice *s, unsigned int nbytes) { + struct comedi_async *async = s->async; unsigned int allocated; /* @@ -342,36 +426,39 @@ unsigned int comedi_buf_read_free(struct comedi_async *async, } EXPORT_SYMBOL_GPL(comedi_buf_read_free); -int comedi_buf_put(struct comedi_async *async, short x) +int comedi_buf_put(struct comedi_subdevice *s, unsigned short x) { - unsigned int n = __comedi_buf_write_alloc(async, sizeof(short), 1); + struct comedi_async *async = s->async; + unsigned int n = __comedi_buf_write_alloc(s, sizeof(short), 1); if (n < sizeof(short)) { async->events |= COMEDI_CB_ERROR; return 0; } - *(short *)(async->prealloc_buf + async->buf_write_ptr) = x; - comedi_buf_write_free(async, sizeof(short)); + *(unsigned short *)(async->prealloc_buf + async->buf_write_ptr) = x; + comedi_buf_write_free(s, sizeof(short)); return 1; } EXPORT_SYMBOL_GPL(comedi_buf_put); -int comedi_buf_get(struct comedi_async *async, short *x) +int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x) { - unsigned int n = comedi_buf_read_n_available(async); + struct comedi_async *async = s->async; + unsigned int n = comedi_buf_read_n_available(s); if (n < sizeof(short)) return 0; - comedi_buf_read_alloc(async, sizeof(short)); - *x = *(short *)(async->prealloc_buf + async->buf_read_ptr); - comedi_buf_read_free(async, sizeof(short)); + comedi_buf_read_alloc(s, sizeof(short)); + *x = *(unsigned short *)(async->prealloc_buf + async->buf_read_ptr); + comedi_buf_read_free(s, sizeof(short)); return 1; } EXPORT_SYMBOL_GPL(comedi_buf_get); -void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, +void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset, const void *data, unsigned int num_bytes) { + struct comedi_async *async = s->async; unsigned int write_ptr = async->buf_write_ptr + offset; if (write_ptr >= async->prealloc_bufsz) @@ -395,10 +482,11 @@ void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, } EXPORT_SYMBOL_GPL(comedi_buf_memcpy_to); -void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, +void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset, void *dest, unsigned int nbytes) { void *src; + struct comedi_async *async = s->async; unsigned int read_ptr = async->buf_read_ptr + offset; if (read_ptr >= async->prealloc_bufsz) diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index 2dfb06aedb1..1e9da405d83 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -86,9 +86,6 @@ struct comedi32_insnlist_struct { static int translated_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - if (!file->f_op) - return -ENOTTY; - if (file->f_op->unlocked_ioctl) return file->f_op->unlocked_ioctl(file, cmd, arg); diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 8647518259f..9d99fb3c18a 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -16,8 +16,6 @@ GNU General Public License for more details. */ -#undef DEBUG - #include "comedi_compat32.h" #include <linux/module.h> @@ -26,7 +24,6 @@ #include <linux/sched.h> #include <linux/fcntl.h> #include <linux/delay.h> -#include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/kmod.h> @@ -48,15 +45,6 @@ #define COMEDI_NUM_SUBDEVICE_MINORS \ (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS) -#ifdef CONFIG_COMEDI_DEBUG -int comedi_debug; -EXPORT_SYMBOL_GPL(comedi_debug); -module_param(comedi_debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(comedi_debug, - "enable comedi core and driver debugging if non-zero (default 0)" - ); -#endif - static int comedi_num_legacy_minors; module_param(comedi_num_legacy_minors, int, S_IRUGO); MODULE_PARM_DESC(comedi_num_legacy_minors, @@ -90,11 +78,38 @@ static struct cdev comedi_cdev; static void comedi_device_init(struct comedi_device *dev) { + kref_init(&dev->refcount); spin_lock_init(&dev->spinlock); mutex_init(&dev->mutex); + init_rwsem(&dev->attach_lock); dev->minor = -1; } +static void comedi_dev_kref_release(struct kref *kref) +{ + struct comedi_device *dev = + container_of(kref, struct comedi_device, refcount); + + mutex_destroy(&dev->mutex); + put_device(dev->class_dev); + kfree(dev); +} + +int comedi_dev_put(struct comedi_device *dev) +{ + if (dev) + return kref_put(&dev->refcount, comedi_dev_kref_release); + return 1; +} +EXPORT_SYMBOL_GPL(comedi_dev_put); + +static struct comedi_device *comedi_dev_get(struct comedi_device *dev) +{ + if (dev) + kref_get(&dev->refcount); + return dev; +} + static void comedi_device_cleanup(struct comedi_device *dev) { struct module *driver_module = NULL; @@ -105,14 +120,9 @@ static void comedi_device_cleanup(struct comedi_device *dev) if (dev->attached) driver_module = dev->driver->module; comedi_device_detach(dev); - while (dev->use_count > 0) { - if (driver_module) - module_put(driver_module); - module_put(THIS_MODULE); - dev->use_count--; - } + if (driver_module && dev->use_count) + module_put(driver_module); mutex_unlock(&dev->mutex); - mutex_destroy(&dev->mutex); } static bool comedi_clear_board_dev(struct comedi_device *dev) @@ -143,17 +153,17 @@ static struct comedi_device *comedi_clear_board_minor(unsigned minor) static void comedi_free_board_dev(struct comedi_device *dev) { if (dev) { + comedi_device_cleanup(dev); if (dev->class_dev) { device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, dev->minor)); } - comedi_device_cleanup(dev); - kfree(dev); + comedi_dev_put(dev); } } static struct comedi_subdevice -*comedi_subdevice_from_minor(unsigned minor) +*comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned minor) { struct comedi_subdevice *s; unsigned int i = minor - COMEDI_NUM_BOARD_MINORS; @@ -161,37 +171,45 @@ static struct comedi_subdevice BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS); mutex_lock(&comedi_subdevice_minor_table_lock); s = comedi_subdevice_minor_table[i]; + if (s && s->device != dev) + s = NULL; mutex_unlock(&comedi_subdevice_minor_table_lock); return s; } -static struct comedi_device *comedi_dev_from_board_minor(unsigned minor) +static struct comedi_device *comedi_dev_get_from_board_minor(unsigned minor) { struct comedi_device *dev; BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); mutex_lock(&comedi_board_minor_table_lock); - dev = comedi_board_minor_table[minor]; + dev = comedi_dev_get(comedi_board_minor_table[minor]); mutex_unlock(&comedi_board_minor_table_lock); return dev; } -static struct comedi_device *comedi_dev_from_subdevice_minor(unsigned minor) +static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor) { + struct comedi_device *dev; struct comedi_subdevice *s; + unsigned int i = minor - COMEDI_NUM_BOARD_MINORS; - s = comedi_subdevice_from_minor(minor); - return s ? s->device : NULL; + BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS); + mutex_lock(&comedi_subdevice_minor_table_lock); + s = comedi_subdevice_minor_table[i]; + dev = comedi_dev_get(s ? s->device : NULL); + mutex_unlock(&comedi_subdevice_minor_table_lock); + return dev; } -struct comedi_device *comedi_dev_from_minor(unsigned minor) +struct comedi_device *comedi_dev_get_from_minor(unsigned minor) { if (minor < COMEDI_NUM_BOARD_MINORS) - return comedi_dev_from_board_minor(minor); + return comedi_dev_get_from_board_minor(minor); else - return comedi_dev_from_subdevice_minor(minor); + return comedi_dev_get_from_subdevice_minor(minor); } -EXPORT_SYMBOL_GPL(comedi_dev_from_minor); +EXPORT_SYMBOL_GPL(comedi_dev_get_from_minor); static struct comedi_subdevice * comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor) @@ -199,10 +217,8 @@ comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor) struct comedi_subdevice *s; if (minor >= COMEDI_NUM_BOARD_MINORS) { - s = comedi_subdevice_from_minor(minor); - if (!s || s->device != dev) - return NULL; - if (s->subdev_flags & SDF_CMD_READ) + s = comedi_subdevice_from_minor(dev, minor); + if (s == NULL || (s->subdev_flags & SDF_CMD_READ)) return s; } return dev->read_subdev; @@ -214,30 +230,30 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor) struct comedi_subdevice *s; if (minor >= COMEDI_NUM_BOARD_MINORS) { - s = comedi_subdevice_from_minor(minor); - if (!s || s->device != dev) - return NULL; - if (s->subdev_flags & SDF_CMD_WRITE) + s = comedi_subdevice_from_minor(dev, minor); + if (s == NULL || (s->subdev_flags & SDF_CMD_WRITE)) return s; } return dev->write_subdev; } static int resize_async_buffer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_async *async, unsigned new_size) + struct comedi_subdevice *s, unsigned new_size) { + struct comedi_async *async = s->async; int retval; if (new_size > async->max_bufsize) return -EPERM; if (s->busy) { - DPRINTK("subdevice is busy, cannot resize buffer\n"); + dev_dbg(dev->class_dev, + "subdevice is busy, cannot resize buffer\n"); return -EBUSY; } - if (async->mmap_count) { - DPRINTK("subdevice is mmapped, cannot resize buffer\n"); + if (comedi_buf_is_mmapped(s)) { + dev_dbg(dev->class_dev, + "subdevice is mmapped, cannot resize buffer\n"); return -EBUSY; } @@ -255,14 +271,14 @@ static int resize_async_buffer(struct comedi_device *dev, return retval; } - DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", - dev->minor, s->index, async->prealloc_bufsz); + dev_dbg(dev->class_dev, "subd %d buffer resized to %i bytes\n", + s->index, async->prealloc_bufsz); return 0; } /* sysfs attribute files */ -static ssize_t show_max_read_buffer_kb(struct device *csdev, +static ssize_t max_read_buffer_kb_show(struct device *csdev, struct device_attribute *attr, char *buf) { unsigned int minor = MINOR(csdev->devt); @@ -270,7 +286,7 @@ static ssize_t show_max_read_buffer_kb(struct device *csdev, struct comedi_subdevice *s; unsigned int size = 0; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; @@ -280,10 +296,11 @@ static ssize_t show_max_read_buffer_kb(struct device *csdev, size = s->async->max_bufsize / 1024; mutex_unlock(&dev->mutex); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } -static ssize_t store_max_read_buffer_kb(struct device *csdev, +static ssize_t max_read_buffer_kb_store(struct device *csdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -300,7 +317,7 @@ static ssize_t store_max_read_buffer_kb(struct device *csdev, return -EINVAL; size *= 1024; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; @@ -312,10 +329,12 @@ static ssize_t store_max_read_buffer_kb(struct device *csdev, err = -EINVAL; mutex_unlock(&dev->mutex); + comedi_dev_put(dev); return err ? err : count; } +static DEVICE_ATTR_RW(max_read_buffer_kb); -static ssize_t show_read_buffer_kb(struct device *csdev, +static ssize_t read_buffer_kb_show(struct device *csdev, struct device_attribute *attr, char *buf) { unsigned int minor = MINOR(csdev->devt); @@ -323,7 +342,7 @@ static ssize_t show_read_buffer_kb(struct device *csdev, struct comedi_subdevice *s; unsigned int size = 0; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; @@ -333,10 +352,11 @@ static ssize_t show_read_buffer_kb(struct device *csdev, size = s->async->prealloc_bufsz / 1024; mutex_unlock(&dev->mutex); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } -static ssize_t store_read_buffer_kb(struct device *csdev, +static ssize_t read_buffer_kb_store(struct device *csdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -353,22 +373,24 @@ static ssize_t store_read_buffer_kb(struct device *csdev, return -EINVAL; size *= 1024; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; mutex_lock(&dev->mutex); s = comedi_read_subdevice(dev, minor); if (s && (s->subdev_flags & SDF_CMD_READ) && s->async) - err = resize_async_buffer(dev, s, s->async, size); + err = resize_async_buffer(dev, s, size); else err = -EINVAL; mutex_unlock(&dev->mutex); + comedi_dev_put(dev); return err ? err : count; } +static DEVICE_ATTR_RW(read_buffer_kb); -static ssize_t show_max_write_buffer_kb(struct device *csdev, +static ssize_t max_write_buffer_kb_show(struct device *csdev, struct device_attribute *attr, char *buf) { @@ -377,7 +399,7 @@ static ssize_t show_max_write_buffer_kb(struct device *csdev, struct comedi_subdevice *s; unsigned int size = 0; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; @@ -387,10 +409,11 @@ static ssize_t show_max_write_buffer_kb(struct device *csdev, size = s->async->max_bufsize / 1024; mutex_unlock(&dev->mutex); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } -static ssize_t store_max_write_buffer_kb(struct device *csdev, +static ssize_t max_write_buffer_kb_store(struct device *csdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -407,7 +430,7 @@ static ssize_t store_max_write_buffer_kb(struct device *csdev, return -EINVAL; size *= 1024; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; @@ -419,10 +442,12 @@ static ssize_t store_max_write_buffer_kb(struct device *csdev, err = -EINVAL; mutex_unlock(&dev->mutex); + comedi_dev_put(dev); return err ? err : count; } +static DEVICE_ATTR_RW(max_write_buffer_kb); -static ssize_t show_write_buffer_kb(struct device *csdev, +static ssize_t write_buffer_kb_show(struct device *csdev, struct device_attribute *attr, char *buf) { unsigned int minor = MINOR(csdev->devt); @@ -430,7 +455,7 @@ static ssize_t show_write_buffer_kb(struct device *csdev, struct comedi_subdevice *s; unsigned int size = 0; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; @@ -440,10 +465,11 @@ static ssize_t show_write_buffer_kb(struct device *csdev, size = s->async->prealloc_bufsz / 1024; mutex_unlock(&dev->mutex); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } -static ssize_t store_write_buffer_kb(struct device *csdev, +static ssize_t write_buffer_kb_store(struct device *csdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -460,32 +486,31 @@ static ssize_t store_write_buffer_kb(struct device *csdev, return -EINVAL; size *= 1024; - dev = comedi_dev_from_minor(minor); + dev = comedi_dev_get_from_minor(minor); if (!dev) return -ENODEV; mutex_lock(&dev->mutex); s = comedi_write_subdevice(dev, minor); if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async) - err = resize_async_buffer(dev, s, s->async, size); + err = resize_async_buffer(dev, s, size); else err = -EINVAL; mutex_unlock(&dev->mutex); + comedi_dev_put(dev); return err ? err : count; } +static DEVICE_ATTR_RW(write_buffer_kb); -static struct device_attribute comedi_dev_attrs[] = { - __ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR, - show_max_read_buffer_kb, store_max_read_buffer_kb), - __ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP, - show_read_buffer_kb, store_read_buffer_kb), - __ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR, - show_max_write_buffer_kb, store_max_write_buffer_kb), - __ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP, - show_write_buffer_kb, store_write_buffer_kb), - __ATTR_NULL +static struct attribute *comedi_dev_attrs[] = { + &dev_attr_max_read_buffer_kb.attr, + &dev_attr_read_buffer_kb.attr, + &dev_attr_max_write_buffer_kb.attr, + &dev_attr_write_buffer_kb.attr, + NULL, }; +ATTRIBUTE_GROUPS(comedi_dev); static void comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask, unsigned bits) @@ -543,7 +568,7 @@ void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size) { s->private = kzalloc(size, GFP_KERNEL); if (s->private) - comedi_set_subdevice_runflags(s, ~0, SRF_FREE_SPRIV); + s->runflags |= SRF_FREE_SPRIV; return s->private; } EXPORT_SYMBOL_GPL(comedi_alloc_spriv); @@ -558,16 +583,17 @@ static void do_become_nonbusy(struct comedi_device *dev, comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); if (async) { - comedi_buf_reset(async); + comedi_buf_reset(s); async->inttrig = NULL; kfree(async->cmd.chanlist); async->cmd.chanlist = NULL; + s->busy = NULL; + wake_up_interruptible_all(&s->async->wait_head); } else { dev_err(dev->class_dev, "BUG: (?) do_become_nonbusy called with async=NULL\n"); + s->busy = NULL; } - - s->busy = NULL; } static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) @@ -582,6 +608,21 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return ret; } +void comedi_device_cancel_all(struct comedi_device *dev) +{ + struct comedi_subdevice *s; + int i; + + if (!dev->attached) + return; + + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + if (s->async) + do_cancel(dev, s); + } +} + static int is_device_busy(struct comedi_device *dev) { struct comedi_subdevice *s; @@ -594,7 +635,7 @@ static int is_device_busy(struct comedi_device *dev) s = &dev->subdevices[i]; if (s->busy) return 1; - if (s->async && s->async->mmap_count) + if (s->async && comedi_buf_is_mmapped(s)) return 1; } @@ -627,6 +668,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev, return -EBUSY; if (dev->attached) { struct module *driver_module = dev->driver->module; + comedi_device_detach(dev); module_put(driver_module); } @@ -684,7 +726,8 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, async = s->async; if (!async) { - DPRINTK("subdevice does not have async capability\n"); + dev_dbg(dev->class_dev, + "subdevice does not have async capability\n"); bc.size = 0; bc.maximum_size = 0; goto copyback; @@ -698,7 +741,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, } if (bc.size) { - retval = resize_async_buffer(dev, s, async, bc.size); + retval = resize_async_buffer(dev, s, bc.size); if (retval < 0) return retval; } @@ -806,7 +849,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, } else { us->range_type = 0; /* XXX */ } - us->flags = s->flags; if (s->busy) us->subd_flags |= SDF_BUSY; @@ -818,8 +860,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->subd_flags |= SDF_LOCK_OWNER; if (!s->maxdata && s->maxdata_list) us->subd_flags |= SDF_MAXDATA; - if (s->flaglist) - us->subd_flags |= SDF_FLAGS; if (s->range_table_list) us->subd_flags |= SDF_RANGETYPE; if (s->do_cmd) @@ -829,8 +869,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->insn_bits_support = COMEDI_SUPPORTED; else us->insn_bits_support = COMEDI_UNSUPPORTED; - - us->settling_time_0 = s->settling_time_0; } ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp)); @@ -875,13 +913,8 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, return -EFAULT; } - if (it.flaglist) { - if (!s->flaglist) - return -EINVAL; - if (copy_to_user(it.flaglist, s->flaglist, - s->n_chan * sizeof(unsigned int))) - return -EFAULT; - } + if (it.flaglist) + return -EINVAL; /* flaglist not supported */ if (it.rangelist) { int i; @@ -941,7 +974,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, async = s->async; if (!async) { - DPRINTK("subdevice does not have async capability\n"); + dev_dbg(dev->class_dev, + "subdevice does not have async capability\n"); bi.buf_write_ptr = 0; bi.buf_read_ptr = 0; bi.buf_write_count = 0; @@ -959,8 +993,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, return -EACCES; if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) { - bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read); - comedi_buf_read_free(async, bi.bytes_read); + bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read); + comedi_buf_read_free(s, bi.bytes_read); if (comedi_is_subdevice_idle(s) && async->buf_write_count == async->buf_read_count) { @@ -970,8 +1004,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) { bi.bytes_written = - comedi_buf_write_alloc(async, bi.bytes_written); - comedi_buf_write_free(async, bi.bytes_written); + comedi_buf_write_alloc(s, bi.bytes_written); + comedi_buf_write_free(s, bi.bytes_written); } copyback_position: @@ -1093,19 +1127,20 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, break; } if (insn->subdev >= dev->n_subdevices) { - DPRINTK("%d not usable subdevice\n", + dev_dbg(dev->class_dev, + "%d not usable subdevice\n", insn->subdev); ret = -EINVAL; break; } s = &dev->subdevices[insn->subdev]; if (!s->async) { - DPRINTK("no async\n"); + dev_dbg(dev->class_dev, "no async\n"); ret = -EINVAL; break; } if (!s->async->inttrig) { - DPRINTK("no inttrig\n"); + dev_dbg(dev->class_dev, "no inttrig\n"); ret = -EAGAIN; break; } @@ -1114,7 +1149,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = 1; break; default: - DPRINTK("invalid insn\n"); + dev_dbg(dev->class_dev, "invalid insn\n"); ret = -EINVAL; break; } @@ -1123,21 +1158,23 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, unsigned int maxdata; if (insn->subdev >= dev->n_subdevices) { - DPRINTK("subdevice %d out of range\n", insn->subdev); + dev_dbg(dev->class_dev, "subdevice %d out of range\n", + insn->subdev); ret = -EINVAL; goto out; } s = &dev->subdevices[insn->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not usable subdevice\n", insn->subdev); + dev_dbg(dev->class_dev, "%d not usable subdevice\n", + insn->subdev); ret = -EIO; goto out; } /* are we locked? (ioctl lock) */ if (s->lock && s->lock != file) { - DPRINTK("device locked\n"); + dev_dbg(dev->class_dev, "device locked\n"); ret = -EACCES; goto out; } @@ -1145,7 +1182,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = comedi_check_chanlist(s, 1, &insn->chanspec); if (ret < 0) { ret = -EINVAL; - DPRINTK("bad chanspec\n"); + dev_dbg(dev->class_dev, "bad chanspec\n"); goto out; } @@ -1158,6 +1195,11 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, switch (insn->insn) { case INSN_READ: ret = s->insn_read(dev, s, insn, data); + if (ret == -ETIMEDOUT) { + dev_dbg(dev->class_dev, + "subdevice %d read instruction timed out\n", + s->index); + } break; case INSN_WRITE: maxdata = s->maxdata_list @@ -1166,12 +1208,19 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, for (i = 0; i < insn->n; ++i) { if (data[i] > maxdata) { ret = -EINVAL; - DPRINTK("bad data value(s)\n"); + dev_dbg(dev->class_dev, + "bad data value(s)\n"); break; } } - if (ret == 0) + if (ret == 0) { ret = s->insn_write(dev, s, insn, data); + if (ret == -ETIMEDOUT) { + dev_dbg(dev->class_dev, + "subdevice %d write instruction timed out\n", + s->index); + } + } break; case INSN_BITS: if (insn->n != 2) { @@ -1248,35 +1297,35 @@ static int do_insnlist_ioctl(struct comedi_device *dev, 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"); + dev_dbg(dev->class_dev, "copy_from_user failed\n"); ret = -EFAULT; goto error; } for (i = 0; i < insnlist.n_insns; i++) { if (insns[i].n > MAX_SAMPLES) { - DPRINTK("number of samples too large\n"); + dev_dbg(dev->class_dev, + "number of samples too large\n"); ret = -EINVAL; goto error; } if (insns[i].insn & INSN_MASK_WRITE) { if (copy_from_user(data, insns[i].data, insns[i].n * sizeof(unsigned int))) { - DPRINTK("copy_from_user failed\n"); + dev_dbg(dev->class_dev, + "copy_from_user failed\n"); ret = -EFAULT; goto error; } @@ -1287,7 +1336,8 @@ static int do_insnlist_ioctl(struct comedi_device *dev, 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"); + dev_dbg(dev->class_dev, + "copy_to_user failed\n"); ret = -EFAULT; goto error; } @@ -1367,107 +1417,133 @@ error: return ret; } -static int do_cmd_ioctl(struct comedi_device *dev, - struct comedi_cmd __user *arg, void *file) +static int __comedi_get_user_cmd(struct comedi_device *dev, + struct comedi_cmd __user *arg, + struct comedi_cmd *cmd) { - struct comedi_cmd cmd; struct comedi_subdevice *s; - struct comedi_async *async; - int ret = 0; - unsigned int __user *user_chanlist; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - DPRINTK("bad cmd address\n"); + if (copy_from_user(cmd, arg, sizeof(*cmd))) { + dev_dbg(dev->class_dev, "bad cmd address\n"); return -EFAULT; } - /* save user's chanlist pointer so it can be restored later */ - user_chanlist = (unsigned int __user *)cmd.chanlist; - if (cmd.subdev >= dev->n_subdevices) { - DPRINTK("%d no such subdevice\n", cmd.subdev); + if (cmd->subdev >= dev->n_subdevices) { + dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev); return -ENODEV; } - s = &dev->subdevices[cmd.subdev]; - async = s->async; + s = &dev->subdevices[cmd->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not valid subdevice\n", cmd.subdev); + dev_dbg(dev->class_dev, "%d not valid subdevice\n", + cmd->subdev); return -EIO; } if (!s->do_cmd || !s->do_cmdtest || !s->async) { - DPRINTK("subdevice %i does not support commands\n", - cmd.subdev); + dev_dbg(dev->class_dev, + "subdevice %d does not support commands\n", + cmd->subdev); return -EIO; } + /* make sure channel/gain list isn't too long */ + if (cmd->chanlist_len > s->len_chanlist) { + dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n", + cmd->chanlist_len, s->len_chanlist); + return -EINVAL; + } + + return 0; +} + +static int __comedi_get_user_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int __user *user_chanlist, + struct comedi_cmd *cmd) +{ + unsigned int *chanlist; + int ret; + + /* user_chanlist could be NULL for do_cmdtest ioctls */ + if (!user_chanlist) + return 0; + + chanlist = memdup_user(user_chanlist, + cmd->chanlist_len * sizeof(unsigned int)); + if (IS_ERR(chanlist)) + return PTR_ERR(chanlist); + + /* make sure each element in channel/gain list is valid */ + ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist); + if (ret < 0) { + kfree(chanlist); + return ret; + } + + cmd->chanlist = chanlist; + + return 0; +} + +static int do_cmd_ioctl(struct comedi_device *dev, + struct comedi_cmd __user *arg, void *file) +{ + struct comedi_cmd cmd; + struct comedi_subdevice *s; + struct comedi_async *async; + unsigned int __user *user_chanlist; + int ret; + + /* get the user's cmd and do some simple validation */ + ret = __comedi_get_user_cmd(dev, arg, &cmd); + if (ret) + return ret; + + /* save user's chanlist pointer so it can be restored later */ + user_chanlist = (unsigned int __user *)cmd.chanlist; + + s = &dev->subdevices[cmd.subdev]; + async = s->async; + /* are we locked? (ioctl lock) */ if (s->lock && s->lock != file) { - DPRINTK("subdevice locked\n"); + dev_dbg(dev->class_dev, "subdevice locked\n"); return -EACCES; } /* are we busy? */ if (s->busy) { - DPRINTK("subdevice busy\n"); + dev_dbg(dev->class_dev, "subdevice busy\n"); return -EBUSY; } - s->busy = file; - - /* make sure channel/gain list isn't too long */ - if (cmd.chanlist_len > s->len_chanlist) { - DPRINTK("channel/gain list too long %u > %d\n", - cmd.chanlist_len, s->len_chanlist); - ret = -EINVAL; - goto cleanup; - } /* make sure channel/gain list isn't too short */ if (cmd.chanlist_len < 1) { - DPRINTK("channel/gain list too short %u < 1\n", + dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n", cmd.chanlist_len); - ret = -EINVAL; - goto cleanup; + return -EINVAL; } async->cmd = cmd; async->cmd.data = NULL; - /* load channel/gain list */ - async->cmd.chanlist = - kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); - if (!async->cmd.chanlist) { - DPRINTK("allocation failed\n"); - ret = -ENOMEM; - goto cleanup; - } - - if (copy_from_user(async->cmd.chanlist, user_chanlist, - async->cmd.chanlist_len * sizeof(int))) { - DPRINTK("fault reading chanlist\n"); - ret = -EFAULT; - goto cleanup; - } - /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, - async->cmd.chanlist_len, - async->cmd.chanlist); - if (ret < 0) { - DPRINTK("bad chanlist\n"); + /* load channel/gain list */ + ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd); + if (ret) goto cleanup; - } ret = s->do_cmdtest(dev, s, &async->cmd); if (async->cmd.flags & TRIG_BOGUS || ret) { - DPRINTK("test returned %d\n", ret); + dev_dbg(dev->class_dev, "test returned %d\n", ret); cmd = async->cmd; /* restore chanlist pointer before copying back */ cmd.chanlist = (unsigned int __force *)user_chanlist; cmd.data = NULL; if (copy_to_user(arg, &cmd, sizeof(cmd))) { - DPRINTK("fault writing cmd\n"); + dev_dbg(dev->class_dev, "fault writing cmd\n"); ret = -EFAULT; goto cleanup; } @@ -1477,11 +1553,11 @@ static int do_cmd_ioctl(struct comedi_device *dev, if (!async->prealloc_bufsz) { ret = -ENOMEM; - DPRINTK("no buffer (?)\n"); + dev_dbg(dev->class_dev, "no buffer (?)\n"); goto cleanup; } - comedi_buf_reset(async); + comedi_buf_reset(s); async->cb_mask = COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | @@ -1489,8 +1565,11 @@ static int do_cmd_ioctl(struct comedi_device *dev, if (async->cmd.flags & TRIG_WAKE_EOS) async->cb_mask |= COMEDI_CB_EOS; - comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); + comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING); + /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with + * comedi_read() or comedi_write() */ + s->busy = file; ret = s->do_cmd(dev, s); if (ret == 0) return 0; @@ -1521,68 +1600,23 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, { struct comedi_cmd cmd; struct comedi_subdevice *s; - int ret = 0; - unsigned int *chanlist = NULL; unsigned int __user *user_chanlist; + int ret; + + /* get the user's cmd and do some simple validation */ + ret = __comedi_get_user_cmd(dev, arg, &cmd); + if (ret) + return ret; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - DPRINTK("bad cmd address\n"); - return -EFAULT; - } /* save user's chanlist pointer so it can be restored later */ user_chanlist = (unsigned int __user *)cmd.chanlist; - if (cmd.subdev >= dev->n_subdevices) { - DPRINTK("%d no such subdevice\n", cmd.subdev); - return -ENODEV; - } - s = &dev->subdevices[cmd.subdev]; - if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not valid subdevice\n", cmd.subdev); - return -EIO; - } - - if (!s->do_cmd || !s->do_cmdtest) { - DPRINTK("subdevice %i does not support commands\n", - cmd.subdev); - return -EIO; - } - - /* make sure channel/gain list isn't too long */ - if (cmd.chanlist_len > s->len_chanlist) { - DPRINTK("channel/gain list too long %d > %d\n", - cmd.chanlist_len, s->len_chanlist); - ret = -EINVAL; - goto cleanup; - } /* load channel/gain list */ - if (cmd.chanlist) { - chanlist = - kmalloc(cmd.chanlist_len * sizeof(int), GFP_KERNEL); - if (!chanlist) { - DPRINTK("allocation failed\n"); - ret = -ENOMEM; - goto cleanup; - } - - if (copy_from_user(chanlist, user_chanlist, - cmd.chanlist_len * sizeof(int))) { - DPRINTK("fault reading chanlist\n"); - ret = -EFAULT; - goto cleanup; - } - - /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist); - if (ret < 0) { - DPRINTK("bad chanlist\n"); - goto cleanup; - } - - cmd.chanlist = chanlist; - } + ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd); + if (ret) + return ret; ret = s->do_cmdtest(dev, s, &cmd); @@ -1590,12 +1624,9 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, cmd.chanlist = (unsigned int __force *)user_chanlist; if (copy_to_user(arg, &cmd, sizeof(cmd))) { - DPRINTK("bad cmd address\n"); + dev_dbg(dev->class_dev, "bad cmd address\n"); ret = -EFAULT; - goto cleanup; } -cleanup: - kfree(chanlist); return ret; } @@ -1705,6 +1736,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file) { struct comedi_subdevice *s; + int ret; if (arg >= dev->n_subdevices) return -EINVAL; @@ -1721,7 +1753,9 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, if (s->busy != file) return -EBUSY; - return do_cancel(dev, s); + ret = do_cancel(dev, s); + + return ret; } /* @@ -1766,12 +1800,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = comedi_dev_from_minor(minor); + struct comedi_device *dev = file->private_data; int rc; - if (!dev) - return -ENODEV; - mutex_lock(&dev->mutex); /* Device config is special, because it must work on @@ -1800,7 +1831,7 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, } if (!dev->attached) { - DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor); + dev_dbg(dev->class_dev, "no driver attached\n"); rc = -ENODEV; goto done; } @@ -1870,28 +1901,18 @@ done: static void comedi_vm_open(struct vm_area_struct *area) { - struct comedi_async *async; - struct comedi_device *dev; - - async = area->vm_private_data; - dev = async->subdevice->device; + struct comedi_buf_map *bm; - mutex_lock(&dev->mutex); - async->mmap_count++; - mutex_unlock(&dev->mutex); + bm = area->vm_private_data; + comedi_buf_map_get(bm); } static void comedi_vm_close(struct vm_area_struct *area) { - struct comedi_async *async; - struct comedi_device *dev; + struct comedi_buf_map *bm; - async = area->vm_private_data; - dev = async->subdevice->device; - - mutex_lock(&dev->mutex); - async->mmap_count--; - mutex_unlock(&dev->mutex); + bm = area->vm_private_data; + comedi_buf_map_put(bm); } static struct vm_operations_struct comedi_vm_ops = { @@ -1902,22 +1923,27 @@ 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_inode(file)); - struct comedi_device *dev = comedi_dev_from_minor(minor); + struct comedi_device *dev = file->private_data; struct comedi_subdevice *s; struct comedi_async *async; + struct comedi_buf_map *bm = NULL; unsigned long start = vma->vm_start; unsigned long size; int n_pages; int i; int retval; - if (!dev) - return -ENODEV; - - mutex_lock(&dev->mutex); + /* + * 'trylock' avoids circular dependency with current->mm->mmap_sem + * and down-reading &dev->attach_lock should normally succeed without + * contention unless the device is in the process of being attached + * or detached. + */ + if (!down_read_trylock(&dev->attach_lock)) + return -EAGAIN; if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); + dev_dbg(dev->class_dev, "no driver attached\n"); retval = -ENODEV; goto done; } @@ -1938,7 +1964,7 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } if (vma->vm_pgoff != 0) { - DPRINTK("comedi: mmap() offset must be 0.\n"); + dev_dbg(dev->class_dev, "mmap() offset must be 0.\n"); retval = -EINVAL; goto done; } @@ -1954,8 +1980,15 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } n_pages = size >> PAGE_SHIFT; + + /* get reference to current buf map (if any) */ + bm = comedi_buf_map_from_subdev_get(s); + if (!bm || n_pages > bm->n_pages) { + retval = -EINVAL; + goto done; + } for (i = 0; i < n_pages; ++i) { - struct comedi_buf_page *buf = &async->buf_page_list[i]; + struct comedi_buf_page *buf = &bm->page_list[i]; if (remap_pfn_range(vma, start, page_to_pfn(virt_to_page(buf->virt_addr)), @@ -1967,13 +2000,14 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } vma->vm_ops = &comedi_vm_ops; - vma->vm_private_data = async; + vma->vm_private_data = bm; - async->mmap_count++; + vma->vm_ops->open(vma); retval = 0; done: - mutex_unlock(&dev->mutex); + up_read(&dev->attach_lock); + comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */ return retval; } @@ -1981,16 +2015,13 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = comedi_dev_from_minor(minor); + struct comedi_device *dev = file->private_data; struct comedi_subdevice *s; - if (!dev) - return -ENODEV; - mutex_lock(&dev->mutex); if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); + dev_dbg(dev->class_dev, "no driver attached\n"); goto done; } @@ -1998,18 +2029,18 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) 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) + comedi_buf_read_n_available(s) > 0) mask |= POLLIN | POLLRDNORM; } s = comedi_write_subdevice(dev, minor); if (s && s->async) { - unsigned int bps = bytes_per_sample(s->async->subdevice); + unsigned int bps = bytes_per_sample(s); poll_wait(file, &s->async->wait_head, wait); - comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_write_alloc(s, s->async->prealloc_bufsz); if (!s->busy || !comedi_is_subdevice_running(s) || - comedi_buf_write_n_allocated(s->async) >= bps) + comedi_buf_write_n_allocated(s) >= bps) mask |= POLLOUT | POLLWRNORM; } @@ -2026,38 +2057,76 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = comedi_dev_from_minor(minor); + struct comedi_device *dev = file->private_data; + bool on_wait_queue = false; + bool attach_locked; + unsigned int old_detach_count; - if (!dev) - return -ENODEV; + /* Protect against device detachment during operation. */ + down_read(&dev->attach_lock); + attach_locked = true; + old_detach_count = dev->detach_count; if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); - return -ENODEV; + dev_dbg(dev->class_dev, "no driver attached\n"); + retval = -ENODEV; + goto out; } s = comedi_write_subdevice(dev, minor); - if (!s || !s->async) - return -EIO; + if (!s || !s->async) { + retval = -EIO; + goto out; + } async = s->async; if (!s->busy || !nbytes) - return 0; - if (s->busy != file) - return -EACCES; + goto out; + if (s->busy != file) { + retval = -EACCES; + goto out; + } add_wait_queue(&async->wait_head, &wait); + on_wait_queue = true; while (nbytes > 0 && !retval) { set_current_state(TASK_INTERRUPTIBLE); if (!comedi_is_subdevice_running(s)) { if (count == 0) { + struct comedi_subdevice *new_s; + if (comedi_is_subdevice_in_error(s)) retval = -EPIPE; else retval = 0; - do_become_nonbusy(dev, s); + /* + * To avoid deadlock, cannot acquire dev->mutex + * while dev->attach_lock is held. Need to + * remove task from the async wait queue before + * releasing dev->attach_lock, as it might not + * be valid afterwards. + */ + remove_wait_queue(&async->wait_head, &wait); + on_wait_queue = false; + up_read(&dev->attach_lock); + attach_locked = false; + mutex_lock(&dev->mutex); + /* + * Become non-busy unless things have changed + * behind our back. Checking dev->detach_count + * is unchanged ought to be sufficient (unless + * there have been 2**32 detaches in the + * meantime!), but check the subdevice pointer + * as well just in case. + */ + new_s = comedi_write_subdevice(dev, minor); + if (dev->attached && + old_detach_count == dev->detach_count && + s == new_s && new_s->async == async) + do_become_nonbusy(dev, s); + mutex_unlock(&dev->mutex); } break; } @@ -2067,9 +2136,9 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, m = n; if (async->buf_write_ptr + m > async->prealloc_bufsz) m = async->prealloc_bufsz - async->buf_write_ptr; - comedi_buf_write_alloc(async, async->prealloc_bufsz); - if (m > comedi_buf_write_n_allocated(async)) - m = comedi_buf_write_n_allocated(async); + comedi_buf_write_alloc(s, async->prealloc_bufsz); + if (m > comedi_buf_write_n_allocated(s)) + m = comedi_buf_write_n_allocated(s); if (m < n) n = m; @@ -2098,7 +2167,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, n -= m; retval = -EFAULT; } - comedi_buf_write_free(async, n); + comedi_buf_write_free(s, n); count += n; nbytes -= n; @@ -2106,8 +2175,12 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, buf += n; break; /* makes device work like a pipe */ } +out: + if (on_wait_queue) + remove_wait_queue(&async->wait_head, &wait); set_current_state(TASK_RUNNING); - remove_wait_queue(&async->wait_head, &wait); + if (attach_locked) + up_read(&dev->attach_lock); return count ? count : retval; } @@ -2120,25 +2193,35 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = comedi_dev_from_minor(minor); + struct comedi_device *dev = file->private_data; + unsigned int old_detach_count; + bool become_nonbusy = false; + bool attach_locked; - if (!dev) - return -ENODEV; + /* Protect against device detachment during operation. */ + down_read(&dev->attach_lock); + attach_locked = true; + old_detach_count = dev->detach_count; if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); - return -ENODEV; + dev_dbg(dev->class_dev, "no driver attached\n"); + retval = -ENODEV; + goto out; } s = comedi_read_subdevice(dev, minor); - if (!s || !s->async) - return -EIO; + if (!s || !s->async) { + retval = -EIO; + goto out; + } async = s->async; if (!s->busy || !nbytes) - return 0; - if (s->busy != file) - return -EACCES; + goto out; + if (s->busy != file) { + retval = -EACCES; + goto out; + } add_wait_queue(&async->wait_head, &wait); while (nbytes > 0 && !retval) { @@ -2146,7 +2229,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, n = nbytes; - m = comedi_buf_read_n_available(async); + m = comedi_buf_read_n_available(s); /* printk("%d available\n",m); */ if (async->buf_read_ptr + m > async->prealloc_bufsz) m = async->prealloc_bufsz - async->buf_read_ptr; @@ -2156,11 +2239,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, if (n == 0) { if (!comedi_is_subdevice_running(s)) { - do_become_nonbusy(dev, s); if (comedi_is_subdevice_in_error(s)) retval = -EPIPE; else retval = 0; + become_nonbusy = true; break; } if (file->f_flags & O_NONBLOCK) { @@ -2189,8 +2272,8 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, retval = -EFAULT; } - comedi_buf_read_alloc(async, n); - comedi_buf_read_free(async, n); + comedi_buf_read_alloc(s, n); + comedi_buf_read_free(s, n); count += n; nbytes -= n; @@ -2198,12 +2281,37 @@ 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_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); + set_current_state(TASK_RUNNING); + if (become_nonbusy || comedi_is_subdevice_idle(s)) { + struct comedi_subdevice *new_s; + + /* + * To avoid deadlock, cannot acquire dev->mutex + * while dev->attach_lock is held. + */ + up_read(&dev->attach_lock); + attach_locked = false; + mutex_lock(&dev->mutex); + /* + * Check device hasn't become detached behind our back. + * Checking dev->detach_count is unchanged ought to be + * sufficient (unless there have been 2**32 detaches in the + * meantime!), but check the subdevice pointer as well just in + * case. + */ + new_s = comedi_read_subdevice(dev, minor); + if (dev->attached && old_detach_count == dev->detach_count && + s == new_s && new_s->async == async) { + if (become_nonbusy || + async->buf_read_count - async->buf_write_count == 0) + do_become_nonbusy(dev, s); + } + mutex_unlock(&dev->mutex); + } +out: + if (attach_locked) + up_read(&dev->attach_lock); return count ? count : retval; } @@ -2211,101 +2319,58 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, static int comedi_open(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); - struct comedi_device *dev = comedi_dev_from_minor(minor); + struct comedi_device *dev = comedi_dev_get_from_minor(minor); + int rc; if (!dev) { - DPRINTK("invalid minor number\n"); - return -ENODEV; - } - - /* This is slightly hacky, but we want module autoloading - * to work for root. - * case: user opens device, attached -> ok - * case: user opens device, unattached, !in_request_module -> autoload - * case: user opens device, unattached, in_request_module -> fail - * case: root opens device, attached -> ok - * case: root opens device, unattached, in_request_module -> ok - * (typically called from modprobe) - * case: root opens device, unattached, !in_request_module -> autoload - * - * The last could be changed to "-> ok", which would deny root - * autoloading. - */ - mutex_lock(&dev->mutex); - if (dev->attached) - goto ok; - if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { - DPRINTK("in request module\n"); - mutex_unlock(&dev->mutex); + pr_debug("invalid minor number\n"); return -ENODEV; } - if (capable(CAP_NET_ADMIN) && dev->in_request_module) - goto ok; - dev->in_request_module = true; - -#ifdef CONFIG_KMOD - mutex_unlock(&dev->mutex); - request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); mutex_lock(&dev->mutex); -#endif - - dev->in_request_module = false; - if (!dev->attached && !capable(CAP_NET_ADMIN)) { - DPRINTK("not attached and not CAP_NET_ADMIN\n"); - mutex_unlock(&dev->mutex); - return -ENODEV; + dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n"); + rc = -ENODEV; + goto out; } -ok: - __module_get(THIS_MODULE); - - if (dev->attached) { + if (dev->attached && dev->use_count == 0) { if (!try_module_get(dev->driver->module)) { - module_put(THIS_MODULE); - mutex_unlock(&dev->mutex); - return -ENOSYS; + rc = -ENOSYS; + goto out; } - } - - if (dev->attached && dev->use_count == 0 && dev->open) { - int rc = dev->open(dev); - if (rc < 0) { - module_put(dev->driver->module); - module_put(THIS_MODULE); - mutex_unlock(&dev->mutex); - return rc; + if (dev->open) { + rc = dev->open(dev); + if (rc < 0) { + module_put(dev->driver->module); + goto out; + } } } dev->use_count++; + file->private_data = dev; + rc = 0; +out: mutex_unlock(&dev->mutex); - - return 0; + if (rc) + comedi_dev_put(dev); + return rc; } 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; + struct comedi_device *dev = file->private_data; return fasync_helper(fd, file, on, &dev->async_queue); } static int comedi_close(struct inode *inode, struct file *file) { - const unsigned minor = iminor(inode); - struct comedi_device *dev = comedi_dev_from_minor(minor); + struct comedi_device *dev = file->private_data; struct comedi_subdevice *s = NULL; int i; - if (!dev) - return -ENODEV; - mutex_lock(&dev->mutex); if (dev->subdevices) { @@ -2318,16 +2383,16 @@ static int comedi_close(struct inode *inode, struct file *file) s->lock = NULL; } } - if (dev->attached && dev->use_count == 1 && dev->close) - dev->close(dev); - - module_put(THIS_MODULE); - if (dev->attached) + if (dev->attached && dev->use_count == 1) { + if (dev->close) + dev->close(dev); module_put(dev->driver->module); + } dev->use_count--; mutex_unlock(&dev->mutex); + comedi_dev_put(dev); return 0; } @@ -2358,8 +2423,6 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) unsigned runflags = 0; unsigned runflags_mask = 0; - /* DPRINTK("comedi_event 0x%x\n",mask); */ - if (!comedi_is_subdevice_running(s)) return; @@ -2380,16 +2443,11 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) } if (async->cb_mask & s->async->events) { - if (comedi_get_subdevice_runflags(s) & SRF_USER) { - wake_up_interruptible(&async->wait_head); - if (s->subdev_flags & SDF_CMD_READ) - kill_fasync(&dev->async_queue, SIGIO, POLL_IN); - if (s->subdev_flags & SDF_CMD_WRITE) - kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); - } else { - if (async->cb_func) - async->cb_func(s->async->events, async->cb_arg); - } + wake_up_interruptible(&async->wait_head); + if (s->subdev_flags & SDF_CMD_READ) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); + if (s->subdev_flags & SDF_CMD_WRITE) + kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); } s->async->events = 0; } @@ -2420,7 +2478,7 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device) if (i == COMEDI_NUM_BOARD_MINORS) { mutex_unlock(&dev->mutex); comedi_device_cleanup(dev); - kfree(dev); + comedi_dev_put(dev); pr_err("comedi: error: ran out of minor numbers for board device files.\n"); return ERR_PTR(-EBUSY); } @@ -2428,7 +2486,7 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device) csdev = device_create(comedi_class, hardware_device, MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i); if (!IS_ERR(csdev)) - dev->class_dev = csdev; + dev->class_dev = get_device(csdev); /* Note: dev->mutex needs to be unlocked by the caller. */ return dev; @@ -2554,7 +2612,7 @@ static int __init comedi_init(void) return PTR_ERR(comedi_class); } - comedi_class->dev_attrs = comedi_dev_attrs; + comedi_class->dev_groups = comedi_dev_groups; /* XXX requires /proc interface */ comedi_proc_init(); @@ -2562,6 +2620,7 @@ static int __init comedi_init(void) /* create devices files for legacy/manual use */ for (i = 0; i < comedi_num_legacy_minors; i++) { struct comedi_device *dev; + dev = comedi_alloc_board_minor(NULL); if (IS_ERR(dev)) { comedi_cleanup_board_minors(); diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h index d5e03e558b3..e978c223f5b 100644 --- a/drivers/staging/comedi/comedi_internal.h +++ b/drivers/staging/comedi/comedi_internal.h @@ -15,8 +15,14 @@ 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); +void comedi_buf_reset(struct comedi_subdevice *s); +bool comedi_buf_is_mmapped(struct comedi_subdevice *s); +void comedi_buf_map_get(struct comedi_buf_map *bm); +int comedi_buf_map_put(struct comedi_buf_map *bm); +struct comedi_buf_map *comedi_buf_map_from_subdev_get( + struct comedi_subdevice *s); +unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s); +void comedi_device_cancel_all(struct comedi_device *dev); extern unsigned int comedi_default_buf_size_kb; extern unsigned int comedi_default_buf_maxsize_kb; @@ -24,6 +30,7 @@ extern unsigned int comedi_default_buf_maxsize_kb; /* drivers.c */ extern struct comedi_driver *comedi_drivers; +extern struct mutex comedi_drivers_list_lock; int insn_inval(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index b75915f30f4..8f4e44bfbe0 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -19,30 +19,14 @@ #ifndef _COMEDIDEV_H #define _COMEDIDEV_H -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/kdev_t.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/wait.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/vmalloc.h> #include <linux/dma-mapping.h> -#include <linux/uaccess.h> -#include <linux/io.h> -#include <linux/timer.h> +#include <linux/mutex.h> +#include <linux/spinlock_types.h> +#include <linux/rwsem.h> +#include <linux/kref.h> #include "comedi.h" -#define DPRINTK(format, args...) do { \ - if (comedi_debug) \ - pr_debug("comedi: " format, ## args); \ -} while (0) - #define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) #define COMEDI_VERSION_CODE COMEDI_VERSION(COMEDI_MAJORVERSION, \ COMEDI_MINORVERSION, COMEDI_MICROVERSION) @@ -72,41 +56,36 @@ struct comedi_subdevice { unsigned int maxdata; /* if maxdata==0, use list */ const unsigned int *maxdata_list; /* list is channel specific */ - unsigned int flags; - const unsigned int *flaglist; - - unsigned int settling_time_0; - const struct comedi_lrange *range_table; const struct comedi_lrange *const *range_table_list; unsigned int *chanlist; /* driver-owned chanlist (not used) */ - int (*insn_read) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_write)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_write) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_config)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_bits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insn_config) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - - int (*do_cmd) (struct comedi_device *, struct comedi_subdevice *); - int (*do_cmdtest) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_cmd *); - int (*poll) (struct comedi_device *, struct comedi_subdevice *); - int (*cancel) (struct comedi_device *, struct comedi_subdevice *); + + int (*do_cmd)(struct comedi_device *, struct comedi_subdevice *); + int (*do_cmdtest)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); + int (*poll)(struct comedi_device *, struct comedi_subdevice *); + int (*cancel)(struct comedi_device *, struct comedi_subdevice *); /* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */ /* int (*do_unlock)(struct comedi_device *, \ struct comedi_subdevice *); */ /* called when the buffer changes */ - int (*buf_change) (struct comedi_device *dev, - struct comedi_subdevice *s, unsigned long new_size); + int (*buf_change)(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned long new_size); - void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s, - void *data, unsigned int num_bytes, - unsigned int start_chan_index); + void (*munge)(struct comedi_device *dev, struct comedi_subdevice *s, + void *data, unsigned int num_bytes, + unsigned int start_chan_index); enum dma_data_direction async_dma_dir; unsigned int state; @@ -120,18 +99,20 @@ struct comedi_buf_page { dma_addr_t dma_addr; }; -struct comedi_async { - struct comedi_subdevice *subdevice; +struct comedi_buf_map { + struct device *dma_hw_dev; + struct comedi_buf_page *page_list; + unsigned int n_pages; + enum dma_data_direction dma_dir; + struct kref refcount; +}; +struct comedi_async { void *prealloc_buf; /* pre-allocated buffer */ unsigned int prealloc_bufsz; /* buffer size, in bytes */ - /* virtual and dma address of each page */ - struct comedi_buf_page *buf_page_list; - unsigned n_buf_pages; /* num elements in buf_page_list */ + struct comedi_buf_map *buf_map; /* map of buffer pages */ unsigned int max_bufsize; /* maximum buffer size, bytes */ - /* current number of mmaps of prealloc_buf */ - unsigned int mmap_count; /* byte count for writer (write completed) */ unsigned int buf_write_count; @@ -161,13 +142,10 @@ struct comedi_async { wait_queue_head_t wait_head; - /* callback stuff */ unsigned int cb_mask; - int (*cb_func) (unsigned int flags, void *); - void *cb_arg; - int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int x); + int (*inttrig)(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned int x); }; struct comedi_driver { @@ -175,9 +153,9 @@ struct comedi_driver { const char *driver_name; struct module *module; - int (*attach) (struct comedi_device *, struct comedi_devconfig *); - void (*detach) (struct comedi_device *); - int (*auto_attach) (struct comedi_device *, unsigned long); + int (*attach)(struct comedi_device *, struct comedi_devconfig *); + void (*detach)(struct comedi_device *); + int (*auto_attach)(struct comedi_device *, unsigned long); /* number of elements in board_name and board_id arrays */ unsigned int num_names; @@ -193,6 +171,7 @@ struct comedi_device { struct device *class_dev; int minor; + unsigned int detach_count; /* hw_dev is passed to dma_alloc_coherent when allocating async buffers * for subdevices that have async_dma_dir set to something other than * DMA_NONE */ @@ -201,10 +180,11 @@ struct comedi_device { const char *board_name; const void *board_ptr; bool attached:1; - bool in_request_module:1; bool ioenabled:1; spinlock_t spinlock; struct mutex mutex; + struct rw_semaphore attach_lock; + struct kref refcount; int n_subdevices; struct comedi_subdevice *subdevices; @@ -219,8 +199,8 @@ struct comedi_device { struct fasync_struct *async_queue; - int (*open) (struct comedi_device *dev); - void (*close) (struct comedi_device *dev); + int (*open)(struct comedi_device *dev); + void (*close)(struct comedi_device *dev); }; static inline const void *comedi_board(const struct comedi_device *dev) @@ -228,12 +208,6 @@ static inline const void *comedi_board(const struct comedi_device *dev) return dev->board_ptr; } -#ifdef CONFIG_COMEDI_DEBUG -extern int comedi_debug; -#else -static const int comedi_debug; -#endif - /* * function prototypes */ @@ -251,7 +225,8 @@ enum comedi_minor_bits { static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4; static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1; -struct comedi_device *comedi_dev_from_minor(unsigned minor); +struct comedi_device *comedi_dev_get_from_minor(unsigned minor); +int comedi_dev_put(struct comedi_device *dev); void init_polling(void); void cleanup_polling(void); @@ -260,7 +235,6 @@ void stop_polling(struct comedi_device *); /* subdevice runflags */ enum subdevice_runflags { - SRF_USER = 0x00000001, SRF_RT = 0x00000002, /* indicates an COMEDI_CB_ERROR event has occurred since the last * command was started */ @@ -322,7 +296,26 @@ static inline bool comedi_range_is_unipolar(struct comedi_subdevice *s, return s->range_table->range[range].min >= 0; } -/* some silly little inline functions */ +static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s, + unsigned int chan, + unsigned int range) +{ + return s->range_table_list[chan]->range[range].min < 0; +} + +static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s, + unsigned int chan, + unsigned int range) +{ + return s->range_table_list[chan]->range[range].min >= 0; +} + +/* munge between offset binary and two's complement values */ +static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, + unsigned int val) +{ + return val ^ s->maxdata ^ (s->maxdata >> 1); +} static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) { @@ -340,23 +333,38 @@ static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) */ int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev); -unsigned int comedi_buf_write_alloc(struct comedi_async *, unsigned int); -unsigned int comedi_buf_write_free(struct comedi_async *, unsigned int); +unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, unsigned int n); +unsigned int comedi_buf_write_free(struct comedi_subdevice *s, unsigned int n); -unsigned int comedi_buf_read_n_available(struct comedi_async *); -unsigned int comedi_buf_read_alloc(struct comedi_async *, unsigned int); -unsigned int comedi_buf_read_free(struct comedi_async *, unsigned int); +unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s); +unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, unsigned int n); +unsigned int comedi_buf_read_free(struct comedi_subdevice *s, unsigned int n); -int comedi_buf_put(struct comedi_async *, short); -int comedi_buf_get(struct comedi_async *, short *); +int comedi_buf_put(struct comedi_subdevice *s, unsigned short x); +int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x); -void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, +void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset, const void *source, unsigned int num_bytes); -void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, +void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset, void *destination, unsigned int num_bytes); /* drivers.c - general comedi driver functions */ +#define COMEDI_TIMEOUT_MS 1000 + +int comedi_timeout(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, + int (*cb)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned long context), + unsigned long context); + +int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data, + unsigned int mask); +unsigned int comedi_dio_update_state(struct comedi_subdevice *, + unsigned int *data); + +void *comedi_alloc_devpriv(struct comedi_device *, size_t); int comedi_alloc_subdevices(struct comedi_device *, int); int comedi_load_firmware(struct comedi_device *, struct device *, @@ -377,7 +385,7 @@ int comedi_auto_config(struct device *, struct comedi_driver *, void comedi_auto_unconfig(struct device *); int comedi_driver_register(struct comedi_driver *); -int comedi_driver_unregister(struct comedi_driver *); +void comedi_driver_unregister(struct comedi_driver *); /** * module_comedi_driver() - Helper macro for registering a comedi driver @@ -400,11 +408,11 @@ int comedi_driver_unregister(struct comedi_driver *); */ #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 +#define PCI_VENDOR_ID_HUMUSOFT 0x186c struct pci_dev; struct pci_driver; diff --git a/drivers/staging/comedi/comedilib.h b/drivers/staging/comedi/comedilib.h index 1a78b15543c..56baf852ecf 100644 --- a/drivers/staging/comedi/comedilib.h +++ b/drivers/staging/comedi/comedilib.h @@ -21,10 +21,13 @@ struct comedi_device *comedi_open(const char *path); int comedi_close(struct comedi_device *dev); +int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev, + unsigned int chan, unsigned int *io); int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, unsigned int chan, unsigned int io); -int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, - unsigned int mask, unsigned int *bits); +int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev, + unsigned int mask, unsigned int *bits, + unsigned int base_channel); int comedi_find_subdevice_by_type(struct comedi_device *dev, int type, unsigned int subd); int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice); diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index e25eba5713c..299726f39e2 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -23,7 +23,6 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/fcntl.h> -#include <linux/delay.h> #include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> @@ -39,6 +38,7 @@ #include "comedi_internal.h" struct comedi_driver *comedi_drivers; +DEFINE_MUTEX(comedi_drivers_list_lock); int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev) { @@ -57,6 +57,18 @@ static void comedi_clear_hw_dev(struct comedi_device *dev) dev->hw_dev = NULL; } +/** + * comedi_alloc_devpriv() - Allocate memory for the device private data. + * @dev: comedi_device struct + * @size: size of the memory to allocate + */ +void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size) +{ + dev->private = kzalloc(size, GFP_KERNEL); + return dev->private; +} +EXPORT_SYMBOL_GPL(comedi_alloc_devpriv); + int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) { struct comedi_subdevice *s; @@ -83,7 +95,7 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) } EXPORT_SYMBOL_GPL(comedi_alloc_subdevices); -static void cleanup_device(struct comedi_device *dev) +static void comedi_device_detach_cleanup(struct comedi_device *dev) { int i; struct comedi_subdevice *s; @@ -121,10 +133,14 @@ static void cleanup_device(struct comedi_device *dev) void comedi_device_detach(struct comedi_device *dev) { + comedi_device_cancel_all(dev); + down_write(&dev->attach_lock); dev->attached = false; + dev->detach_count++; if (dev->driver) dev->driver->detach(dev); - cleanup_device(dev); + comedi_device_detach_cleanup(dev); + up_write(&dev->attach_lock); } static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s) @@ -138,6 +154,98 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, return -EINVAL; } +/** + * comedi_timeout() - busy-wait for a driver condition to occur. + * @dev: comedi_device struct + * @s: comedi_subdevice struct + * @insn: comedi_insn struct + * @cb: callback to check for the condition + * @context: private context from the driver + */ +int comedi_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + int (*cb)(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context), + unsigned long context) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(COMEDI_TIMEOUT_MS); + int ret; + + while (time_before(jiffies, timeout)) { + ret = cb(dev, s, insn, context); + if (ret != -EBUSY) + return ret; /* success (0) or non EBUSY errno */ + cpu_relax(); + } + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(comedi_timeout); + +/** + * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices. + * @dev: comedi_device struct + * @s: comedi_subdevice struct + * @insn: comedi_insn struct + * @data: parameters for the @insn + * @mask: io_bits mask for grouped channels + */ +int comedi_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data, + unsigned int mask) +{ + unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); + + if (!mask) + mask = chan_mask; + + switch (data[0]) { + case INSN_CONFIG_DIO_INPUT: + s->io_bits &= ~mask; + break; + + case INSN_CONFIG_DIO_OUTPUT: + s->io_bits |= mask; + break; + + case INSN_CONFIG_DIO_QUERY: + data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; + return insn->n; + + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_dio_insn_config); + +/** + * comedi_dio_update_state() - update the internal state of DIO subdevices. + * @s: comedi_subdevice struct + * @data: the channel mask and bits to update + */ +unsigned int comedi_dio_update_state(struct comedi_subdevice *s, + unsigned int *data) +{ + unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1) + : 0xffffffff; + unsigned int mask = data[0] & chanmask; + unsigned int bits = data[1]; + + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + } + + return mask; +} +EXPORT_SYMBOL_GPL(comedi_dio_update_state); + static int insn_rw_emulate_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -150,6 +258,7 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, 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; @@ -198,7 +307,6 @@ static int __comedi_device_postconfig_async(struct comedi_device *dev, return -ENOMEM; init_waitqueue_head(&async->wait_head); - async->subdevice = s; s->async = async; async->max_bufsize = comedi_default_buf_maxsize_kb * 1024; @@ -233,6 +341,13 @@ static int __comedi_device_postconfig(struct comedi_device *dev) if (s->type == COMEDI_SUBD_UNUSED) continue; + if (s->type == COMEDI_SUBD_DO) { + if (s->n_chan < 32) + s->io_bits = (1 << s->n_chan) - 1; + else + s->io_bits = 0xffffffff; + } + if (s->len_chanlist == 0) s->len_chanlist = 1; @@ -274,8 +389,9 @@ static int comedi_device_postconfig(struct comedi_device *dev) ret = __comedi_device_postconfig(dev); if (ret < 0) return ret; - smp_wmb(); + down_write(&dev->attach_lock); dev->attached = true; + up_write(&dev->attach_lock); return 0; } @@ -365,7 +481,7 @@ int comedi_load_firmware(struct comedi_device *dev, release_firmware(fw); } - return ret; + return ret < 0 ? ret : 0; } EXPORT_SYMBOL_GPL(comedi_load_firmware); @@ -442,6 +558,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (dev->attached) return -EBUSY; + mutex_lock(&comedi_drivers_list_lock); for (driv = comedi_drivers; driv; driv = driv->next) { if (!try_module_get(driv->module)) continue; @@ -462,7 +579,8 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) comedi_report_boards(driv); module_put(driv->module); } - return -EIO; + ret = -EIO; + goto out; } if (driv->attach == NULL) { /* driver does not support manual configuration */ @@ -470,7 +588,8 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) "driver '%s' does not support attach using comedi_config\n", driv->driver_name); module_put(driv->module); - return -ENOSYS; + ret = -ENOSYS; + goto out; } /* initialize dev->driver here so * comedi_error() can be called from attach */ @@ -482,9 +601,11 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) ret = comedi_device_postconfig(dev); if (ret < 0) { comedi_device_detach(dev); - module_put(dev->driver->module); + module_put(driv->module); } /* On success, the driver module count has been incremented. */ +out: + mutex_unlock(&comedi_drivers_list_lock); return ret; } @@ -512,8 +633,12 @@ int comedi_auto_config(struct device *hardware_device, } dev = comedi_alloc_board_minor(hardware_device); - if (IS_ERR(dev)) + if (IS_ERR(dev)) { + dev_warn(hardware_device, + "driver '%s' could not create device.\n", + driver->driver_name); return PTR_ERR(dev); + } /* Note: comedi_alloc_board_minor() locked dev->mutex. */ dev->driver = driver; @@ -521,12 +646,22 @@ int comedi_auto_config(struct device *hardware_device, ret = driver->auto_attach(dev, context); if (ret >= 0) ret = comedi_device_postconfig(dev); - if (ret < 0) - comedi_device_detach(dev); mutex_unlock(&dev->mutex); - if (ret < 0) + if (ret < 0) { + dev_warn(hardware_device, + "driver '%s' failed to auto-configure device.\n", + driver->driver_name); comedi_release_hardware_device(hardware_device); + } else { + /* + * class_dev should be set properly here + * after a successful auto config + */ + dev_info(dev->class_dev, + "driver '%s' has successfully auto-configured '%s'.\n", + driver->driver_name, dev->board_name); + } return ret; } EXPORT_SYMBOL_GPL(comedi_auto_config); @@ -541,21 +676,37 @@ EXPORT_SYMBOL_GPL(comedi_auto_unconfig); int comedi_driver_register(struct comedi_driver *driver) { + mutex_lock(&comedi_drivers_list_lock); driver->next = comedi_drivers; comedi_drivers = driver; + mutex_unlock(&comedi_drivers_list_lock); return 0; } EXPORT_SYMBOL_GPL(comedi_driver_register); -int comedi_driver_unregister(struct comedi_driver *driver) +void comedi_driver_unregister(struct comedi_driver *driver) { struct comedi_driver *prev; int i; + /* unlink the driver */ + mutex_lock(&comedi_drivers_list_lock); + if (comedi_drivers == driver) { + comedi_drivers = driver->next; + } else { + for (prev = comedi_drivers; prev->next; prev = prev->next) { + if (prev->next == driver) { + prev->next = driver->next; + break; + } + } + } + mutex_unlock(&comedi_drivers_list_lock); + /* check for devices using this driver */ for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { - struct comedi_device *dev = comedi_dev_from_minor(i); + struct comedi_device *dev = comedi_dev_get_from_minor(i); if (!dev) continue; @@ -569,19 +720,7 @@ int comedi_driver_unregister(struct comedi_driver *driver) comedi_device_detach(dev); } mutex_unlock(&dev->mutex); + comedi_dev_put(dev); } - - if (comedi_drivers == driver) { - comedi_drivers = driver->next; - return 0; - } - - 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_driver_unregister); diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index 3abedcd2527..5829b46b757 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -21,106 +21,20 @@ #include "../comedi.h" -#define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div - -static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) -{ - int divider; - int div1, div2; - int div1_glb, div2_glb, ns_glb; - int div1_lub, div2_lub, ns_lub; - int ns; - - divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base; - - /* find 2 integers 1<={x,y}<=65536 such that x*y is - close to divider */ - - div1_lub = div2_lub = 0; - div1_glb = div2_glb = 0; - - ns_glb = 0; - ns_lub = 0xffffffff; - - div2 = 0x10000; - for (div1 = divider / 65536 + 1; div1 < div2; div1++) { - div2 = divider / div1; - - ns = i8253_osc_base * div1 * div2; - if (ns <= *nanosec && ns > ns_glb) { - ns_glb = ns; - div1_glb = div1; - div2_glb = div2; - } - - div2++; - if (div2 <= 65536) { - ns = i8253_osc_base * div1 * div2; - if (ns > *nanosec && ns < ns_lub) { - ns_lub = ns; - div1_lub = div1; - div2_lub = div2; - } - } - } - - *nanosec = div1_lub * div2_lub * i8253_osc_base; - *d1 = div1_lub & 0xffff; - *d2 = div2_lub & 0xffff; - return; -} - -static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) -{ - int div1, div2; - int base; - - for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) { - base = i8253_osc_base * div1; - round_mode &= TRIG_ROUND_MASK; - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - div2 = (*nanosec + base / 2) / base; - break; - case TRIG_ROUND_DOWN: - div2 = (*nanosec) / base; - break; - case TRIG_ROUND_UP: - div2 = (*nanosec + base - 1) / base; - break; - } - if (div2 < 2) - div2 = 2; - if (div2 <= 65536) { - *nanosec = div2 * base; - *d1 = div1 & 0xffff; - *d2 = div2 & 0xffff; - return; - } - } - - /* shouldn't get here */ - div1 = 0x10000; - div2 = 0x10000; - *nanosec = div1 * div2 * i8253_osc_base; - *d1 = div1 & 0xffff; - *d2 = div2 & 0xffff; -} - -static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) +/* + * Common oscillator base values in nanoseconds + */ +#define I8254_OSC_BASE_10MHZ 100 +#define I8254_OSC_BASE_5MHZ 200 +#define I8254_OSC_BASE_4MHZ 250 +#define I8254_OSC_BASE_2MHZ 500 +#define I8254_OSC_BASE_1MHZ 1000 + +static inline void i8253_cascade_ns_to_timer(int i8253_osc_base, + unsigned int *d1, + unsigned int *d2, + unsigned int *nanosec, + int round_mode) { unsigned int divider; unsigned int div1, div2; @@ -377,7 +291,7 @@ static inline int i8254_set_mode(unsigned long base_address, if (counter_number > 2) return -1; - if (mode > (I8254_MODE5 | I8254_BINARY)) + if (mode > (I8254_MODE5 | I8254_BCD)) return -1; byte = counter_number << 6; @@ -397,7 +311,7 @@ static inline int i8254_mm_set_mode(void __iomem *base_address, if (counter_number > 2) return -1; - if (mode > (I8254_MODE5 | I8254_BINARY)) + if (mode > (I8254_MODE5 | I8254_BCD)) return -1; byte = counter_number << 6; diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 94e17500150..46113a37413 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -73,10 +73,9 @@ I/O port base address can be found in the output of 'lspci -v'. will copy the latched value to a Comedi buffer. */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - #include "comedi_fc.h" #include "8255.h" @@ -95,7 +94,7 @@ I/O port base address can be found in the output of 'lspci -v'. struct subdev_8255_private { unsigned long iobase; - int (*io) (int, int, int, unsigned long); + int (*io)(int, int, int, unsigned long); }; static int subdev_8255_io(int dir, int port, int data, unsigned long iobase) @@ -113,12 +112,12 @@ void subdev_8255_interrupt(struct comedi_device *dev, { struct subdev_8255_private *spriv = s->private; unsigned long iobase = spriv->iobase; - short d; + unsigned short d; d = spriv->io(0, _8255_DATA, 0, iobase); d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8); - comedi_buf_put(s->async, d); + comedi_buf_put(s, d); s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); @@ -127,30 +126,24 @@ EXPORT_SYMBOL_GPL(subdev_8255_interrupt); static int subdev_8255_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct subdev_8255_private *spriv = s->private; unsigned long iobase = spriv->iobase; unsigned int mask; - unsigned int bits; unsigned int v; - mask = data[0]; - bits = data[1]; - + mask = comedi_dio_update_state(s, data); if (mask) { - v = s->state; - v &= ~mask; - v |= (bits & mask); - if (mask & 0xff) - spriv->io(1, _8255_DATA, v & 0xff, iobase); + spriv->io(1, _8255_DATA, s->state & 0xff, iobase); if (mask & 0xff00) - spriv->io(1, _8255_DATA + 1, (v >> 8) & 0xff, iobase); + spriv->io(1, _8255_DATA + 1, (s->state >> 8) & 0xff, + iobase); if (mask & 0xff0000) - spriv->io(1, _8255_DATA + 2, (v >> 16) & 0xff, iobase); - - s->state = v; + spriv->io(1, _8255_DATA + 2, (s->state >> 16) & 0xff, + iobase); } v = spriv->io(0, _8255_DATA, 0, iobase); @@ -185,39 +178,29 @@ static void subdev_8255_do_config(struct comedi_device *dev, static int subdev_8255_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int mask; - unsigned int bits; - - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x0000ff) - bits = 0x0000ff; - else if (mask & 0x00ff00) - bits = 0x00ff00; - else if (mask & 0x0f0000) - bits = 0x0f0000; + int ret; + + if (chan < 8) + mask = 0x0000ff; + else if (chan < 16) + mask = 0x00ff00; + else if (chan < 20) + mask = 0x0f0000; else - bits = 0xf00000; - - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + mask = 0xf00000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; subdev_8255_do_config(dev, s); - return 1; + return insn->n; } static int subdev_8255_cmdtest(struct comedi_device *dev, @@ -248,7 +231,7 @@ static int subdev_8255_cmdtest(struct comedi_device *dev, 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, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -279,7 +262,7 @@ static int subdev_8255_cancel(struct comedi_device *dev, } int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io) (int, int, int, unsigned long), + int (*io)(int, int, int, unsigned long), unsigned long iobase) { struct subdev_8255_private *spriv; @@ -299,9 +282,6 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, s->insn_bits = subdev_8255_insn; s->insn_config = subdev_8255_insn_config; - s->state = 0; - s->io_bits = 0; - subdev_8255_do_config(dev, s); return 0; @@ -309,7 +289,7 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, EXPORT_SYMBOL_GPL(subdev_8255_init); int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io) (int, int, int, unsigned long), + int (*io)(int, int, int, unsigned long), unsigned long iobase) { int ret; @@ -318,6 +298,7 @@ int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, if (ret) return ret; + s->len_chanlist = 1; s->do_cmdtest = subdev_8255_cmdtest; s->do_cmd = subdev_8255_cmd; s->cancel = subdev_8255_cancel; diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index 4f16ea78f86..795d232a6c0 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -22,10 +22,10 @@ #include "../comedidev.h" int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io) (int, int, int, unsigned long), + int (*io)(int, int, int, unsigned long), unsigned long iobase); int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io) (int, int, int, unsigned long), + int (*io)(int, int, int, unsigned long), unsigned long iobase); void subdev_8255_interrupt(struct comedi_device *dev, struct comedi_subdevice *s); diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index 3d3547c1948..46a385c29ba 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -50,11 +50,13 @@ Interrupt support for these boards is also not currently supported. Configuration Options: not applicable, uses PCI auto config */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" #include "8255.h" +#include "mite.h" enum pci_8255_boardid { BOARD_ADLINK_PCI7224, @@ -62,7 +64,8 @@ enum pci_8255_boardid { BOARD_ADLINK_PCI7296, BOARD_CB_PCIDIO24, BOARD_CB_PCIDIO24H, - BOARD_CB_PCIDIO48H, + BOARD_CB_PCIDIO48H_OLD, + BOARD_CB_PCIDIO48H_NEW, BOARD_CB_PCIDIO96H, BOARD_NI_PCIDIO96, BOARD_NI_PCIDIO96B, @@ -77,6 +80,7 @@ struct pci_8255_boardinfo { const char *name; int dio_badr; int n_8255; + unsigned int has_mite:1; }; static const struct pci_8255_boardinfo pci_8255_boards[] = { @@ -105,11 +109,16 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { .dio_badr = 2, .n_8255 = 1, }, - [BOARD_CB_PCIDIO48H] = { + [BOARD_CB_PCIDIO48H_OLD] = { .name = "cb_pci-dio48h", .dio_badr = 1, .n_8255 = 2, }, + [BOARD_CB_PCIDIO48H_NEW] = { + .name = "cb_pci-dio48h", + .dio_badr = 2, + .n_8255 = 2, + }, [BOARD_CB_PCIDIO96H] = { .name = "cb_pci-dio96h", .dio_badr = 2, @@ -119,36 +128,43 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { .name = "ni_pci-dio-96", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCIDIO96B] = { .name = "ni_pci-dio-96b", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PXI6508] = { .name = "ni_pxi-6508", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCI6503] = { .name = "ni_pci-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503B] = { .name = "ni_pci-6503b", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503X] = { .name = "ni_pci-6503x", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PXI_6503] = { .name = "ni_pxi-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, }; @@ -156,6 +172,25 @@ struct pci_8255_private { void __iomem *mmio_base; }; +static int pci_8255_mite_init(struct pci_dev *pcidev) +{ + void __iomem *mite_base; + u32 main_phys_addr; + + /* ioremap the MITE registers (BAR 0) temporarily */ + mite_base = pci_ioremap_bar(pcidev, 0); + if (!mite_base) + return -ENOMEM; + + /* set data window to main registers (BAR 1) */ + main_phys_addr = pci_resource_start(pcidev, 1); + writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR); + + /* finished with MITE registers */ + iounmap(mite_base); + return 0; +} + static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase) { void __iomem *mmio_base = (void __iomem *)iobase; @@ -186,15 +221,20 @@ static int pci_8255_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) return ret; + if (board->has_mite) { + ret = pci_8255_mite_init(pcidev); + if (ret) + return ret; + } + is_mmio = (pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM) != 0; if (is_mmio) { @@ -229,9 +269,6 @@ static int pci_8255_auto_attach(struct comedi_device *dev, return ret; } - dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n", - dev->board_name, board->n_8255 * 24); - return 0; } @@ -257,13 +294,16 @@ static int pci_8255_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &pci_8255_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(pci_8255_pci_table) = { +static const struct pci_device_id pci_8255_pci_table[] = { { PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 }, { PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 }, { PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 }, { PCI_VDEVICE(CB, 0x0028), BOARD_CB_PCIDIO24 }, { PCI_VDEVICE(CB, 0x0014), BOARD_CB_PCIDIO24H }, - { PCI_VDEVICE(CB, 0x000b), BOARD_CB_PCIDIO48H }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, 0x0000, 0x0000), + .driver_data = BOARD_CB_PCIDIO48H_OLD }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, PCI_VENDOR_ID_CB, 0x000b), + .driver_data = BOARD_CB_PCIDIO48H_NEW }, { PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H }, { PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 }, { PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B }, diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index dbb93e33248..0757a82ddcf 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -1,5 +1,6 @@ # Makefile for individual comedi drivers # +ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG # Comedi "helper" modules @@ -23,6 +24,7 @@ obj-$(CONFIG_COMEDI_PCL818) += pcl818.o obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o +obj-$(CONFIG_COMEDI_DAC02) += dac02.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o obj-$(CONFIG_COMEDI_DAS16) += das16.o @@ -39,6 +41,7 @@ obj-$(CONFIG_COMEDI_DMM32AT) += dmm32at.o obj-$(CONFIG_COMEDI_FL512) += fl512.o obj-$(CONFIG_COMEDI_AIO_AIO12_8) += aio_aio12_8.o obj-$(CONFIG_COMEDI_AIO_IIRO_16) += aio_iiro_16.o +obj-$(CONFIG_COMEDI_II_PCI20KC) += ii_pci20kc.o obj-$(CONFIG_COMEDI_C6XDIGIO) += c6xdigio.o obj-$(CONFIG_COMEDI_MPC624) += mpc624.o obj-$(CONFIG_COMEDI_ADQ12B) += adq12b.o @@ -51,7 +54,6 @@ obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o -obj-$(CONFIG_COMEDI_POC) += poc.o obj-$(CONFIG_COMEDI_S526) += s526.o # Comedi PCI drivers @@ -89,7 +91,6 @@ obj-$(CONFIG_COMEDI_DYNA_PCI10XX) += dyna_pci10xx.o obj-$(CONFIG_COMEDI_UNIOXX5) += unioxx5.o obj-$(CONFIG_COMEDI_GSC_HPDI) += gsc_hpdi.o obj-$(CONFIG_COMEDI_ICP_MULTI) += icp_multi.o -obj-$(CONFIG_COMEDI_II_PCI20KC) += ii_pci20kc.o obj-$(CONFIG_COMEDI_DAQBOARD2000) += daqboard2000.o obj-$(CONFIG_COMEDI_JR3_PCI) += jr3_pci.o obj-$(CONFIG_COMEDI_KE_COUNTER) += ke_counter.o @@ -110,6 +111,7 @@ obj-$(CONFIG_COMEDI_NI_PCIMIO) += ni_pcimio.o obj-$(CONFIG_COMEDI_RTD520) += rtd520.o obj-$(CONFIG_COMEDI_S626) += s626.o obj-$(CONFIG_COMEDI_SSV_DNP) += ssv_dnp.o +obj-$(CONFIG_COMEDI_MF6X4) += mf6x4.o # Comedi PCMCIA drivers obj-$(CONFIG_COMEDI_CB_DAS16_CS) += cb_das16_cs.o @@ -132,6 +134,7 @@ obj-$(CONFIG_COMEDI_MITE) += mite.o obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o obj-$(CONFIG_COMEDI_NI_TIOCMD) += ni_tiocmd.o obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o +obj-$(CONFIG_COMEDI_NI_LABPC_ISADMA) += ni_labpc_isadma.o obj-$(CONFIG_COMEDI_8255) += 8255.o obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200_common.o diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c deleted file mode 100644 index d0702084caa..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* - * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - * - * ADDI-DATA GmbH - * Dieselstrasse 3 - * D-77833 Ottersweier - * Tel: +19(0)7223/9493-0 - * Fax: +49(0)7223/9493-92 - * http://www.addi-data.com - * info@addi-data.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ -/* - | Description : APCI-1710 82X54 timer module | -*/ - -#define APCI1710_PCI_BUS_CLOCK 0 -#define APCI1710_FRONT_CONNECTOR_INPUT 1 -#define APCI1710_TIMER_READVALUE 0 -#define APCI1710_TIMER_GETOUTPUTLEVEL 1 -#define APCI1710_TIMER_GETPROGRESSSTATUS 2 -#define APCI1710_TIMER_WRITEVALUE 3 - -#define APCI1710_TIMER_READINTERRUPT 1 -#define APCI1710_TIMER_READALLTIMER 2 - -#ifndef APCI1710_10MHZ -#define APCI1710_10MHZ 10 -#endif - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitTimer | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| unsigned char_ b_TimerMode, | -| ULONG_ ul_ReloadValue, | -| unsigned char_ b_InputClockSelection, | -| unsigned char_ b_InputClockLevel, | -| unsigned char_ b_OutputLevel, | -| unsigned char_ b_HardwareGateLevel) -int i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) -| -+----------------------------------------------------------------------------+ -| Task : Configure the Timer (b_TimerNbr) operating mode | -| (b_TimerMode) from selected module (b_ModulNbr). | -| You must calling this function be for you call any | -| other function witch access of the timer. | -| | -| | -| Timer mode description table | -| | -|+--------+-----------------------------+--------------+--------------------+| -||Selected+ Mode description +u_ReloadValue | Hardware gate input|| -|| mode | | description | action || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 0 is typically used | | || -|| |for event counting. After | | || -|| |the initialisation, OUT | | || -|| |is initially low, and | | || -|| 0 |will remain low until the |Start counting| Hardware gate || -|| |counter reaches zero. | value | || -|| |OUT then goes high and | | || -|| |remains high until a new | | || -|| |count is written. See | | || -|| |"i_APCI1710_WriteTimerValue" | | || -|| |function. | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 1 is similar to mode 0 | | || -|| |except for the gate input | | || -|| 1 |action. The gate input is not|Start counting| Hardware trigger || -|| |used for enabled or disabled | value | || -|| |the timer. | | || -|| |The gate input is used for | | || -|| |triggered the timer. | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |This mode functions like a | | || -|| |divide-by-ul_ReloadValue | | || -|| |counter. It is typically used| | || -|| |to generate a real time clock| | || -|| |interrupt. OUT will initially| | || -|| 2 |be high after the | Division | Hardware gate || -|| |initialisation. When the | factor | || -|| |initial count has decremented| | || -|| |to 1, OUT goes low for one | | || -|| |CLK pule. OUT then goes high | | || -|| |again, the counter reloads | | || -|| |the initial count | | || -|| |(ul_ReloadValue) and the | | || -|| |process is repeated. | | || -|| |This action can generated a | | || -|| |interrupt. See function | | || -|| |"i_APCI1710_SetBoardInt- | | || -|| |RoutineX" | | || -|| |and "i_APCI1710_EnableTimer" | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 3 is typically used for | | || -|| |baud rate generation. This | | || -|| |mode is similar to mode 2 | | || -|| |except for the duty cycle of | | || -|| 3 |OUT. OUT will initially be | Division | Hardware gate || -|| |high after the initialisation| factor | || -|| |When half the initial count | | || -|| |(ul_ReloadValue) has expired,| | || -|| |OUT goes low for the | | || -|| |remainder of the count. The | | || -|| |mode is periodic; the | | || -|| |sequence above is repeated | | || -|| |indefinitely. | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |OUT will be initially high | | || -|| |after the initialisation. | | || -|| |When the initial count | | || -|| 4 |expires OUT will go low for |Start counting| Hardware gate || -|| |one CLK pulse and then go | value | || -|| |high again. | | || -|| |The counting sequences is | | || -|| |triggered by writing a new | | || -|| |value. See | | || -|| |"i_APCI1710_WriteTimerValue" | | || -|| |function. If a new count is | | || -|| |written during counting, | | || -|| |it will be loaded on the | | || -|| |next CLK pulse | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 5 is similar to mode 4 | | || -|| |except for the gate input | | || -|| |action. The gate input is not| | || -|| 5 |used for enabled or disabled |Start counting| Hardware trigger || -|| |the timer. The gate input is | value | || -|| |used for triggered the timer.| | || -|+--------+-----------------------------+--------------+--------------------+| -| | -| | -| | -| Input clock selection table | -| | -| +--------------------------------+------------------------------------+ | -| | b_InputClockSelection | Description | | -| | parameter | | | -| +--------------------------------+------------------------------------+ | -| | APCI1710_PCI_BUS_CLOCK | For the timer input clock, the PCI | | -| | | bus clock / 4 is used. This PCI bus| | -| | | clock can be 30MHz or 33MHz. For | | -| | | Timer 0 only this selection are | | -| | | available. | | -| +--------------------------------+------------------------------------+ | -| | APCI1710_ FRONT_CONNECTOR_INPUT| Of the front connector you have the| | -| | | possibility to inject a input clock| | -| | | for Timer 1 or Timer 2. The source | | -| | | from this clock can eat the output | | -| | | clock from Timer 0 or any other | | -| | | clock source. | | -| +--------------------------------+------------------------------------+ | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to | -| configure (0 to 2) | -| unsigned char_ b_TimerMode : Timer mode selection | -| (0 to 5) | -| 0: Interrupt on terminal| -| count | -| 1: Hardware | -| retriggerable one- | -| shot | -| 2: Rate generator | -| 3: Square wave mode | -| 4: Software triggered | -| strobe | -| 5: Hardware triggered | -| strobe | -| See timer mode | -| description table. | -| ULONG_ ul_ReloadValue : Start counting value | -| or division factor | -| See timer mode | -| description table. | -| unsigned char_ b_InputClockSelection : Selection from input | -| timer clock. | -| See input clock | -| selection table. | -| unsigned char_ b_InputClockLevel : Selection from input | -| clock level. | -| 0 : Low active | -| (Input inverted) | -| 1 : High active | -| unsigned char_ b_OutputLevel, : Selection from output | -| clock level. | -| 0 : Low active | -| 1 : High active | -| (Output inverted) | -| unsigned char_ b_HardwareGateLevel : Selection from | -| hardware gate level. | -| 0 : Low active | -| (Input inverted) | -| 1 : High active | -| If you will not used | -| the hardware gate set | -| this value to 0. -|b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_TimerMode = (unsigned char) data[0]; - ul_ReloadValue = (unsigned int) data[1]; - b_InputClockSelection =(unsigned char) data[2]; - b_InputClockLevel =(unsigned char) data[3]; - b_OutputLevel =(unsigned char) data[4]; - b_HardwareGateLevel =(unsigned char) data[5]; -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer mode selection is wrong | -| -6: Input timer clock selection is wrong | -| -7: Selection from input clock level is wrong | -| -8: Selection from output clock level is wrong | -| -9: Selection from hardware gate level is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned char b_ModulNbr; - unsigned char b_TimerNbr; - unsigned char b_TimerMode; - unsigned int ul_ReloadValue; - unsigned char b_InputClockSelection; - unsigned char b_InputClockLevel; - unsigned char b_OutputLevel; - unsigned char b_HardwareGateLevel; - - /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - unsigned int dw_Test = 0; - /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_TimerMode = (unsigned char) data[0]; - ul_ReloadValue = (unsigned int) data[1]; - b_InputClockSelection = (unsigned char) data[2]; - b_InputClockLevel = (unsigned char) data[3]; - b_OutputLevel = (unsigned char) data[4]; - b_HardwareGateLevel = (unsigned char) data[5]; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - - if (b_TimerNbr <= 2) { - /* Test the timer mode */ - if (b_TimerMode <= 5) { - /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - /* Test te imput clock selection */ - /* - if (((b_TimerNbr == 0) && (b_InputClockSelection == 0)) || - ((b_TimerNbr != 0) && ((b_InputClockSelection == 0) || (b_InputClockSelection == 1)))) - */ - - if (((b_TimerNbr == 0) && - (b_InputClockSelection == APCI1710_PCI_BUS_CLOCK)) || - ((b_TimerNbr == 0) && - (b_InputClockSelection == APCI1710_10MHZ)) || - ((b_TimerNbr != 0) && - ((b_InputClockSelection == APCI1710_PCI_BUS_CLOCK) || - (b_InputClockSelection == APCI1710_FRONT_CONNECTOR_INPUT) || - (b_InputClockSelection == APCI1710_10MHZ)))) { - /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - if (((b_InputClockSelection == APCI1710_10MHZ) && - ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) >= 0x3131)) || - (b_InputClockSelection != APCI1710_10MHZ)) { - /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - /* Test the input clock level selection */ - - if ((b_InputClockLevel == 0) || - (b_InputClockLevel == 1)) { - /* Test the output clock level selection */ - if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) { - /* Test the hardware gate level selection */ - if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) { - /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - /* Test if version > 1.1 and clock selection = 10MHz */ - if ((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) > 0x3131)) { - /* Test if 40MHz quartz on board */ - dw_Test = inl(devpriv->s_BoardInfos.ui_Address + (16 + (b_TimerNbr * 4) + (64 * b_ModulNbr))); - - dw_Test = (dw_Test >> 16) & 1; - } else { - dw_Test = 1; - } - - /* Test if detection OK */ - if (dw_Test == 1) { - /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - /* Initialisation OK */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init = 1; - - /* Save the input clock selection */ - devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockSelection = b_InputClockSelection; - - /* Save the input clock level */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockLevel = ~b_InputClockLevel & 1; - - /* Save the output level */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel = ~b_OutputLevel & 1; - - /* Save the gate level */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_HardwareGateLevel = b_HardwareGateLevel; - - /* Set the configuration word and disable the timer */ - /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - /* - devpriv->s_ModuleInfo [b_ModulNbr]. - s_82X54ModuleInfo. - s_82X54TimerInfo [b_TimerNbr]. - dw_ConfigurationWord = (unsigned int) (((b_HardwareGateLevel << 0) & 0x1) | - ((b_InputClockLevel << 1) & 0x2) | - (((~b_OutputLevel & 1) << 2) & 0x4) | - ((b_InputClockSelection << 4) & 0x10)); - */ - /* Test if 10MHz selected */ - if (b_InputClockSelection == APCI1710_10MHZ) { - b_InputClockSelection = 2; - } - - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (unsigned int)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30)); - /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Initialise the 82X54 Timer */ - outl((unsigned int) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Write the reload value */ - outl(ul_ReloadValue, devpriv->s_BoardInfos.ui_Address + 0 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - } /* if (dw_Test == 1) */ - else { - /* Input timer clock selection is wrong */ - i_ReturnValue = -6; - } /* if (dw_Test == 1) */ - /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */ - else { - /* Selection from hardware gate level is wrong */ - DPRINTK("Selection from hardware gate level is wrong\n"); - i_ReturnValue = -9; - } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */ - } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */ - else { - /* Selection from output clock level is wrong */ - DPRINTK("Selection from output clock level is wrong\n"); - i_ReturnValue = -8; - } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */ - } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */ - else { - /* Selection from input clock level is wrong */ - DPRINTK("Selection from input clock level is wrong\n"); - i_ReturnValue = -7; - } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */ - } else { - /* Input timer clock selection is wrong */ - DPRINTK("Input timer clock selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /* Input timer clock selection is wrong */ - DPRINTK("Input timer clock selection is wrong\n"); - i_ReturnValue = -6; - } - } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */ - else { - /* Timer mode selection is wrong */ - DPRINTK("Timer mode selection is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */ - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableTimer | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| unsigned char_ b_InterruptEnable) -int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Enable OR Disable the Timer (b_TimerNbr) from selected module | -| (b_ModulNbr). You must calling the | -| "i_APCI1710_InitTimer" function be for you call this | -| function. If you enable the timer interrupt, the timer | -| generate a interrupt after the timer value reach | -| the zero. See function "i_APCI1710_SetBoardIntRoutineX"| -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to enable | -| (0 to 2) | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| timer interrupt. | -| APCI1710_ENABLE : | -| Enable the timer interrupt | -| APCI1710_DISABLE : | -| Disable the timer interrupt| -i_ReturnValue=insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_ActionType = (unsigned char) data[0]; /* enable disable */ -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -| -6: Interrupt parameter is wrong | -| -7: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_DummyRead; - unsigned char b_ModulNbr; - unsigned char b_TimerNbr; - unsigned char b_ActionType; - unsigned char b_InterruptEnable; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_ActionType = (unsigned char) data[0]; /* enable disable */ - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - - switch (b_ActionType) { - case APCI1710_ENABLE: - b_InterruptEnable = (unsigned char) data[1]; - /* Test the interrupt selection */ - if ((b_InterruptEnable == APCI1710_ENABLE) || - (b_InterruptEnable == APCI1710_DISABLE)) { - if (b_InterruptEnable == APCI1710_ENABLE) { - - dw_DummyRead = inl(devpriv->s_BoardInfos.ui_Address + 12 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Enable the interrupt */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord | 0x8; - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - } /* if (b_InterruptEnable == APCI1710_ENABLE) */ - else { - /* Disable the interrupt */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7; - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Save the interrupt flag */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr)); - } /* if (b_InterruptEnable == APCI1710_ENABLE) */ - - /* Test if error occur */ - if (i_ReturnValue >= 0) { - /* Save the interrupt flag */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask | ((1 & b_InterruptEnable) << b_TimerNbr); - - /* Enable the timer */ - outl(1, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - } - } else { - /* Interrupt parameter is wrong */ - DPRINTK("\n"); - i_ReturnValue = -6; - } - break; - case APCI1710_DISABLE: - /* Test the interrupt flag */ - if (((devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask >> b_TimerNbr) & 1) == 1) { - /* Disable the interrupt */ - - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr]. dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7; - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Save the interrupt flag */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr)); - } - - /* Disable the timer */ - outl(0, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - break; - } /* Switch end */ - } else { - /* Timer not initialised see function */ - DPRINTK ("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadAllTimerValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| PULONG_ pul_TimerValueArray) -int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the all timer values from selected timer | -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_TimerValueArray : Timer value array. | -| Element 0 contain the timer 0 value. | -| Element 1 contain the timer 1 value. | -| Element 2 contain the timer 2 value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a TIMER module | -| -4: Timer 0 not initialised see function | -| "i_APCI1710_InitTimer" | -| -5: Timer 1 not initialised see function | -| "i_APCI1710_InitTimer" | -| -6: Timer 2 not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned char b_ModulNbr, b_ReadType; - unsigned int *pul_TimerValueArray; - - b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = CR_CHAN(insn->chanspec); - pul_TimerValueArray = (unsigned int *) data; - i_ReturnValue = insn->n; - - switch (b_ReadType) { - case APCI1710_TIMER_READINTERRUPT: - - data[0] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /* Increment the read FIFO */ - devpriv->s_InterruptParameters.ui_Read = (devpriv->s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - break; - - case APCI1710_TIMER_READALLTIMER: - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test if timer 0 iniutialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[0].b_82X54Init == 1) { - /* Test if timer 1 iniutialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[1].b_82X54Init == 1) { - /* Test if timer 2 iniutialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[2].b_82X54Init == 1) { - /* Latch all counter */ - outl(0x17, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - /* Read the timer 0 value */ - pul_TimerValueArray[0] = inl(devpriv->s_BoardInfos.ui_Address + 0 + (64 * b_ModulNbr)); - - /* Read the timer 1 value */ - pul_TimerValueArray[1] = inl(devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); - - /* Read the timer 2 value */ - pul_TimerValueArray[2] = inl(devpriv->s_BoardInfos.ui_Address + 8 + (64 * b_ModulNbr)); - } else { - /* Timer 2 not initialised see function */ - DPRINTK("Timer 2 not initialised see function\n"); - i_ReturnValue = -6; - } - } else { - /* Timer 1 not initialised see function */ - DPRINTK("Timer 1 not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer 0 not initialised see function */ - DPRINTK("Timer 0 not initialised see function\n"); - i_ReturnValue = -4; - } - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -3; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - } /* End of Switch */ - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadTimerValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| PULONG_ pul_TimerValue) | -+----------------------------------------------------------------------------+ -| Task : Return the timer value from selected digital timer | -| (b_TimerNbr) from selected timer module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to read | -| (0 to 2) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_TimerValue : Timer value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_ReadTimerValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_TimerNbr, - unsigned int *pul_TimerValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_82X54ModuleInfo. - s_82X54TimerInfo[b_TimerNbr]. - b_82X54Init == 1) { - /* Latch the timer value */ - outl((2 << b_TimerNbr) | 0xD0, - devpriv->s_BoardInfos. - ui_Address + 12 + - (64 * b_ModulNbr)); - - /* Read the counter value */ - *pul_TimerValue = - inl(devpriv->s_BoardInfos. - ui_Address + (b_TimerNbr * 4) + - (64 * b_ModulNbr)); - } else { - /* Timer not initialised see function */ - DPRINTK("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_GetTimerOutputLevel | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned char_ b_TimerNbr, | - | unsigned char *_ pb_OutputLevel) | - +----------------------------------------------------------------------------+ - | Task : Return the output signal level (pb_OutputLevel) from | - | selected digital timer (b_TimerNbr) from selected timer| - | module (b_ModulNbr). | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board | - | APCI-1710 | - | unsigned char_ b_ModulNbr : Selected module number | - | (0 to 3) | - | unsigned char_ b_TimerNbr : Timer number to test | - | (0 to 2) | - +----------------------------------------------------------------------------+ - | Output Parameters : unsigned char *_ pb_OutputLevel : Output signal level | - | 0 : The output is low | - | 1 : The output is high | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: Module selection wrong | - | -3: Timer selection wrong | - | -4: The module is not a TIMER module | - | -5: Timer not initialised see function | - | "i_APCI1710_InitTimer" | - +----------------------------------------------------------------------------+ - */ -static int i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_TimerNbr, - unsigned char *pb_OutputLevel) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_TimerStatus; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - /* Latch the timer value */ - outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - /* Read the timer status */ - dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - *pb_OutputLevel = (unsigned char) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel); - } else { - /* Timer not initialised see function */ - DPRINTK("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetTimerProgressStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| unsigned char *_ pb_TimerStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the progress status (pb_TimerStatus) from | -| selected digital timer (b_TimerNbr) from selected timer| -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to test | -| (0 to 2) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TimerStatus : Output signal level | -| 0 : Timer not in progress | -| 1 : Timer in progress | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_TimerNbr, - unsigned char *pb_TimerStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_TimerStatus; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - /* Latch the timer value */ - outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - /* Read the timer status */ - dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - *pb_TimerStatus = (unsigned char) ((dw_TimerStatus) >> 8) & 1; - printk("ProgressStatus : %d", *pb_TimerStatus); - } else { - /* Timer not initialised see function */ - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - - i_ReturnValue = -4; - } - } else { - /* Module number error */ - - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_WriteTimerValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| ULONG_ ul_WriteValue) | -+----------------------------------------------------------------------------+ -| Task : Write the value (ul_WriteValue) into the selected timer| -| (b_TimerNbr) from selected timer module (b_ModulNbr). | -| The action in depend of the time mode selection. | -| See timer mode description table. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to write | -| (0 to 2) | -| ULONG_ ul_WriteValue : Value to write | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_WriteTimerValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_TimerNbr, - unsigned int ul_WriteValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - /* Write the value */ - outl(ul_WriteValue, devpriv->s_BoardInfos.ui_Address + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - } else { - /* Timer not initialised see function */ - DPRINTK("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read write functions for Timer | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnBitsTimer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned char b_BitsType; - int i_ReturnValue = 0; - b_BitsType = data[0]; - - printk("\n82X54"); - - switch (b_BitsType) { - case APCI1710_TIMER_READVALUE: - i_ReturnValue = i_APCI1710_ReadTimerValue(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned int *) &data[0]); - break; - - case APCI1710_TIMER_GETOUTPUTLEVEL: - i_ReturnValue = i_APCI1710_GetTimerOutputLevel(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned char *) &data[0]); - break; - - case APCI1710_TIMER_GETPROGRESSSTATUS: - i_ReturnValue = i_APCI1710_GetTimerProgressStatus(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned char *)&data[0]); - break; - - case APCI1710_TIMER_WRITEVALUE: - i_ReturnValue = i_APCI1710_WriteTimerValue(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned int)data[1]); - - break; - - default: - printk("Bits Config Parameter Wrong\n"); - i_ReturnValue = -1; - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c deleted file mode 100644 index d91f586fdd2..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c +++ /dev/null @@ -1,2050 +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. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : CHRONO.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 chronometer module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 29/06/98 | S. Weber | Digital input / output implementation | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | | | | - | | | | - +-----------------------------------------------------------------------+ -*/ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_SINGLE 0 -#define APCI1710_CONTINUOUS 1 - -#define APCI1710_CHRONO_PROGRESS_STATUS 0 -#define APCI1710_CHRONO_READVALUE 1 -#define APCI1710_CHRONO_CONVERTVALUE 2 -#define APCI1710_CHRONO_READINTERRUPT 3 - -#define APCI1710_CHRONO_SET_CHANNELON 0 -#define APCI1710_CHRONO_SET_CHANNELOFF 1 -#define APCI1710_CHRONO_READ_CHANNEL 2 -#define APCI1710_CHRONO_READ_PORT 3 - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitChrono | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ChronoMode, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_TimingInterval, | -| PULONG_ pul_RealTimingInterval) - -+----------------------------------------------------------------------------+ -| Task : Configure the chronometer operating mode (b_ChronoMode)| -| from selected module (b_ModulNbr). | -| The ul_TimingInterval and ul_TimingUnit determine the | -| timing base for the measurement. | -| The pul_RealTimingInterval return the real timing | -| value. You must calling this function be for you call | -| any other function witch access of the chronometer. | -| | -| Witch this functionality from the APCI-1710 you have | -| the possibility to measure the timing witch two event. | -| | -| The mode 0 and 1 is appropriate for period measurement.| -| The mode 2 and 3 is appropriate for frequent | -| measurement. | -| The mode 4 to 7 is appropriate for measuring the timing| -| between two event. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr CR_AREF(insn->chanspec) : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ChronoMode data[0] : Chronometer action mode | -| (0 to 7). | -| unsigned char_ b_PCIInputClock data[1] : Selection from PCI bus clock| -| - APCI1710_30MHZ : | -| The PC have a PCI bus | -| clock from 30 MHz | -| - APCI1710_33MHZ : | -| The PC have a PCI bus | -| clock from 33 MHz | -| - APCI1710_40MHZ | -| The APCI-1710 have a | -| integrated 40Mhz | -| quartz. | -| unsigned char_ b_TimingUnit data[2] : Base timing unity (0 to 4) | -| 0 : ns | -| 1 : µs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| ULONG_ ul_TimingInterval : data[3] Base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealTimingInterval : Real base timing | -| value. -| data[0] -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer mode selection is wrong | -| -5: The selected PCI input clock is wrong | -| -6: Timing unity selection is wrong | -| -7: Base timing selection is wrong | -| -8: You can not used the 40MHz clock selection with | -| this board | -| -9: You can not used the 40MHz clock selection with | -| this CHRONOS version | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int ul_TimerValue = 0; - unsigned int ul_TimingInterval = 0; - unsigned int ul_RealTimingInterval = 0; - double d_RealTimingInterval = 0; - unsigned int dw_ModeArray[8] = - { 0x01, 0x05, 0x00, 0x04, 0x02, 0x0E, 0x0A, 0x06 }; - unsigned char b_ModulNbr, b_ChronoMode, b_PCIInputClock, b_TimingUnit; - - b_ModulNbr = CR_AREF(insn->chanspec); - b_ChronoMode = (unsigned char) data[0]; - b_PCIInputClock = (unsigned char) data[1]; - b_TimingUnit = (unsigned char) data[2]; - ul_TimingInterval = (unsigned int) data[3]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /*****************************/ - /* Test the chronometer mode */ - /*****************************/ - - if (b_ChronoMode <= 7) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ)) { - /*************************/ - /* Test the timing unity */ - /*************************/ - - if (b_TimingUnit <= 4) { - /**********************************/ - /* Test the base timing selection */ - /**********************************/ - - if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 66) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165576UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 60) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150240UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 50) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374182UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 1UL))) { - /**************************/ - /* Test the board version */ - /**************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) { - /************************/ - /* Test the TOR version */ - /************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || (b_PCIInputClock != APCI1710_40MHZ)) { - fpu_begin - (); - - /****************************************/ - /* Calculate the timer 0 division fator */ - /****************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.001 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.001 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.001 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (0.001 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.001 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (1.0 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (1.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - ( - (double) - 1.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (1.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - ul_TimingInterval - * - (1000 - * - b_PCIInputClock); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (1000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1000.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (1000.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (1000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (1000000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1000000.0 - * - (double) - b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (1000000.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - ( - (ul_TimingInterval - * - 60) - * - (1000000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_TimingInterval * 60.0) * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1000000.0 - * - (double) - b_PCIInputClock)) - / - 60; - d_RealTimingInterval - = - ( - (double) - ul_TimerValue - / - (0.001 * (double)b_PCIInputClock)) / 60.0; - - if ((double)(((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - } - - fpu_end(); - - /****************************/ - /* Save the PCI input clock */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_PCIInputClock - = - b_PCIInputClock; - - /*************************/ - /* Save the timing unity */ - /*************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_TimingUnit - = - b_TimingUnit; - - /************************/ - /* Save the base timing */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - d_TimingInterval - = - d_RealTimingInterval; - - /****************************/ - /* Set the chronometer mode */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg - = - dw_ModeArray - [b_ChronoMode]; - - /***********************/ - /* Test if 40 MHz used */ - /***********************/ - - if (b_PCIInputClock == APCI1710_40MHZ) { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg - | - 0x80; - } - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_ChronoModuleInfo.dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 16 + (64 * b_ModulNbr)); - - /***********************/ - /* Write timer 0 value */ - /***********************/ - - outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr)); - - /*********************/ - /* Chronometer init. */ - /*********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_ChronoInit - = - 1; - } else { - /***********************************************/ - /* TOR version error for 40MHz clock selection */ - /***********************************************/ - - DPRINTK("TOR version error for 40MHz clock selection\n"); - i_ReturnValue - = - -9; - } - } else { - /**************************************************************/ - /* You can not use the 40MHz clock selection with this board */ - /**************************************************************/ - - DPRINTK("You can not used the 40MHz clock selection with this board\n"); - i_ReturnValue = - -8; - } - } else { - /**********************************/ - /* Base timing selection is wrong */ - /**********************************/ - - DPRINTK("Base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /***********************************/ - /* Timing unity selection is wrong */ - /***********************************/ - - DPRINTK("Timing unity selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */ - else { - /***************************************/ - /* Chronometer mode selection is wrong */ - /***************************************/ - - DPRINTK("Chronometer mode selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */ - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - data[0] = ul_RealTimingInterval; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableChrono | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_CycleMode, | -| unsigned char_ b_InterruptEnable) -int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Enable the chronometer from selected module | -| (b_ModulNbr). You must calling the | -| "i_APCI1710_InitChrono" function be for you call this | -| function. | -| If you enable the chronometer interrupt, the | -| chronometer generate a interrupt after the stop signal.| -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter from this manual. | -| The b_CycleMode parameter determine if you will | -| measured a single or more cycle. - -| Disable the chronometer from selected module | -| (b_ModulNbr). If you disable the chronometer after a | -| start signal occur and you restart the chronometer | -| witch the " i_APCI1710_EnableChrono" function, if no | -| stop signal occur this start signal is ignored. -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number (0 to 3) | - data[0] ENABle/Disable chrono -| unsigned char_ b_CycleMode : Selected the chronometer | -| data[1] acquisition mode | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| data[2] chronometer interrupt. | -| APCI1710_ENABLE: | -| Enable the chronometer | -| interrupt | -| APCI1710_DISABLE: | -| Disable the chronometer | -| interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -| -5: Chronometer acquisition mode cycle is wrong | -| -6: Interrupt parameter is wrong | -| -7: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" - -8: data[0] wrong input | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned char b_ModulNbr, b_CycleMode, b_InterruptEnable, b_Action; - b_ModulNbr = CR_AREF(insn->chanspec); - b_Action = (unsigned char) data[0]; - b_CycleMode = (unsigned char) data[1]; - b_InterruptEnable = (unsigned char) data[2]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - - switch (b_Action) { - - case APCI1710_ENABLE: - - /*********************************/ - /* Test the cycle mode parameter */ - /*********************************/ - - if ((b_CycleMode == APCI1710_SINGLE) - || (b_CycleMode == - APCI1710_CONTINUOUS)) { - /***************************/ - /* Test the interrupt flag */ - /***************************/ - - if ((b_InterruptEnable == - APCI1710_ENABLE) - || (b_InterruptEnable == - APCI1710_DISABLE)) - { - - /***************************/ - /* Save the interrupt flag */ - /***************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_InterruptMask - = - b_InterruptEnable; - - /***********************/ - /* Save the cycle mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode = - b_CycleMode; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg & - 0x8F) | ((1 & - b_InterruptEnable) - << 5) | ((1 & - b_CycleMode) - << 6) | 0x10; - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if (b_InterruptEnable == - APCI1710_ENABLE) - { - /****************************/ - /* Clear the interrupt flag */ - /****************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg, - devpriv-> - s_BoardInfos. - ui_Address - + 32 + - (64 * b_ModulNbr)); - devpriv->tsk_Current = current; /* Save the current process task structure */ - } - - /***********************************/ - /* Enable or disable the interrupt */ - /* Enable the chronometer */ - /***********************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg, - devpriv-> - s_BoardInfos. - ui_Address + - 16 + - (64 * b_ModulNbr)); - - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv-> - s_BoardInfos. - ui_Address + - 36 + - (64 * b_ModulNbr)); - - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - else { - /***********************************************/ - /* Chronometer acquisition mode cycle is wrong */ - /***********************************************/ - - DPRINTK("Chronometer acquisition mode cycle is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - break; - - case APCI1710_DISABLE: - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - b_InterruptMask = 0; - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg & 0x2F; - - /***************************/ - /* Disable the interrupt */ - /* Disable the chronometer */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.dw_ConfigReg, - devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - /***************************/ - /* Test if continuous mode */ - /***************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode == - APCI1710_CONTINUOUS) { - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 36 + - (64 * b_ModulNbr)); - } - break; - - default: - DPRINTK("Inputs wrong! Enable or Disable chrono\n"); - i_ReturnValue = -8; - } /* switch ENABLE/DISABLE */ - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetChronoProgressStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_ChronoStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the chronometer status (pb_ChronoStatus) from | -| selected chronometer module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer | -| status. | -| 0 : Measurement not started.| -| No start signal occur. | -| 1 : Measurement started. | -| A start signal occur. | -| 2 : Measurement stopped. | -| A stop signal occur. | -| The measurement is | -| terminate. | -| 3: A overflow occur. You | -| must change the base | -| timing witch the | -| function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_ChronoStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (64 * b_ModulNbr)); - - /********************/ - /* Test if overflow */ - /********************/ - - if ((dw_Status & 8) == 8) { - /******************/ - /* Overflow occur */ - /******************/ - - *pb_ChronoStatus = 3; - } /* if ((dw_Status & 8) == 8) */ - else { - /*******************************/ - /* Test if measurement stopped */ - /*******************************/ - - if ((dw_Status & 2) == 2) { - /***********************/ - /* A stop signal occur */ - /***********************/ - - *pb_ChronoStatus = 2; - } /* if ((dw_Status & 2) == 2) */ - else { - /*******************************/ - /* Test if measurement started */ - /*******************************/ - - if ((dw_Status & 1) == 1) { - /************************/ - /* A start signal occur */ - /************************/ - - *pb_ChronoStatus = 1; - } /* if ((dw_Status & 1) == 1) */ - else { - /***************************/ - /* Measurement not started */ - /***************************/ - - *pb_ChronoStatus = 0; - } /* if ((dw_Status & 1) == 1) */ - } /* if ((dw_Status & 2) == 2) */ - } /* if ((dw_Status & 8) == 8) */ - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadChronoValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned int_ ui_TimeOut, | -| unsigned char *_ pb_ChronoStatus, | -| PULONG_ pul_ChronoValue) | -+----------------------------------------------------------------------------+ -| Task : Return the chronometer status (pb_ChronoStatus) and the| -| timing value (pul_ChronoValue) after a stop signal | -| occur from selected chronometer module (b_ModulNbr). | -| This function are only avaible if you have disabled | -| the interrupt functionality. See function | -| "i_APCI1710_EnableChrono" and the Interrupt mask | -| description chapter. | -| You can test the chronometer status witch the | -| "i_APCI1710_GetChronoProgressStatus" function. | -| | -| The returned value from pul_ChronoValue parameter is | -| not real measured timing. | -| You must used the "i_APCI1710_ConvertChronoValue" | -| function or make this operation for calculate the | -| timing: | -| | -| Timing = pul_ChronoValue * pul_RealTimingInterval. | -| | -| pul_RealTimingInterval is the returned parameter from | -| "i_APCI1710_InitChrono" function and the time unity is | -| the b_TimingUnit from "i_APCI1710_InitChrono" function| -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer | -| status. | -| 0 : Measurement not started.| -| No start signal occur. | -| 1 : Measurement started. | -| A start signal occur. | -| 2 : Measurement stopped. | -| A stop signal occur. | -| The measurement is | -| terminate. | -| 3: A overflow occur. You | -| must change the base | -| timing witch the | -| function | -| "i_APCI1710_InitChrono" | -| unsigned int * pul_ChronoValue : Chronometer timing value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -| -5: Timeout parameter is wrong (0 to 65535) | -| -6: Interrupt routine installed. You can not read | -| directly the chronometer measured timing. | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_ReadChronoValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ui_TimeOut, - unsigned char *pb_ChronoStatus, - unsigned int *pul_ChronoValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_TimeOut = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - /*****************************/ - /* Test the timout parameter */ - /*****************************/ - - if (ui_TimeOut <= 65535UL) { - - for (;;) { - /*******************/ - /* Read the status */ - /*******************/ - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + 8 + - (64 * b_ModulNbr)); - - /********************/ - /* Test if overflow */ - /********************/ - - if ((dw_Status & 8) == 8) { - /******************/ - /* Overflow occur */ - /******************/ - - *pb_ChronoStatus = 3; - - /***************************/ - /* Test if continuous mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode == - APCI1710_CONTINUOUS) - { - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr)); - } - - break; - } /* if ((dw_Status & 8) == 8) */ - else { - /*******************************/ - /* Test if measurement stopped */ - /*******************************/ - - if ((dw_Status & 2) == - 2) { - /***********************/ - /* A stop signal occur */ - /***********************/ - - *pb_ChronoStatus - = 2; - - /***************************/ - /* Test if continnous mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode - == - APCI1710_CONTINUOUS) - { - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr)); - } - break; - } /* if ((dw_Status & 2) == 2) */ - else { - /*******************************/ - /* Test if measurement started */ - /*******************************/ - - if ((dw_Status & 1) == 1) { - /************************/ - /* A start signal occur */ - /************************/ - - *pb_ChronoStatus - = - 1; - } /* if ((dw_Status & 1) == 1) */ - else { - /***************************/ - /* Measurement not started */ - /***************************/ - - *pb_ChronoStatus - = - 0; - } /* if ((dw_Status & 1) == 1) */ - } /* if ((dw_Status & 2) == 2) */ - } /* if ((dw_Status & 8) == 8) */ - - if (dw_TimeOut == ui_TimeOut) { - /*****************/ - /* Timeout occur */ - /*****************/ - - break; - } else { - /*************************/ - /* Increment the timeout */ - /*************************/ - - dw_TimeOut = - dw_TimeOut + 1; - mdelay(1000); - - } - } /* for (;;) */ - - /*****************************/ - /* Test if stop signal occur */ - /*****************************/ - - if (*pb_ChronoStatus == 2) { - /**********************************/ - /* Read the measured timing value */ - /**********************************/ - - *pul_ChronoValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (64 * b_ModulNbr)); - - if (*pul_ChronoValue != 0) { - *pul_ChronoValue = - *pul_ChronoValue - - 1; - } - } else { - /*************************/ - /* Test if timeout occur */ - /*************************/ - - if ((*pb_ChronoStatus != 3) - && (dw_TimeOut == - ui_TimeOut) - && (ui_TimeOut != 0)) { - /*****************/ - /* Timeout occur */ - /*****************/ - - *pb_ChronoStatus = 4; - } - } - - } else { - /******************************/ - /* Timeout parameter is wrong */ - /******************************/ - DPRINTK("Timeout parameter is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ConvertChronoValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| ULONG_ ul_ChronoValue, | -| PULONG_ pul_Hour, | -| unsigned char *_ pb_Minute, | -| unsigned char *_ pb_Second, | -| unsigned int *_ pui_MilliSecond, | -| unsigned int *_ pui_MicroSecond, | -| unsigned int *_ pui_NanoSecond) | -+----------------------------------------------------------------------------+ -| Task : Convert the chronometer measured timing | -| (ul_ChronoValue) in to h, mn, s, ms, µs, ns. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| ULONG_ ul_ChronoValue : Measured chronometer timing | -| value. | -| See"i_APCI1710_ReadChronoValue"| -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_Hour : Chronometer timing hour | -| unsigned char *_ pb_Minute : Chronometer timing minute | -| unsigned char *_ pb_Second : Chronometer timing second | -| unsigned int *_ pui_MilliSecond : Chronometer timing mini | -| second | -| unsigned int *_ pui_MicroSecond : Chronometer timing micro | -| second | -| unsigned int *_ pui_NanoSecond : Chronometer timing nano | -| second | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_ConvertChronoValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ul_ChronoValue, - unsigned int *pul_Hour, - unsigned char *pb_Minute, - unsigned char *pb_Second, - unsigned int *pui_MilliSecond, - unsigned int *pui_MicroSecond, - unsigned int *pui_NanoSecond) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - double d_Hour; - double d_Minute; - double d_Second; - double d_MilliSecond; - double d_MicroSecond; - double d_NanoSecond; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - fpu_begin(); - - d_Hour = (double)ul_ChronoValue *(double) - devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.d_TimingInterval; - - switch (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_TimingUnit) { - case 0: - d_Hour = d_Hour / (double)1000.0; - - case 1: - d_Hour = d_Hour / (double)1000.0; - - case 2: - d_Hour = d_Hour / (double)1000.0; - - case 3: - d_Hour = d_Hour / (double)60.0; - - case 4: - /**********************/ - /* Calculate the hour */ - /**********************/ - - d_Hour = d_Hour / (double)60.0; - *pul_Hour = (unsigned int) d_Hour; - - /************************/ - /* Calculate the minute */ - /************************/ - - d_Minute = d_Hour - *pul_Hour; - d_Minute = d_Minute * 60; - *pb_Minute = (unsigned char) d_Minute; - - /************************/ - /* Calculate the second */ - /************************/ - - d_Second = d_Minute - *pb_Minute; - d_Second = d_Second * 60; - *pb_Second = (unsigned char) d_Second; - - /*****************************/ - /* Calculate the mini second */ - /*****************************/ - - d_MilliSecond = d_Second - *pb_Second; - d_MilliSecond = d_MilliSecond * 1000; - *pui_MilliSecond = (unsigned int) d_MilliSecond; - - /******************************/ - /* Calculate the micro second */ - /******************************/ - - d_MicroSecond = - d_MilliSecond - - *pui_MilliSecond; - d_MicroSecond = d_MicroSecond * 1000; - *pui_MicroSecond = (unsigned int) d_MicroSecond; - - /******************************/ - /* Calculate the micro second */ - /******************************/ - - d_NanoSecond = - d_MicroSecond - - *pui_MicroSecond; - d_NanoSecond = d_NanoSecond * 1000; - *pui_NanoSecond = (unsigned int) d_NanoSecond; - break; - } - - fpu_end(); - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnReadChrono(struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read functions for Timer | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnReadChrono(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_ReadType; - int i_ReturnValue = insn->n; - - b_ReadType = CR_CHAN(insn->chanspec); - - switch (b_ReadType) { - case APCI1710_CHRONO_PROGRESS_STATUS: - i_ReturnValue = i_APCI1710_GetChronoProgressStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_CHRONO_READVALUE: - i_ReturnValue = i_APCI1710_ReadChronoValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned int) insn->unused[0], - (unsigned char *) &data[0], (unsigned int *) &data[1]); - break; - - case APCI1710_CHRONO_CONVERTVALUE: - i_ReturnValue = i_APCI1710_ConvertChronoValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned int) insn->unused[0], - (unsigned int *) &data[0], - (unsigned char *) &data[1], - (unsigned char *) &data[2], - (unsigned int *) &data[3], - (unsigned int *) &data[4], (unsigned int *) &data[5]); - break; - - case APCI1710_CHRONO_READINTERRUPT: - printk("In Chrono Read Interrupt\n"); - - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters. - ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - break; - - default: - printk("ReadType Parameter wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; - -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Sets the output witch has been passed with the | -| parameter b_Channel. Setting an output means setting an| -| output high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel : Selection from digital output | -| CR_CHAN() channel (0 to 2) | -| 0 : Channel H | -| 1 : Channel A | -| 2 : Channel B | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: The selected digital output is wrong | -| -5: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetChronoChlOff | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_OutputChannel) | -+----------------------------------------------------------------------------+ -| Task : Resets the output witch has been passed with the | -| parameter b_Channel. Resetting an output means setting | -| an output low. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 - data[0] : Chl ON, Chl OFF , Chl Read , Port Read - -| unsigned char_ b_ModulNbr CR_AREF : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel CR_CHAN : Selection from digital output | -| channel (0 to 2) | -| 0 : Channel H | -| 1 : Channel A | -| 2 : Channel B | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: The selected digital output is wrong | -| -5: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadChronoChlValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_InputChannel, | -| unsigned char *_ pb_ChannelStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the status from selected digital input | -| (b_InputChannel) from selected chronometer | -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| unsigned char_ b_InputChannel : Selection from digital input | -| channel (0 to 2) | -| CR_CHAN() 0 : Channel E | -| 1 : Channel F | -| 2 : Channel G | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel status.| -| data[0] 0 : Channel is not active | -| 1 : Channel is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: The selected digital input is wrong | -| -5: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadChronoPortValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_PortValue) | -+----------------------------------------------------------------------------+ -| Task : Return the status from digital inputs port from | -| selected (b_ModulNbr) chronometer module. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_PortValue : Digital inputs port status. -| data[0] -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned char b_ModulNbr, b_OutputChannel, b_InputChannel, b_IOType; - unsigned int dw_Status; - unsigned char *pb_ChannelStatus; - unsigned char *pb_PortValue; - - b_ModulNbr = CR_AREF(insn->chanspec); - i_ReturnValue = insn->n; - b_IOType = (unsigned char) data[0]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - /***********************************/ - /* Test the digital output channel */ - /***********************************/ - switch (b_IOType) { - - case APCI1710_CHRONO_SET_CHANNELOFF: - - b_OutputChannel = - (unsigned char) CR_CHAN(insn->chanspec); - if (b_OutputChannel <= 2) { - - outl(0, devpriv->s_BoardInfos. - ui_Address + 20 + - (b_OutputChannel * 4) + - (64 * b_ModulNbr)); - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - else { - /****************************************/ - /* The selected digital output is wrong */ - /****************************************/ - - DPRINTK("The selected digital output is wrong\n"); - i_ReturnValue = -4; - - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - - break; - - case APCI1710_CHRONO_SET_CHANNELON: - - b_OutputChannel = - (unsigned char) CR_CHAN(insn->chanspec); - if (b_OutputChannel <= 2) { - - outl(1, devpriv->s_BoardInfos. - ui_Address + 20 + - (b_OutputChannel * 4) + - (64 * b_ModulNbr)); - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - else { - /****************************************/ - /* The selected digital output is wrong */ - /****************************************/ - - DPRINTK("The selected digital output is wrong\n"); - i_ReturnValue = -4; - - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - - break; - - case APCI1710_CHRONO_READ_CHANNEL: - /**********************************/ - /* Test the digital input channel */ - /**********************************/ - pb_ChannelStatus = (unsigned char *) &data[0]; - b_InputChannel = - (unsigned char) CR_CHAN(insn->chanspec); - - if (b_InputChannel <= 2) { - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + 12 + - (64 * b_ModulNbr)); - - *pb_ChannelStatus = - (unsigned char) (((dw_Status >> - b_InputChannel) - & 1) ^ 1); - } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */ - else { - /***************************************/ - /* The selected digital input is wrong */ - /***************************************/ - - DPRINTK("The selected digital input is wrong\n"); - i_ReturnValue = -4; - } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */ - - break; - - case APCI1710_CHRONO_READ_PORT: - - pb_PortValue = (unsigned char *) &data[0]; - - dw_Status = - inl(devpriv->s_BoardInfos. - ui_Address + 12 + - (64 * b_ModulNbr)); - - *pb_PortValue = - (unsigned char) ((dw_Status & 0x7) ^ 7); - break; - } - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -5; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c deleted file mode 100644 index 27de18e7989..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c +++ /dev/null @@ -1,1037 +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. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : DIG_IO.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 digital I/O module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 16/06/98 | S. Weber | Digital input / output implementation | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | | | | - | | | | - +-----------------------------------------------------------------------+ -*/ - -/* Digital Output ON or OFF */ -#define APCI1710_ON 1 -#define APCI1710_OFF 0 - -/* Digital I/O */ -#define APCI1710_INPUT 0 -#define APCI1710_OUTPUT 1 - -#define APCI1710_DIGIO_MEMORYONOFF 0x10 -#define APCI1710_DIGIO_INIT 0x11 - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, | -| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| -+----------------------------------------------------------------------------+ -| Task : Configure the digital I/O operating mode from selected | -| module (b_ModulNbr). You must calling this function be| -| for you call any other function witch access of digital| -| I/O. | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| unsigned char_ b_ModulNbr data[0]: Module number to | -| configure (0 to 3) | -| unsigned char_ b_ChannelAMode data[1] : Channel A mode selection | -| 0 : Channel used for digital | -| input | -| 1 : Channel used for digital | -| output | -| unsigned char_ b_ChannelBMode data[2] : Channel B mode selection | -| 0 : Channel used for digital | -| input | -| 1 : Channel used for digital | -| output | - data[0] memory on/off -Activates and deactivates the digital output memory. - After having | -| called up this function with memory on,the output you have previously| -| activated with the function are not reset -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: Bi-directional channel A configuration error | -| -5: Bi-directional channel B configuration error | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_ModulNbr, b_ChannelAMode, b_ChannelBMode; - unsigned char b_MemoryOnOff, b_ConfigType; - int i_ReturnValue = 0; - unsigned int dw_WriteConfig = 0; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_ConfigType = (unsigned char) data[0]; /* Memory or Init */ - b_ChannelAMode = (unsigned char) data[1]; - b_ChannelBMode = (unsigned char) data[2]; - b_MemoryOnOff = (unsigned char) data[1]; /* if memory operation */ - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr >= 4) { - DPRINTK("Module Number invalid\n"); - i_ReturnValue = -2; - return i_ReturnValue; - } - switch (b_ConfigType) { - case APCI1710_DIGIO_MEMORYONOFF: - - if (b_MemoryOnOff) /* If Memory ON */ - { - /****************************/ - /* Set the output memory on */ - /****************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_OutputMemoryEnabled = 1; - - /***************************/ - /* Clear the output memory */ - /***************************/ - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.dw_OutputMemory = 0; - } else /* If memory off */ - { - /*****************************/ - /* Set the output memory off */ - /*****************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_OutputMemoryEnabled = 0; - } - break; - - case APCI1710_DIGIO_INIT: - - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - - /***************************************************/ - /* Test the bi-directional channel A configuration */ - /***************************************************/ - - if ((b_ChannelAMode == 0) || (b_ChannelAMode == 1)) { - /***************************************************/ - /* Test the bi-directional channel B configuration */ - /***************************************************/ - - if ((b_ChannelBMode == 0) - || (b_ChannelBMode == 1)) { - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit = - 1; - - /********************************/ - /* Save channel A configuration */ - /********************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode = b_ChannelAMode; - - /********************************/ - /* Save channel B configuration */ - /********************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode = b_ChannelBMode; - - /*****************************************/ - /* Set the channel A and B configuration */ - /*****************************************/ - - dw_WriteConfig = - (unsigned int) (b_ChannelAMode | - (b_ChannelBMode * 2)); - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(dw_WriteConfig, - devpriv->s_BoardInfos. - ui_Address + 4 + - (64 * b_ModulNbr)); - - } else { - /************************************************/ - /* Bi-directional channel B configuration error */ - /************************************************/ - DPRINTK("Bi-directional channel B configuration error\n"); - i_ReturnValue = -5; - } - - } else { - /************************************************/ - /* Bi-directional channel A configuration error */ - /************************************************/ - DPRINTK("Bi-directional channel A configuration error\n"); - i_ReturnValue = -4; - - } - - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - DPRINTK("The module is not a digital I/O module\n"); - i_ReturnValue = -3; - } - } /* end of Switch */ - printk("Return Value %d\n", i_ReturnValue); - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ - -|INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,comedi_subdevice -*s, struct comedi_insn *insn,unsigned int *data) - -+----------------------------------------------------------------------------+ -| Task : Read the status from selected digital I/O digital input| -| (b_InputChannel) | -+----------------------------------------------------------------------------| - - -| -| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number | -| (0 to 3) | -| unsigned char_ b_InputChannel CR_CHAN(chanspec) : Selection from digital | -| input ( 0 to 6) | -| 0 : Channel C | -| 1 : Channel D | -| 2 : Channel E | -| 3 : Channel F | -| 4 : Channel G | -| 5 : Channel A | -| 6 : Channel B - - - | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Digital input channel | -| status | -| 0 : Channle is not active| -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: The selected digital I/O digital input is wrong | -| -5: Digital I/O not initialised | -| -6: The digital channel A is used for output | -| -7: The digital channel B is used for output | -+----------------------------------------------------------------------------+ -*/ - -/* _INT_ i_APCI1710_ReadDigitalIOChlValue (unsigned char_ b_BoardHandle, */ -/* -* unsigned char_ b_ModulNbr, unsigned char_ b_InputChannel, -* unsigned char *_ pb_ChannelStatus) -*/ -static int i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr, b_InputChannel; - unsigned char *pb_ChannelStatus; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec); - data[0] = 0; - pb_ChannelStatus = (unsigned char *) &data[0]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /******************************************/ - /* Test the digital imnput channel number */ - /******************************************/ - - if (b_InputChannel <= 6) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /**********************************/ - /* Test if channel A or channel B */ - /**********************************/ - - if (b_InputChannel > 4) { - /*********************/ - /* Test if channel A */ - /*********************/ - - if (b_InputChannel == 5) { - /***************************/ - /* Test the channel A mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode - != 0) { - /********************************************/ - /* The digital channel A is used for output */ - /********************************************/ - - i_ReturnValue = - -6; - } - } /* if (b_InputChannel == 5) */ - else { - /***************************/ - /* Test the channel B mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode - != 0) { - /********************************************/ - /* The digital channel B is used for output */ - /********************************************/ - - i_ReturnValue = - -7; - } - } /* if (b_InputChannel == 5) */ - } /* if (b_InputChannel > 4) */ - - /***********************/ - /* Test if error occur */ - /***********************/ - - if (i_ReturnValue >= 0) { - /**************************/ - /* Read all digital input */ - /**************************/ - -/* -* INPDW (ps_APCI1710Variable-> s_Board [b_BoardHandle]. -* s_BoardInfos. ui_Address + (64 * b_ModulNbr), &dw_StatusReg); -*/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - - *pb_ChannelStatus = - (unsigned char) ((dw_StatusReg ^ - 0x1C) >> - b_InputChannel) & 1; - - } /* if (i_ReturnValue == 0) */ - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - DPRINTK("Digital I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /********************************/ - /* Selected digital input error */ - /********************************/ - DPRINTK("Selected digital input error\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - DPRINTK("The module is not a digital I/O module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnWriteDigitalIOChlOnOff(comedi_device -|*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) - -+----------------------------------------------------------------------------+ -| Task : Sets or resets the output witch has been passed with the | -| parameter b_Channel. Setting an output means setting | -| an ouput high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr (aref ) : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel (CR_CHAN) : Selection from digital output | -| channel (0 to 2) | -| 0 : Channel H | -| 1 : Channel A | -| 2 : Channel B | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: The selected digital output is wrong | -| -5: digital I/O not initialised see function | -| " i_APCI1710_InitDigitalIO" | -| -6: The digital channel A is used for input | -| -7: The digital channel B is used for input - -8: Digital Output Memory OFF. | -| Use previously the function | -| "i_APCI1710_SetDigitalIOMemoryOn". | -+----------------------------------------------------------------------------+ -*/ - -/* -* _INT_ i_APCI1710_SetDigitalIOChlOn (unsigned char_ b_BoardHandle, -* unsigned char_ b_ModulNbr, unsigned char_ b_OutputChannel) -*/ -static int i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_WriteValue = 0; - unsigned char b_ModulNbr, b_OutputChannel; - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_OutputChannel = CR_CHAN(insn->chanspec); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /******************************************/ - /* Test the digital output channel number */ - /******************************************/ - - switch (b_OutputChannel) { - /*************/ - /* Channel H */ - /*************/ - - case 0: - break; - - /*************/ - /* Channel A */ - /*************/ - - case 1: - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode != 1) { - /*******************************************/ - /* The digital channel A is used for input */ - /*******************************************/ - - i_ReturnValue = -6; - } - break; - - /*************/ - /* Channel B */ - /*************/ - - case 2: - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode != 1) { - /*******************************************/ - /* The digital channel B is used for input */ - /*******************************************/ - - i_ReturnValue = -7; - } - break; - - default: - /****************************************/ - /* The selected digital output is wrong */ - /****************************************/ - - i_ReturnValue = -4; - break; - } - - /***********************/ - /* Test if error occur */ - /***********************/ - - if (i_ReturnValue >= 0) { - - /*********************************/ - /* Test if set channel ON */ - /*********************************/ - if (data[0]) { - /*********************************/ - /* Test if output memory enabled */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled == - 1) { - dw_WriteValue = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - | (1 << - b_OutputChannel); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = dw_WriteValue; - } else { - dw_WriteValue = - 1 << - b_OutputChannel; - } - } /* set channel off */ - else { - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled == - 1) { - dw_WriteValue = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - & (0xFFFFFFFFUL - - - (1 << b_OutputChannel)); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = dw_WriteValue; - } else { - /*****************************/ - /* Digital Output Memory OFF */ - /*****************************/ - /* +Use previously the function "i_APCI1710_SetDigitalIOMemoryOn" */ - i_ReturnValue = -8; - } - - } - /*******************/ - /* Write the value */ - /*******************/ - - /* OUTPDW (ps_APCI1710Variable-> - * s_Board [b_BoardHandle]. - * s_BoardInfos. ui_Address + (64 * b_ModulNbr), - * dw_WriteValue); - */ -*/ - outl(dw_WriteValue, - devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - } - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - - i_ReturnValue = -5; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ - -|INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,comedi_subdevice - *s, struct comedi_insn *insn,unsigned int *data) -+----------------------------------------------------------------------------+ -| Task : write: - Sets or resets one or several outputs from port. | -| Setting an output means setting an output high. | -| If you have switched OFF the digital output memory | -| (OFF), all the other output are set to "0". - -| read: - Read the status from digital input port | -| from selected digital I/O module (b_ModulNbr) -+----------------------------------------------------------------------------+ -| Input Parameters : - unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr CR_AREF(aref) : Selected module number (0 to 3)| -| unsigned char_ b_PortValue CR_CHAN(chanspec) : Output Value ( 0 To 7 ) -| data[0] read or write port -| data[1] if write then indicate ON or OFF - -| if read : data[1] will return port status. -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - -| INPUT : - - 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: Digital I/O not initialised - - OUTPUT: 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: Output value wrong | -| -5: digital I/O not initialised see function | -| " i_APCI1710_InitDigitalIO" | -| -6: The digital channel A is used for input | -| -7: The digital channel B is used for input - -8: Digital Output Memory OFF. | -| Use previously the function | -| "i_APCI1710_SetDigitalIOMemoryOn". | -+----------------------------------------------------------------------------+ -*/ - -/* - * _INT_ i_APCI1710_SetDigitalIOPortOn (unsigned char_ - * b_BoardHandle, unsigned char_ b_ModulNbr, unsigned char_ - * b_PortValue) -*/ -static int i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_WriteValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr, b_PortValue; - unsigned char b_PortOperation, b_PortOnOFF; - - unsigned char *pb_PortValue; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_PortOperation = (unsigned char) data[0]; /* Input or output */ - b_PortOnOFF = (unsigned char) data[1]; /* if output then On or Off */ - b_PortValue = (unsigned char) data[2]; /* if out put then Value */ - i_ReturnValue = insn->n; - pb_PortValue = (unsigned char *) &data[0]; -/* if input then read value */ - - switch (b_PortOperation) { - case APCI1710_INPUT: - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /**************************/ - /* Read all digital input */ - /**************************/ - - /* INPDW (ps_APCI1710Variable-> - * s_Board [b_BoardHandle]. - * s_BoardInfos. - * ui_Address + (64 * b_ModulNbr), - * &dw_StatusReg); - */ - - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - *pb_PortValue = - (unsigned char) (dw_StatusReg ^ 0x1C); - - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - i_ReturnValue = -2; - } - - break; - - case APCI1710_OUTPUT: - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /***********************/ - /* Test the port value */ - /***********************/ - - if (b_PortValue <= 7) { - /***********************************/ - /* Test the digital output channel */ - /***********************************/ - - /**************************/ - /* Test if channel A used */ - /**************************/ - - if ((b_PortValue & 2) == 2) { - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode - != 1) { - /*******************************************/ - /* The digital channel A is used for input */ - /*******************************************/ - - i_ReturnValue = - -6; - } - } /* if ((b_PortValue & 2) == 2) */ - - /**************************/ - /* Test if channel B used */ - /**************************/ - - if ((b_PortValue & 4) == 4) { - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode - != 1) { - /*******************************************/ - /* The digital channel B is used for input */ - /*******************************************/ - - i_ReturnValue = - -7; - } - } /* if ((b_PortValue & 4) == 4) */ - - /***********************/ - /* Test if error occur */ - /***********************/ - - if (i_ReturnValue >= 0) { - - /* if(data[1]) { */ - - switch (b_PortOnOFF) { - /*********************************/ - /* Test if set Port ON */ - /*********************************/ - - case APCI1710_ON: - - /*********************************/ - /* Test if output memory enabled */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled - == 1) { - dw_WriteValue - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - | - b_PortValue; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = - dw_WriteValue; - } else { - dw_WriteValue - = - b_PortValue; - } - break; - - /* If Set PORT OFF */ - case APCI1710_OFF: - - /*********************************/ - /* Test if output memory enabled */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled - == 1) { - dw_WriteValue - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - & - (0xFFFFFFFFUL - - - b_PortValue); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = - dw_WriteValue; - } else { - /*****************************/ - /* Digital Output Memory OFF */ - /*****************************/ - - i_ReturnValue - = - -8; - } - } /* switch */ - - /*******************/ - /* Write the value */ - /*******************/ - - /* OUTPDW (ps_APCI1710Variable-> - * s_Board [b_BoardHandle]. - * s_BoardInfos. - * ui_Address + (64 * b_ModulNbr), - * dw_WriteValue); */ - - outl(dw_WriteValue, - devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } - } else { - /**********************/ - /* Output value wrong */ - /**********************/ - - i_ReturnValue = -4; - } - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - - i_ReturnValue = -5; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - i_ReturnValue = -2; - } - break; - - default: - i_ReturnValue = -9; - DPRINTK("NO INPUT/OUTPUT specified\n"); - } /* switch INPUT / OUTPUT */ - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c deleted file mode 100644 index c9db601da2c..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c +++ /dev/null @@ -1,5461 +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. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : INC_CPT.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 incremental counter module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | 29/06/01 | Guinot C. | - 1100/0231 -> 0701/0232 | - | | | See i_APCI1710_DisableFrequencyMeasurement | - +-----------------------------------------------------------------------+ -*/ - -#define APCI1710_16BIT_COUNTER 0x10 -#define APCI1710_32BIT_COUNTER 0x0 -#define APCI1710_QUADRUPLE_MODE 0x0 -#define APCI1710_DOUBLE_MODE 0x3 -#define APCI1710_SIMPLE_MODE 0xF -#define APCI1710_DIRECT_MODE 0x80 -#define APCI1710_HYSTERESIS_ON 0x60 -#define APCI1710_HYSTERESIS_OFF 0x0 -#define APCI1710_INCREMENT 0x60 -#define APCI1710_DECREMENT 0x0 -#define APCI1710_LATCH_COUNTER 0x1 -#define APCI1710_CLEAR_COUNTER 0x0 -#define APCI1710_LOW 0x0 -#define APCI1710_HIGH 0x1 - -/*********************/ -/* Version 0600-0229 */ -/*********************/ -#define APCI1710_HIGH_EDGE_CLEAR_COUNTER 0x0 -#define APCI1710_HIGH_EDGE_LATCH_COUNTER 0x1 -#define APCI1710_LOW_EDGE_CLEAR_COUNTER 0x2 -#define APCI1710_LOW_EDGE_LATCH_COUNTER 0x3 -#define APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER 0x4 -#define APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER 0x5 -#define APCI1710_SOURCE_0 0x0 -#define APCI1710_SOURCE_1 0x1 - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_ENABLE_LATCH_INT 0x80 -#define APCI1710_DISABLE_LATCH_INT (~APCI1710_ENABLE_LATCH_INT) - -#define APCI1710_INDEX_LATCH_COUNTER 0x10 -#define APCI1710_INDEX_AUTO_MODE 0x8 -#define APCI1710_ENABLE_INDEX 0x4 -#define APCI1710_DISABLE_INDEX (~APCI1710_ENABLE_INDEX) -#define APCI1710_ENABLE_LATCH_AND_CLEAR 0x8 -#define APCI1710_DISABLE_LATCH_AND_CLEAR (~APCI1710_ENABLE_LATCH_AND_CLEAR) -#define APCI1710_SET_LOW_INDEX_LEVEL 0x4 -#define APCI1710_SET_HIGH_INDEX_LEVEL (~APCI1710_SET_LOW_INDEX_LEVEL) -#define APCI1710_INVERT_INDEX_RFERENCE 0x2 -#define APCI1710_DEFAULT_INDEX_RFERENCE (~APCI1710_INVERT_INDEX_RFERENCE) - -#define APCI1710_ENABLE_INDEX_INT 0x1 -#define APCI1710_DISABLE_INDEX_INT (~APCI1710_ENABLE_INDEX_INT) - -#define APCI1710_ENABLE_FREQUENCY 0x4 -#define APCI1710_DISABLE_FREQUENCY (~APCI1710_ENABLE_FREQUENCY) - -#define APCI1710_ENABLE_FREQUENCY_INT 0x8 -#define APCI1710_DISABLE_FREQUENCY_INT (~APCI1710_ENABLE_FREQUENCY_INT) - -#define APCI1710_ENABLE_40MHZ_FREQUENCY 0x40 -#define APCI1710_DISABLE_40MHZ_FREQUENCY (~APCI1710_ENABLE_40MHZ_FREQUENCY) - -#define APCI1710_ENABLE_40MHZ_FILTER 0x80 -#define APCI1710_DISABLE_40MHZ_FILTER (~APCI1710_ENABLE_40MHZ_FILTER) - -#define APCI1710_ENABLE_COMPARE_INT 0x2 -#define APCI1710_DISABLE_COMPARE_INT (~APCI1710_ENABLE_COMPARE_INT) - -#define APCI1710_ENABLE_INDEX_ACTION 0x20 -#define APCI1710_DISABLE_INDEX_ACTION (~APCI1710_ENABLE_INDEX_ACTION) -#define APCI1710_REFERENCE_HIGH 0x40 -#define APCI1710_REFERENCE_LOW (~APCI1710_REFERENCE_HIGH) - -#define APCI1710_TOR_GATE_LOW 0x40 -#define APCI1710_TOR_GATE_HIGH (~APCI1710_TOR_GATE_LOW) - -/* INSN CONFIG */ -#define APCI1710_INCCPT_INITCOUNTER 100 -#define APCI1710_INCCPT_COUNTERAUTOTEST 101 -#define APCI1710_INCCPT_INITINDEX 102 -#define APCI1710_INCCPT_INITREFERENCE 103 -#define APCI1710_INCCPT_INITEXTERNALSTROBE 104 -#define APCI1710_INCCPT_INITCOMPARELOGIC 105 -#define APCI1710_INCCPT_INITFREQUENCYMEASUREMENT 106 - -/* INSN READ */ -#define APCI1710_INCCPT_READLATCHREGISTERSTATUS 200 -#define APCI1710_INCCPT_READLATCHREGISTERVALUE 201 -#define APCI1710_INCCPT_READ16BITCOUNTERVALUE 202 -#define APCI1710_INCCPT_READ32BITCOUNTERVALUE 203 -#define APCI1710_INCCPT_GETINDEXSTATUS 204 -#define APCI1710_INCCPT_GETREFERENCESTATUS 205 -#define APCI1710_INCCPT_GETUASSTATUS 206 -#define APCI1710_INCCPT_GETCBSTATUS 207 -#define APCI1710_INCCPT_GET16BITCBSTATUS 208 -#define APCI1710_INCCPT_GETUDSTATUS 209 -#define APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS 210 -#define APCI1710_INCCPT_READFREQUENCYMEASUREMENT 211 -#define APCI1710_INCCPT_READINTERRUPT 212 - -/* INSN BITS */ -#define APCI1710_INCCPT_CLEARCOUNTERVALUE 300 -#define APCI1710_INCCPT_CLEARALLCOUNTERVALUE 301 -#define APCI1710_INCCPT_SETINPUTFILTER 302 -#define APCI1710_INCCPT_LATCHCOUNTER 303 -#define APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE 304 -#define APCI1710_INCCPT_SETDIGITALCHLON 305 -#define APCI1710_INCCPT_SETDIGITALCHLOFF 306 - -/* INSN WRITE */ -#define APCI1710_INCCPT_ENABLELATCHINTERRUPT 400 -#define APCI1710_INCCPT_DISABLELATCHINTERRUPT 401 -#define APCI1710_INCCPT_WRITE16BITCOUNTERVALUE 402 -#define APCI1710_INCCPT_WRITE32BITCOUNTERVALUE 403 -#define APCI1710_INCCPT_ENABLEINDEX 404 -#define APCI1710_INCCPT_DISABLEINDEX 405 -#define APCI1710_INCCPT_ENABLECOMPARELOGIC 406 -#define APCI1710_INCCPT_DISABLECOMPARELOGIC 407 -#define APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT 408 -#define APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT 409 - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_CounterRange, | -| unsigned char_ b_FirstCounterModus, | -| unsigned char_ b_FirstCounterOption, | -| unsigned char_ b_SecondCounterModus, | -| unsigned char_ b_SecondCounterOption) | -+----------------------------------------------------------------------------+ -| Task : Configure the counter operating mode from selected | -| module (b_ModulNbr). You must calling this function be | -| for you call any other function witch access of | -| counters. | -| | -| Counter range | -| ------------- | -| +------------------------------------+-----------------------------------+ | -| | Parameter Passed value | Description | | -| |------------------------------------+-----------------------------------| | -| |b_ModulNbr APCI1710_16BIT_COUNTER | The module is configured for | | -| | | two 16-bit counter. | | -| | | - b_FirstCounterModus and | | -| | | b_FirstCounterOption | | -| | | configure the first 16 bit | | -| | | counter. | | -| | | - b_SecondCounterModus and | | -| | | b_SecondCounterOption | | -| | | configure the second 16 bit | | -| | | counter. | | -| |------------------------------------+-----------------------------------| | -| |b_ModulNbr APCI1710_32BIT_COUNTER | The module is configured for one | | -| | | 32-bit counter. | | -| | | - b_FirstCounterModus and | | -| | | b_FirstCounterOption | | -| | | configure the 32 bit counter. | | -| | | - b_SecondCounterModus and | | -| | | b_SecondCounterOption | | -| | | are not used and have no | | -| | | importance. | | -| +------------------------------------+-----------------------------------+ | -| | -| Counter operating mode | -| ---------------------- | -| | -| +--------------------+-------------------------+-------------------------+ | -| | Parameter | Passed value | Description | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_QUADRUPLE_MODE | In the quadruple mode, | | -| | or | | the edge analysis | | -| |b_SecondCounterModus| | circuit generates a | | -| | | | counting pulse from | | -| | | | each edge of 2 signals | | -| | | | which are phase shifted | | -| | | | in relation to each | | -| | | | other. | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_DOUBLE_MODE | Functions in the same | | -| | or | | way as the quadruple | | -| |b_SecondCounterModus| | mode, except that only | | -| | | | two of the four edges | | -| | | | are analysed per | | -| | | | period | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_SIMPLE_MODE | Functions in the same | | -| | or | | way as the quadruple | | -| |b_SecondCounterModus| | mode, except that only | | -| | | | one of the four edges | | -| | | | is analysed per | | -| | | | period. | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_DIRECT_MODE | In the direct mode the | | -| | or | | both edge analysis | | -| |b_SecondCounterModus| | circuits are inactive. | | -| | | | The inputs A, B in the | | -| | | | 32-bit mode or A, B and | | -| | | | C, D in the 16-bit mode | | -| | | | represent, each, one | | -| | | | clock pulse gate circuit| | -| | | | There by frequency and | | -| | | | pulse duration | | -| | | | measurements can be | | -| | | | performed. | | -| +--------------------+-------------------------+-------------------------+ | -| | -| | -| IMPORTANT! | -| If you have configured the module for two 16-bit counter, a mixed | -| mode with a counter in quadruple/double/single mode | -| and the other counter in direct mode is not possible! | -| | -| | -| Counter operating option for quadruple/double/simple mode | -| --------------------------------------------------------- | -| | -| +----------------------+-------------------------+------------------------+| -| | Parameter | Passed value | Description || -| |----------------------+-------------------------+------------------------|| -| |b_FirstCounterOption | APCI1710_HYSTERESIS_ON | In both edge analysis || -| | or | | circuits is available || -| |b_SecondCounterOption | | one hysteresis circuit.|| -| | | | It suppresses each || -| | | | time the first counting|| -| | | | pulse after a change || -| | | | of rotation. || -| |----------------------+-------------------------+------------------------|| -| |b_FirstCounterOption | APCI1710_HYSTERESIS_OFF | The first counting || -| | or | | pulse is not suppress || -| |b_SecondCounterOption | | after a change of || -| | | | rotation. || -| +----------------------+-------------------------+------------------------+| -| | -| | -| IMPORTANT! | -| This option are only avaible if you have selected the direct mode. | -| | -| | -| Counter operating option for direct mode | -| ---------------------------------------- | -| | -| +----------------------+--------------------+----------------------------+ | -| | Parameter | Passed value | Description | | -| |----------------------+--------------------+----------------------------| | -| |b_FirstCounterOption | APCI1710_INCREMENT | The counter increment for | | -| | or | | each counting pulse | | -| |b_SecondCounterOption | | | | -| |----------------------+--------------------+----------------------------| | -| |b_FirstCounterOption | APCI1710_DECREMENT | The counter decrement for | | -| | or | | each counting pulse | | -| |b_SecondCounterOption | | | | -| +----------------------+--------------------+----------------------------+ | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_CounterRange : Selection form counter | -| range. | -| unsigned char_ b_FirstCounterModus : First counter operating | -| mode. | -| unsigned char_ b_FirstCounterOption : First counter option. | -| unsigned char_ b_SecondCounterModus : Second counter operating | -| mode. | -| unsigned char_ b_SecondCounterOption : Second counter option. | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module is not a counter module | -| -3: The selected counter range is wrong. | -| -4: The selected first counter operating mode is wrong. | -| -5: The selected first counter operating option is wrong| -| -6: The selected second counter operating mode is wrong.| -| -7: The selected second counter operating option is | -| wrong. | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InitCounter(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_CounterRange, - unsigned char b_FirstCounterModus, - unsigned char b_FirstCounterOption, - unsigned char b_SecondCounterModus, - unsigned char b_SecondCounterOption) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - /**************************/ - /* Test the counter range */ - /**************************/ - - if (b_CounterRange == APCI1710_16BIT_COUNTER - || b_CounterRange == APCI1710_32BIT_COUNTER) { - /********************************/ - /* Test the first counter modus */ - /********************************/ - - if (b_FirstCounterModus == APCI1710_QUADRUPLE_MODE || - b_FirstCounterModus == APCI1710_DOUBLE_MODE || - b_FirstCounterModus == APCI1710_SIMPLE_MODE || - b_FirstCounterModus == APCI1710_DIRECT_MODE) { - /*********************************/ - /* Test the first counter option */ - /*********************************/ - - if ((b_FirstCounterModus == APCI1710_DIRECT_MODE - && (b_FirstCounterOption == - APCI1710_INCREMENT - || b_FirstCounterOption - == APCI1710_DECREMENT)) - || (b_FirstCounterModus != - APCI1710_DIRECT_MODE - && (b_FirstCounterOption == - APCI1710_HYSTERESIS_ON - || b_FirstCounterOption - == - APCI1710_HYSTERESIS_OFF))) - { - /**************************/ - /* Test if 16-bit counter */ - /**************************/ - - if (b_CounterRange == - APCI1710_16BIT_COUNTER) { - /*********************************/ - /* Test the second counter modus */ - /*********************************/ - - if ((b_FirstCounterModus != - APCI1710_DIRECT_MODE - && - (b_SecondCounterModus - == - APCI1710_QUADRUPLE_MODE - || - b_SecondCounterModus - == - APCI1710_DOUBLE_MODE - || - b_SecondCounterModus - == - APCI1710_SIMPLE_MODE)) - || (b_FirstCounterModus - == - APCI1710_DIRECT_MODE - && - b_SecondCounterModus - == - APCI1710_DIRECT_MODE)) - { - /**********************************/ - /* Test the second counter option */ - /**********************************/ - - if ((b_SecondCounterModus == APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_INCREMENT || b_SecondCounterOption == APCI1710_DECREMENT)) || (b_SecondCounterModus != APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_HYSTERESIS_ON || b_SecondCounterOption == APCI1710_HYSTERESIS_OFF))) { - i_ReturnValue = - 0; - } else { - /*********************************************************/ - /* The selected second counter operating option is wrong */ - /*********************************************************/ - - DPRINTK("The selected second counter operating option is wrong\n"); - i_ReturnValue = - -7; - } - } else { - /*******************************************************/ - /* The selected second counter operating mode is wrong */ - /*******************************************************/ - - DPRINTK("The selected second counter operating mode is wrong\n"); - i_ReturnValue = -6; - } - } - } else { - /********************************************************/ - /* The selected first counter operating option is wrong */ - /********************************************************/ - - DPRINTK("The selected first counter operating option is wrong\n"); - i_ReturnValue = -5; - } - } else { - /******************************************************/ - /* The selected first counter operating mode is wrong */ - /******************************************************/ - DPRINTK("The selected first counter operating mode is wrong\n"); - i_ReturnValue = -4; - } - } else { - /***************************************/ - /* The selected counter range is wrong */ - /***************************************/ - - DPRINTK("The selected counter range is wrong\n"); - i_ReturnValue = -3; - } - - /*************************/ - /* Test if a error occur */ - /*************************/ - - if (i_ReturnValue == 0) { - /**************************/ - /* Test if 16-Bit counter */ - /**************************/ - - if (b_CounterRange == APCI1710_32BIT_COUNTER) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 = b_CounterRange | - b_FirstCounterModus | - b_FirstCounterOption; - } else { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 = b_CounterRange | - (b_FirstCounterModus & 0x5) | - (b_FirstCounterOption & 0x20) | - (b_SecondCounterModus & 0xA) | - (b_SecondCounterOption & 0x40); - - /***********************/ - /* Test if direct mode */ - /***********************/ - - if (b_FirstCounterModus == APCI1710_DIRECT_MODE) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 | - APCI1710_DIRECT_MODE; - } - } - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CounterInit = 1; - } - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_CounterAutoTest | -| (unsigned char_ b_BoardHandle, | -| unsigned char *_ pb_TestStatus) | -+----------------------------------------------------------------------------+ -| Task : A test mode is intended for testing the component and | -| the connected periphery. All the 8-bit counter chains | -| are operated internally as down counters. | -| Independently from the external signals, | -| all the four 8-bit counter chains are decremented in | -| parallel by each negative clock pulse edge of CLKX. | -| | -| Counter auto test conclusion | -| ---------------------------- | -| +-----------------+-----------------------------+ | -| | pb_TestStatus | Error description | | -| | mask | | | -| |-----------------+-----------------------------| | -| | 0000 | No error detected | | -| |-----------------|-----------------------------| | -| | 0001 | Error detected of counter 0 | | -| |-----------------|-----------------------------| | -| | 0010 | Error detected of counter 1 | | -| |-----------------|-----------------------------| | -| | 0100 | Error detected of counter 2 | | -| |-----------------|-----------------------------| | -| | 1000 | Error detected of counter 3 | | -| +-----------------+-----------------------------+ | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TestStatus : Auto test conclusion. See table| -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_CounterAutoTest(struct comedi_device *dev, - unsigned char *pb_TestStatus) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_ModulCpt = 0; - int i_ReturnValue = 0; - unsigned int dw_LathchValue; - - *pb_TestStatus = 0; - - /********************************/ - /* Test if counter module found */ - /********************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[0] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[1] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[2] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[3] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulCpt] & - 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - /******************/ - /* Start the test */ - /******************/ - - outl(3, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulCpt)); - - /*********************/ - /* Tatch the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulCpt)); - - /************************/ - /* Read the latch value */ - /************************/ - - dw_LathchValue = inl(devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulCpt)); - - if ((dw_LathchValue & 0xFF) != - ((dw_LathchValue >> 8) & 0xFF) - && (dw_LathchValue & 0xFF) != - ((dw_LathchValue >> 16) & 0xFF) - && (dw_LathchValue & 0xFF) != - ((dw_LathchValue >> 24) & 0xFF)) { - *pb_TestStatus = - *pb_TestStatus | (1 << - b_ModulCpt); - } - - /*****************/ - /* Stop the test */ - /*****************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulCpt)); - } - } - } else { - /***************************/ - /* No counter module found */ - /***************************/ - - DPRINTK("No counter module found\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitIndex (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ReferenceAction, | -| unsigned char_ b_IndexOperation, | -| unsigned char_ b_AutoMode, | -| unsigned char_ b_InterruptEnable) | -+----------------------------------------------------------------------------+ -| Task : Initialise the index corresponding to the selected | -| module (b_ModulNbr). If a INDEX flag occur, you have | -| the possibility to clear the 32-Bit counter or to latch| -| the current 32-Bit value in to the first latch | -| register. The b_IndexOperation parameter give the | -| possibility to choice the INDEX action. | -| If you have enabled the automatic mode, each INDEX | -| action is cleared automatically, else you must read | -| the index status ("i_APCI1710_ReadIndexStatus") | -| after each INDEX action. | -| | -| | -| Index action | -| ------------ | -| | -| +------------------------+------------------------------------+ | -| | b_IndexOperation | Operation | | -| |------------------------+------------------------------------| | -| |APCI1710_LATCH_COUNTER | After a index signal, the counter | | -| | | value (32-Bit) is latched in to | | -| | | the first latch register | | -| |------------------------|------------------------------------| | -| |APCI1710_CLEAR_COUNTER | After a index signal, the counter | | -| | | value is cleared (32-Bit) | | -| +------------------------+------------------------------------+ | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ReferenceAction : Determine if the reference | -| must set or no for the | -| acceptance from index | -| APCI1710_ENABLE : | -| Reference must be set for | -| accepted the index | -| APCI1710_DISABLE : | -| Reference have not | -| importance | -| unsigned char_ b_IndexOperation : Index operating mode. | -| See table. | -| unsigned char_ b_AutoMode : Enable or disable the | -| automatic index reset. | -| APCI1710_ENABLE : | -| Enable the automatic mode | -| APCI1710_DISABLE : | -| Disable the automatic mode | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| interrupt. | -| APCI1710_ENABLE : | -| Enable the interrupt | -| APCI1710_DISABLE : | -| Disable the interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4 The reference action parameter is wrong | -| -5: The index operating mode parameter is wrong | -| -6: The auto mode parameter is wrong | -| -7: Interrupt parameter is wrong | -| -8: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InitIndex(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_ReferenceAction, - unsigned char b_IndexOperation, - unsigned char b_AutoMode, - unsigned char b_InterruptEnable) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************/ - /* Test the reference parameter */ - /********************************/ - - if (b_ReferenceAction == APCI1710_ENABLE || - b_ReferenceAction == APCI1710_DISABLE) { - /****************************/ - /* Test the index parameter */ - /****************************/ - - if (b_IndexOperation == - APCI1710_HIGH_EDGE_LATCH_COUNTER - || b_IndexOperation == - APCI1710_LOW_EDGE_LATCH_COUNTER - || b_IndexOperation == - APCI1710_HIGH_EDGE_CLEAR_COUNTER - || b_IndexOperation == - APCI1710_LOW_EDGE_CLEAR_COUNTER - || b_IndexOperation == - APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER - || b_IndexOperation == - APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) - { - /********************************/ - /* Test the auto mode parameter */ - /********************************/ - - if (b_AutoMode == APCI1710_ENABLE || - b_AutoMode == APCI1710_DISABLE) - { - /***************************/ - /* Test the interrupt mode */ - /***************************/ - - if (b_InterruptEnable == - APCI1710_ENABLE - || b_InterruptEnable == - APCI1710_DISABLE) { - - /************************************/ - /* Makte the configuration commando */ - /************************************/ - - if (b_ReferenceAction == - APCI1710_ENABLE) - { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - | - APCI1710_ENABLE_INDEX_ACTION; - } else { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - & - APCI1710_DISABLE_INDEX_ACTION; - } - - /****************************************/ - /* Test if low level latch or/and clear */ - /****************************************/ - - if (b_IndexOperation == - APCI1710_LOW_EDGE_LATCH_COUNTER - || - b_IndexOperation - == - APCI1710_LOW_EDGE_CLEAR_COUNTER - || - b_IndexOperation - == - APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) - { - /*************************************/ - /* Set the index level to low (DQ26) */ - /*************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_SET_LOW_INDEX_LEVEL; - } else { - /**************************************/ - /* Set the index level to high (DQ26) */ - /**************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_SET_HIGH_INDEX_LEVEL; - } - - /***********************************/ - /* Test if latch and clear counter */ - /***********************************/ - - if (b_IndexOperation == - APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER - || - b_IndexOperation - == - APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) - { - /***************************************/ - /* Set the latch and clear flag (DQ27) */ - /***************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_ENABLE_LATCH_AND_CLEAR; - } /* if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */ - else { - /*****************************************/ - /* Clear the latch and clear flag (DQ27) */ - /*****************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_DISABLE_LATCH_AND_CLEAR; - - /*************************/ - /* Test if latch counter */ - /*************************/ - - if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_COUNTER) { - /*********************************/ - /* Enable the latch from counter */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - | - APCI1710_INDEX_LATCH_COUNTER; - } else { - /*********************************/ - /* Enable the clear from counter */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - & - (~APCI1710_INDEX_LATCH_COUNTER); - } - } /* // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */ - - if (b_AutoMode == - APCI1710_DISABLE) - { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - | - APCI1710_INDEX_AUTO_MODE; - } else { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - & - (~APCI1710_INDEX_AUTO_MODE); - } - - if (b_InterruptEnable == - APCI1710_ENABLE) - { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - | - APCI1710_ENABLE_INDEX_INT; - } else { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - & - APCI1710_DISABLE_INDEX_INT; - } - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_IndexInit = 1; - - } else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue = -7; - } - } else { - /************************************/ - /* The auto mode parameter is wrong */ - /************************************/ - - DPRINTK("The auto mode parameter is wrong\n"); - i_ReturnValue = -6; - } - } else { - /***********************************************/ - /* The index operating mode parameter is wrong */ - /***********************************************/ - - DPRINTK("The index operating mode parameter is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*******************************************/ - /* The reference action parameter is wrong */ - /*******************************************/ - - DPRINTK("The reference action parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitReference | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ReferenceLevel) | -+----------------------------------------------------------------------------+ -| Task : Initialise the reference corresponding to the selected | -| module (b_ModulNbr). | -| | -| Reference level | -| --------------- | -| +--------------------+-------------------------+ | -| | b_ReferenceLevel | Operation | | -| +--------------------+-------------------------+ | -| | APCI1710_LOW | Reference occur if "0" | | -| |--------------------|-------------------------| | -| | APCI1710_HIGH | Reference occur if "1" | | -| +--------------------+-------------------------+ | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ReferenceLevel : Reference level. | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number parameter is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Reference level parameter is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InitReference(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_ReferenceLevel) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /**************************************/ - /* Test the reference level parameter */ - /**************************************/ - - if (b_ReferenceLevel == 0 || b_ReferenceLevel == 1) { - if (b_ReferenceLevel == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 | - APCI1710_REFERENCE_HIGH; - } else { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & - APCI1710_REFERENCE_LOW; - } - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_ReferenceInit = 1; - } else { - /**************************************/ - /* Reference level parameter is wrong */ - /**************************************/ - - DPRINTK("Reference level parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitExternalStrobe | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ExternalStrobe, | -| unsigned char_ b_ExternalStrobeLevel) | -+----------------------------------------------------------------------------+ -| Task : Initialises the external strobe level corresponding to | -| the selected module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ExternalStrobe : External strobe selection | -| 0 : External strobe A | -| 1 : External strobe B | -| unsigned char_ b_ExternalStrobeLevel : External strobe level | -| APCI1710_LOW : | -| External latch occurs if "0" | -| APCI1710_HIGH : | -| External latch occurs if "1" | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised. | -| See function "i_APCI1710_InitCounter" | -| -4: External strobe selection is wrong | -| -5: External strobe level parameter is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InitExternalStrobe(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_ExternalStrobe, - unsigned char b_ExternalStrobeLevel) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /**************************************/ - /* Test the external strobe selection */ - /**************************************/ - - if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) { - /******************/ - /* Test the level */ - /******************/ - - if ((b_ExternalStrobeLevel == APCI1710_HIGH) || - ((b_ExternalStrobeLevel == APCI1710_LOW - && (devpriv-> - s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3135))) { - /*****************/ - /* Set the level */ - /*****************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 = (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 & (0xFF - - (0x10 << b_ExternalStrobe))) | ((b_ExternalStrobeLevel ^ 1) << (4 + b_ExternalStrobe)); - } else { - /********************************************/ - /* External strobe level parameter is wrong */ - /********************************************/ - - DPRINTK("External strobe level parameter is wrong\n"); - i_ReturnValue = -5; - } - } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */ - else { - /**************************************/ - /* External strobe selection is wrong */ - /**************************************/ - - DPRINTK("External strobe selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */ - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_InitCompareLogic | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned int_ ui_CompareValue) | - +----------------------------------------------------------------------------+ - | Task : Set the 32-Bit compare value. At that moment that the | - | incremental counter arrive to the compare value | - | (ui_CompareValue) a interrupt is generated. | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Module number to configure | - | (0 to 3) | - | unsigned int_ ui_CompareValue : 32-Bit compare value | - +----------------------------------------------------------------------------+ - | Output Parameters : - - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: No counter module found | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - +----------------------------------------------------------------------------+ - */ -static int i_APCI1710_InitCompareLogic(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ui_CompareValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - - outl(ui_CompareValue, devpriv->s_BoardInfos. - ui_Address + 28 + (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CompareLogicInit = 1; - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitFrequencyMeasurement | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_TimingUnity, | -| ULONG_ ul_TimingInterval, | -| PULONG_ pul_RealTimingInterval) | -+----------------------------------------------------------------------------+ -| Task : Sets the time for the frequency measurement. | -| Configures the selected TOR incremental counter of the | -| selected module (b_ModulNbr). The ul_TimingInterval and| -| ul_TimingUnity determine the time base for the | -| measurement. The pul_RealTimingInterval returns the | -| real time value. You must call up this function before | -| you call up any other function which gives access to | -| the frequency measurement. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -| unsigned char_ b_PCIInputClock : Selection of the PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC has a PCI bus clock | -| of 30 MHz | -| - APCI1710_33MHZ : | -| The PC has a PCI bus clock | -| of 33 MHz | -| unsigned char_ b_TimingUnity : Base time unit (0 to 2) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| ULONG_ ul_TimingInterval: Base time value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealTimingInterval : Real base time value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected PCI input clock is wrong | -| -5: Timing unity selection is wrong | -| -6: Base timing selection is wrong | -| -7: 40MHz quartz not on board | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PCIInputClock, - unsigned char b_TimingUnity, - unsigned int ul_TimingInterval, - unsigned int *pul_RealTimingInterval) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int ul_TimerValue = 0; - double d_RealTimingInterval; - unsigned int dw_Status = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ)) { - /************************/ - /* Test the timing unit */ - /************************/ - - if (b_TimingUnity <= 2) { - /**********************************/ - /* Test the base timing selection */ - /**********************************/ - - if (((b_PCIInputClock == APCI1710_30MHZ) - && (b_TimingUnity == 0) - && (ul_TimingInterval >= - 266) - && (ul_TimingInterval <= - 8738133UL)) - || ((b_PCIInputClock == - APCI1710_30MHZ) - && (b_TimingUnity == 1) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 8738UL)) - || ((b_PCIInputClock == - APCI1710_30MHZ) - && (b_TimingUnity == 2) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 8UL)) - || ((b_PCIInputClock == - APCI1710_33MHZ) - && (b_TimingUnity == 0) - && (ul_TimingInterval >= - 242) - && (ul_TimingInterval <= - 7943757UL)) - || ((b_PCIInputClock == - APCI1710_33MHZ) - && (b_TimingUnity == 1) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 7943UL)) - || ((b_PCIInputClock == - APCI1710_33MHZ) - && (b_TimingUnity == 2) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 7UL)) - || ((b_PCIInputClock == - APCI1710_40MHZ) - && (b_TimingUnity == 0) - && (ul_TimingInterval >= - 200) - && (ul_TimingInterval <= - 6553500UL)) - || ((b_PCIInputClock == - APCI1710_40MHZ) - && (b_TimingUnity == 1) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 6553UL)) - || ((b_PCIInputClock == - APCI1710_40MHZ) - && (b_TimingUnity == 2) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 6UL))) { - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == - APCI1710_40MHZ) { - /******************************/ - /* Test if firmware >= Rev1.5 */ - /******************************/ - - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3135) { - /*********************************/ - /* Test if 40MHz quartz on board */ - /*********************************/ - - /*INPDW (ps_APCI1710Variable-> - s_Board [b_BoardHandle]. - s_BoardInfos. - ui_Address + 36 + (64 * b_ModulNbr), &dw_Status); */ - dw_Status = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + 36 + - (64 * b_ModulNbr)); - - /******************************/ - /* Test the quartz flag (DQ0) */ - /******************************/ - - if ((dw_Status & 1) != 1) { - /*****************************/ - /* 40MHz quartz not on board */ - /*****************************/ - - DPRINTK("40MHz quartz not on board\n"); - i_ReturnValue - = - -7; - } - } else { - /*****************************/ - /* 40MHz quartz not on board */ - /*****************************/ - DPRINTK("40MHz quartz not on board\n"); - i_ReturnValue = - -7; - } - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /***************************/ - /* Test if not error occur */ - /***************************/ - - if (i_ReturnValue == 0) { - /****************************/ - /* Test the INC_CPT version */ - /****************************/ - - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131) { - - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == APCI1710_40MHZ) { - /*********************************/ - /* Enable the 40MHz quarz (DQ30) */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_ENABLE_40MHZ_FREQUENCY; - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - else { - /**********************************/ - /* Disable the 40MHz quarz (DQ30) */ - /**********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_DISABLE_40MHZ_FREQUENCY; - - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /********************************/ - /* Calculate the division fator */ - /********************************/ - - fpu_begin(); - switch (b_TimingUnity) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.00025 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.00025 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (0.00025 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) { - *pul_RealTimingInterval - = - *pul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.25 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.25 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - ( - (double) - 0.25 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) { - *pul_RealTimingInterval - = - *pul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - ul_TimingInterval - * - (250.0 - * - b_PCIInputClock); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (250.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) { - *pul_RealTimingInterval - = - *pul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - break; - } - - fpu_end(); - /*************************/ - /* Write the timer value */ - /*************************/ - - outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 32 + (64 * b_ModulNbr)); - - /*******************************/ - /* Set the initialisation flag */ - /*******************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementInit - = 1; - } else { - /***************************/ - /* Counter not initialised */ - /***************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = - -3; - } - } /* if (i_ReturnValue == 0) */ - } else { - /**********************************/ - /* Base timing selection is wrong */ - /**********************************/ - - DPRINTK("Base timing selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /***********************************/ - /* Timing unity selection is wrong */ - /***********************************/ - - DPRINTK("Timing unity selection is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* - * Configuration function for INC_CPT - */ -static int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_ConfigType; - int i_ReturnValue = 0; - - ui_ConfigType = CR_CHAN(insn->chanspec); - - printk("\nINC_CPT"); - - devpriv->tsk_Current = current; /* Save the current process task structure */ - switch (ui_ConfigType) { - case APCI1710_INCCPT_INITCOUNTER: - i_ReturnValue = i_APCI1710_InitCounter(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], - (unsigned char) data[2], (unsigned char) data[3], (unsigned char) data[4]); - break; - - case APCI1710_INCCPT_COUNTERAUTOTEST: - i_ReturnValue = i_APCI1710_CounterAutoTest(dev, - (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_INITINDEX: - i_ReturnValue = i_APCI1710_InitIndex(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], (unsigned char) data[2], (unsigned char) data[3]); - break; - - case APCI1710_INCCPT_INITREFERENCE: - i_ReturnValue = i_APCI1710_InitReference(dev, - CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_INITEXTERNALSTROBE: - i_ReturnValue = i_APCI1710_InitExternalStrobe(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], (unsigned char) data[1]); - break; - - case APCI1710_INCCPT_INITCOMPARELOGIC: - i_ReturnValue = i_APCI1710_InitCompareLogic(dev, - CR_AREF(insn->chanspec), (unsigned int) data[0]); - break; - - case APCI1710_INCCPT_INITFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_InitFrequencyMeasurement(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], (unsigned int) data[2], (unsigned int *) &data[0]); - break; - - default: - printk("Insn Config : Config Parameter Wrong\n"); - - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ClearCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Clear the counter value from selected module | -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number parameter is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_ClearCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************/ - /* Clear the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ClearAllCounterValue | -| (unsigned char_ b_BoardHandle) | -+----------------------------------------------------------------------------+ -| Task : Clear all counter value. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_ClearAllCounterValue(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_ModulCpt = 0; - int i_ReturnValue = 0; - - /********************************/ - /* Test if counter module found */ - /********************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[0] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[1] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[2] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[3] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulCpt] & - 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - /*********************/ - /* Clear the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulCpt)); - } - } - } else { - /***************************/ - /* No counter module found */ - /***************************/ - - DPRINTK("No counter module found\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetInputFilter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_Module, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_Filter) | -+----------------------------------------------------------------------------+ -| Task : Disable or enable the software filter from selected | -| module (b_ModulNbr). b_Filter determine the filter time| -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -| unsigned char_ b_PCIInputClock : Selection of the PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC has a PCI bus clock | -| of 30 MHz | -| - APCI1710_33MHZ : | -| The PC has a PCI bus clock | -| of 33 MHz | -| - APCI1710_40MHZ : | -| The APCI1710 has a 40MHz | -| quartz | -| unsigned char_ b_Filter : Filter selection | -| | -| 30 MHz | -| ------ | -| 0: Software filter not used | -| 1: Filter from 266ns (3.750000MHz) | -| 2: Filter from 400ns (2.500000MHz) | -| 3: Filter from 533ns (1.876170MHz) | -| 4: Filter from 666ns (1.501501MHz) | -| 5: Filter from 800ns (1.250000MHz) | -| 6: Filter from 933ns (1.071800MHz) | -| 7: Filter from 1066ns (0.938080MHz) | -| 8: Filter from 1200ns (0.833333MHz) | -| 9: Filter from 1333ns (0.750000MHz) | -| 10: Filter from 1466ns (0.682100MHz) | -| 11: Filter from 1600ns (0.625000MHz) | -| 12: Filter from 1733ns (0.577777MHz) | -| 13: Filter from 1866ns (0.535900MHz) | -| 14: Filter from 2000ns (0.500000MHz) | -| 15: Filter from 2133ns (0.468800MHz) | -| | -| 33 MHz | -| ------ | -| 0: Software filter not used | -| 1: Filter from 242ns (4.125000MHz) | -| 2: Filter from 363ns (2.754820MHz) | -| 3: Filter from 484ns (2.066115MHz) | -| 4: Filter from 605ns (1.652892MHz) | -| 5: Filter from 726ns (1.357741MHz) | -| 6: Filter from 847ns (1.180637MHz) | -| 7: Filter from 968ns (1.033055MHz) | -| 8: Filter from 1089ns (0.918273MHz) | -| 9: Filter from 1210ns (0.826446MHz) | -| 10: Filter from 1331ns (0.751314MHz) | -| 11: Filter from 1452ns (0.688705MHz) | -| 12: Filter from 1573ns (0.635727MHz) | -| 13: Filter from 1694ns (0.590318MHz) | -| 14: Filter from 1815ns (0.550964MHz) | -| 15: Filter from 1936ns (0.516528MHz) | -| | -| 40 MHz | -| ------ | -| 0: Software filter not used | -| 1: Filter from 200ns (5.000000MHz) | -| 2: Filter from 300ns (3.333333MHz) | -| 3: Filter from 400ns (2.500000MHz) | -| 4: Filter from 500ns (2.000000MHz) | -| 5: Filter from 600ns (1.666666MHz) | -| 6: Filter from 700ns (1.428500MHz) | -| 7: Filter from 800ns (1.250000MHz) | -| 8: Filter from 900ns (1.111111MHz) | -| 9: Filter from 1000ns (1.000000MHz) | -| 10: Filter from 1100ns (0.909090MHz) | -| 11: Filter from 1200ns (0.833333MHz) | -| 12: Filter from 1300ns (0.769200MHz) | -| 13: Filter from 1400ns (0.714200MHz) | -| 14: Filter from 1500ns (0.666666MHz) | -| 15: Filter from 1600ns (0.625000MHz) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: The module is not a counter module | -| -4: The selected PCI input clock is wrong | -| -5: The selected filter value is wrong | -| -6: 40MHz quartz not on board | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_SetInputFilter(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PCIInputClock, - unsigned char b_Filter) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) { - /******************************/ - /* Test if firmware >= Rev1.5 */ - /******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF) >= 0x3135) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ)) { - /*************************/ - /* Test the filter value */ - /*************************/ - - if (b_Filter < 16) { - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == - APCI1710_40MHZ) { - /*********************************/ - /* Test if 40MHz quartz on board */ - /*********************************/ - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + - 36 + - (64 * b_ModulNbr)); - - /******************************/ - /* Test the quartz flag (DQ0) */ - /******************************/ - - if ((dw_Status & 1) != - 1) { - /*****************************/ - /* 40MHz quartz not on board */ - /*****************************/ - - DPRINTK("40MHz quartz not on board\n"); - i_ReturnValue = - -6; - } - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /***************************/ - /* Test if error not occur */ - /***************************/ - - if (i_ReturnValue == 0) { - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == - APCI1710_40MHZ) - { - /*********************************/ - /* Enable the 40MHz quarz (DQ31) */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_ENABLE_40MHZ_FILTER; - - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - else { - /**********************************/ - /* Disable the 40MHz quarz (DQ31) */ - /**********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_DISABLE_40MHZ_FILTER; - - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /************************/ - /* Set the filter value */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - & 0x1F) | - ((b_Filter & - 0x7) << - 5); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & 0xFE) | - ((b_Filter & - 0x8) >> - 3); - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv-> - s_BoardInfos. - ui_Address + - 20 + - (64 * b_ModulNbr)); - } /* if (i_ReturnValue == 0) */ - } /* if (b_Filter < 16) */ - else { - /**************************************/ - /* The selected filter value is wrong */ - /**************************************/ - - DPRINTK("The selected filter value is wrong\n"); - i_ReturnValue = -5; - } /* if (b_Filter < 16) */ - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */ - else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = 4; - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */ - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_LatchCounter (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_LatchReg) | -+----------------------------------------------------------------------------+ -| Task : Latch the courant value from selected module | -| (b_ModulNbr) in to the selected latch register | -| (b_LatchReg). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_LatchReg : Selected latch register | -| 0 : for the first latch register | -| 1 : for the second latch register | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected latch register parameter is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_LatchCounter(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_LatchReg) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test the latch register parameter */ - /*************************************/ - - if (b_LatchReg < 2) { - /*********************/ - /* Tatch the counter */ - /*********************/ - - outl(1 << (b_LatchReg * 4), - devpriv->s_BoardInfos.ui_Address + - (64 * b_ModulNbr)); - } else { - /**************************************************/ - /* The selected latch register parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected latch register parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetIndexAndReferenceSource | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SourceSelection) | -+----------------------------------------------------------------------------+ -| Task : Determine the hardware source for the index and the | -| reference logic. Per default the index logic is | -| connected to the difference input C and the reference | -| logic is connected to the 24V input E | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_SourceSelection : APCI1710_SOURCE_0 : | -| The index logic is connected | -| to the difference input C and| -| the reference logic is | -| connected to the 24V input E.| -| This is the default | -| configuration. | -| APCI1710_SOURCE_1 : | -| The reference logic is | -| connected to the difference | -| input C and the index logic | -| is connected to the 24V | -| input E | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: The module is not a counter module. | -| -4: The source selection is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_SourceSelection) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) { - /******************************/ - /* Test if firmware >= Rev1.5 */ - /******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF) >= 0x3135) { - /*****************************/ - /* Test the source selection */ - /*****************************/ - - if (b_SourceSelection == APCI1710_SOURCE_0 || - b_SourceSelection == APCI1710_SOURCE_1) - { - /******************************************/ - /* Test if invert the index and reference */ - /******************************************/ - - if (b_SourceSelection == - APCI1710_SOURCE_1) { - /********************************************/ - /* Invert index and reference source (DQ25) */ - /********************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 | - APCI1710_INVERT_INDEX_RFERENCE; - } else { - /****************************************/ - /* Set the default configuration (DQ25) */ - /****************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 & - APCI1710_DEFAULT_INDEX_RFERENCE; - } - } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */ - else { - /*********************************/ - /* The source selection is wrong */ - /*********************************/ - - DPRINTK("The source selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */ - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /***************************************/ - /* The selected module number is wrong */ - /***************************************/ - - DPRINTK("The selected module number is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetDigitalChlOn | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Sets the digital output H Setting an output means | -| setting an ouput high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_SetDigitalChlOn(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister.b_ModeRegister3 | 0x10; - - /*********************/ - /* Set the output On */ - /*********************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetDigitalChlOff | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Resets the digital output H. Resetting an output means | -| setting an ouput low. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_SetDigitalChlOff(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister.b_ModeRegister3 & 0xEF; - - /**********************/ - /* Set the output Off */ - /**********************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* - * Set & Clear Functions for INC_CPT - */ -static int i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_BitsType; - int i_ReturnValue = 0; - - ui_BitsType = CR_CHAN(insn->chanspec); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - switch (ui_BitsType) { - case APCI1710_INCCPT_CLEARCOUNTERVALUE: - i_ReturnValue = i_APCI1710_ClearCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_CLEARALLCOUNTERVALUE: - i_ReturnValue = i_APCI1710_ClearAllCounterValue(dev); - break; - - case APCI1710_INCCPT_SETINPUTFILTER: - i_ReturnValue = i_APCI1710_SetInputFilter(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], (unsigned char) data[1]); - break; - - case APCI1710_INCCPT_LATCHCOUNTER: - i_ReturnValue = i_APCI1710_LatchCounter(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE: - i_ReturnValue = i_APCI1710_SetIndexAndReferenceSource(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_SETDIGITALCHLON: - i_ReturnValue = i_APCI1710_SetDigitalChlOn(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_SETDIGITALCHLOFF: - i_ReturnValue = i_APCI1710_SetDigitalChlOff(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - default: - printk("Bits Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableLatchInterrupt | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Enable the latch interrupt from selected module | -| (b_ModulNbr). Each software or hardware latch occur a | -| interrupt. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Interrupt routine not installed see function | -| "i_APCI1710_SetBoardIntRoutine" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - - /********************/ - /* Enable interrupt */ - /********************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 | APCI1710_ENABLE_LATCH_INT; - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableLatchInterrupt | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Disable the latch interrupt from selected module | -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Interrupt routine not installed see function | -| "i_APCI1710_SetBoardIntRoutine" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4 & - ((APCI1710_DISABLE_LATCH_INT << 8) | 0xFF), - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - - mdelay(1000); - - /*********************/ - /* Disable interrupt */ - /*********************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & APCI1710_DISABLE_LATCH_INT; - - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Write16BitCounterValue | -| (unsigned char_ b_BoardHandle | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedCounter, | -| unsigned int_ ui_WriteValue) | -+----------------------------------------------------------------------------+ -| Task : Write a 16-Bit value (ui_WriteValue) in to the selected| -| 16-Bit counter (b_SelectedCounter) from selected module| -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_SelectedCounter : Selected 16-Bit counter | -| (0 or 1) | -| unsigned int_ ui_WriteValue : 16-Bit write value | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected 16-Bit counter parameter is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_Write16BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_SelectedCounter, - unsigned int ui_WriteValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /******************************/ - /* Test the counter selection */ - /******************************/ - - if (b_SelectedCounter < 2) { - /*******************/ - /* Write the value */ - /*******************/ - - outl((unsigned int) ((unsigned int) (ui_WriteValue) << (16 * - b_SelectedCounter)), - devpriv->s_BoardInfos.ui_Address + 8 + - (b_SelectedCounter * 4) + - (64 * b_ModulNbr)); - } else { - /**************************************************/ - /* The selected 16-Bit counter parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected 16-Bit counter parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Write32BitCounterValue | -| (unsigned char_ b_BoardHandle | -| unsigned char_ b_ModulNbr, | -| ULONG_ ul_WriteValue) | -+----------------------------------------------------------------------------+ -| Task : Write a 32-Bit value (ui_WriteValue) in to the selected| -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| ULONG_ ul_WriteValue : 32-Bit write value | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_Write32BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ul_WriteValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*******************/ - /* Write the value */ - /*******************/ - - outl(ul_WriteValue, devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableIndex (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Enable the INDEX actions | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Index not initialised see function | -| "i_APCI1710_InitIndex" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_EnableIndex(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int ul_InterruptLatchReg; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*****************************/ - /* Test if index initialised */ - /*****************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_IndexInit) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 | APCI1710_ENABLE_INDEX; - - ul_InterruptLatchReg = - inl(devpriv->s_BoardInfos.ui_Address + - 24 + (64 * b_ModulNbr)); - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*************************************************************/ - /* Index not initialised see function "i_APCI1710_InitIndex" */ - /*************************************************************/ - - DPRINTK("Index not initialised \n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableIndex (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Disable the INDEX actions | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Index not initialised see function | -| "i_APCI1710_InitIndex" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_DisableIndex(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*****************************/ - /* Test if index initialised */ - /*****************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_IndexInit) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & - APCI1710_DISABLE_INDEX; - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*************************************************************/ - /* Index not initialised see function "i_APCI1710_InitIndex" */ - /*************************************************************/ - - DPRINTK("Index not initialised \n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableCompareLogic | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Enable the 32-Bit compare logic. At that moment that | -| the incremental counter arrive to the compare value a | -| interrupt is generated. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Compare logic not initialised. | -| See function "i_APCI1710_InitCompareLogic" | -| -5: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_EnableCompareLogic(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test if compare logic initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CompareLogicInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 | - APCI1710_ENABLE_COMPARE_INT; - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*********************************/ - /* Compare logic not initialised */ - /*********************************/ - - DPRINTK("Compare logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableCompareLogic | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Disable the 32-Bit compare logic. -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Compare logic not initialised. | -| See function "i_APCI1710_InitCompareLogic" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_DisableCompareLogic(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test if compare logic initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CompareLogicInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_DISABLE_COMPARE_INT; - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*********************************/ - /* Compare logic not initialised */ - /*********************************/ - - DPRINTK("Compare logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_EnableFrequencyMeasurement | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned char_ b_InterruptEnable) | - +----------------------------------------------------------------------------+ - | Task : Enables the frequency measurement function | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Number of the module to be | - | configured (0 to 3) | - | unsigned char_ b_InterruptEnable: Enable or disable the | - | interrupt. | - | APCI1710_ENABLE: | - | Enable the interrupt | - | APCI1710_DISABLE: | - | Disable the interrupt | - +----------------------------------------------------------------------------+ - | Output Parameters : - | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: The selected module number is wrong | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - | -4: Frequency measurement logic not initialised. | - | See function "i_APCI1710_InitFrequencyMeasurement" | - | -5: Interrupt parameter is wrong | - | -6: Interrupt function not initialised. | - +----------------------------------------------------------------------------+ - */ -static int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_InterruptEnable) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************************/ - /* Test if frequency measurement initialised */ - /********************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_FrequencyMeasurementInit == 1) { - /***************************/ - /* Test the interrupt mode */ - /***************************/ - - if ((b_InterruptEnable == APCI1710_DISABLE) || - (b_InterruptEnable == APCI1710_ENABLE)) - { - - /************************************/ - /* Enable the frequency measurement */ - /************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 | - APCI1710_ENABLE_FREQUENCY; - - /*********************************************/ - /* Disable or enable the frequency interrupt */ - /*********************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_DISABLE_FREQUENCY_INT) - | (b_InterruptEnable << 3); - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos. - ui_Address + 20 + - (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementEnable = - 1; - } else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue = -5; - } - } else { - /***********************************************/ - /* Frequency measurement logic not initialised */ - /***********************************************/ - - DPRINTK("Frequency measurement logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_DisableFrequencyMeasurement | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr) | - +----------------------------------------------------------------------------+ - | Task : Disables the frequency measurement function | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Number of the module to be | - | configured (0 to 3) | - +----------------------------------------------------------------------------+ - | Output Parameters : - | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: The selected module number is wrong | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - | -4: Frequency measurement logic not initialised. | - | See function "i_APCI1710_InitFrequencyMeasurement" | - +----------------------------------------------------------------------------+ - */ -static int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************************/ - /* Test if frequency measurement initialised */ - /********************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_FrequencyMeasurementInit == 1) { - /*************************************/ - /* Disable the frequency measurement */ - /*************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_DISABLE_FREQUENCY - /* Begin CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */ - & APCI1710_DISABLE_FREQUENCY_INT; - /* End CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */ - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - - /*************************************/ - /* Disable the frequency measurement */ - /*************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementEnable = 0; - } else { - /***********************************************/ - /* Frequency measurement logic not initialised */ - /***********************************************/ - - DPRINTK("Frequency measurement logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* - * Enable Disable functions for INC_CPT - */ -static int i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_WriteType; - int i_ReturnValue = 0; - - ui_WriteType = CR_CHAN(insn->chanspec); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - switch (ui_WriteType) { - case APCI1710_INCCPT_ENABLELATCHINTERRUPT: - i_ReturnValue = i_APCI1710_EnableLatchInterrupt(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_DISABLELATCHINTERRUPT: - i_ReturnValue = i_APCI1710_DisableLatchInterrupt(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_WRITE16BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Write16BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], (unsigned int) data[1]); - break; - - case APCI1710_INCCPT_WRITE32BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Write32BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned int) data[0]); - - break; - - case APCI1710_INCCPT_ENABLEINDEX: - i_APCI1710_EnableIndex(dev, (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_DISABLEINDEX: - i_ReturnValue = i_APCI1710_DisableIndex(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_ENABLECOMPARELOGIC: - i_ReturnValue = i_APCI1710_EnableCompareLogic(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_DISABLECOMPARELOGIC: - i_ReturnValue = i_APCI1710_DisableCompareLogic(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_EnableFrequencyMeasurement(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_DisableFrequencyMeasurement(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - default: - printk("Write Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadLatchRegisterStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_LatchReg, | -| unsigned char *_ pb_LatchStatus) | -+----------------------------------------------------------------------------+ -| Task : Read the latch register status from selected module | -| (b_ModulNbr) and selected latch register (b_LatchReg). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_LatchReg : Selected latch register | -| 0 : for the first latch register | -| 1 : for the second latch register | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_LatchStatus : Latch register status. | -| 0 : No latch occur | -| 1 : A software latch occur | -| 2 : A hardware latch occur | -| 3 : A software and hardware | -| latch occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected latch register parameter is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_LatchReg, - unsigned char *pb_LatchStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_LatchReg; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test the latch register parameter */ - /*************************************/ - - if (b_LatchReg < 2) { - dw_LatchReg = inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - *pb_LatchStatus = - (unsigned char) ((dw_LatchReg >> (b_LatchReg * - 4)) & 0x3); - } else { - /**************************************************/ - /* The selected latch register parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected latch register parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadLatchRegisterValue | -| (unsigned char_ b_BoardHandle,| -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_LatchReg, | -| PULONG_ pul_LatchValue) | -+----------------------------------------------------------------------------+ -| Task : Read the latch register value from selected module | -| (b_ModulNbr) and selected latch register (b_LatchReg). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_LatchReg : Selected latch register | -| 0 : for the first latch register | -| 1 : for the second latch register | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_LatchValue : Latch register value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected latch register parameter is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_LatchReg, - unsigned int *pul_LatchValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test the latch register parameter */ - /*************************************/ - - if (b_LatchReg < 2) { - *pul_LatchValue = inl(devpriv->s_BoardInfos. - ui_Address + ((b_LatchReg + 1) * 4) + - (64 * b_ModulNbr)); - - } else { - /**************************************************/ - /* The selected latch register parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected latch register parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Read16BitCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedCounter, | -| unsigned int *_ pui_CounterValue) | -+----------------------------------------------------------------------------+ -| Task : Latch the selected 16-Bit counter (b_SelectedCounter) | -| from selected module (b_ModulNbr) in to the first | -| latch register and return the latched value. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_SelectedCounter : Selected 16-Bit counter | -| (0 or 1) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned int *_ pui_CounterValue : 16-Bit counter value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected 16-Bit counter parameter is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_Read16BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_SelectedCounter, - unsigned int *pui_CounterValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_LathchValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /******************************/ - /* Test the counter selection */ - /******************************/ - - if (b_SelectedCounter < 2) { - /*********************/ - /* Latch the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - /************************/ - /* Read the latch value */ - /************************/ - - dw_LathchValue = inl(devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulNbr)); - - *pui_CounterValue = - (unsigned int) ((dw_LathchValue >> (16 * - b_SelectedCounter)) & - 0xFFFFU); - } else { - /**************************************************/ - /* The selected 16-Bit counter parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected 16-Bit counter parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Read32BitCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| PULONG_ pul_CounterValue) | -+----------------------------------------------------------------------------+ -| Task : Latch the 32-Bit counter from selected module | -| (b_ModulNbr) in to the first latch register and return | -| the latched value. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_CounterValue : 32-Bit counter value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_Read32BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int *pul_CounterValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************/ - /* Tatch the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - /************************/ - /* Read the latch value */ - /************************/ - - *pul_CounterValue = inl(devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetIndexStatus (unsigned char_ b_BoardHandle,| -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_IndexStatus)| -+----------------------------------------------------------------------------+ -| Task : Return the index status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_IndexStatus : 0 : No INDEX occur | -| 1 : A INDEX occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Index not initialised see function | -| "i_APCI1710_InitIndex" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetIndexStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_IndexStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*****************************/ - /* Test if index initialised */ - /*****************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_IndexInit) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModulNbr)); - - *pb_IndexStatus = (unsigned char) (dw_StatusReg & 1); - } else { - /*************************************************************/ - /* Index not initialised see function "i_APCI1710_InitIndex" */ - /*************************************************************/ - - DPRINTK("Index not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetReferenceStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_ReferenceStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the reference status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_ReferenceStatus : 0 : No REFERENCE occur | -| 1 : A REFERENCE occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Reference not initialised see function | -| "i_APCI1710_InitReference" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetReferenceStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_ReferenceStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************************/ - /* Test if reference initialised */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_ReferenceInit) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModulNbr)); - - *pb_ReferenceStatus = - (unsigned char) (~dw_StatusReg & 1); - } else { - /*********************************************************************/ - /* Reference not initialised see function "i_APCI1710_InitReference" */ - /*********************************************************************/ - - DPRINTK("Reference not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetUASStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_UASStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the error signal (UAS) status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_UASStatus : 0 : UAS is low "0" | -| 1 : UAS is high "1" | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetUASStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_UASStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModulNbr)); - - *pb_UASStatus = (unsigned char) ((dw_StatusReg >> 1) & 1); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetCBStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_CBStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the counter overflow status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_CBStatus : 0 : Counter no overflow | -| 1 : Counter overflow | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetCBStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_CBStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulNbr)); - - *pb_CBStatus = (unsigned char) (dw_StatusReg & 1); - - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Get16BitCBStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_CBStatusCounter0, | -| unsigned char *_ pb_CBStatusCounter1) | -+----------------------------------------------------------------------------+ -| Task : Returns the counter overflow (counter initialised to | -| 2*16-bit) status from selected incremental counter | -| module | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_CBStatusCounter0 : 0 : No overflow occur for | -| the first 16-bit | -| counter | -| 1 : Overflow occur for the| -| first 16-bit counter | -| unsigned char *_ pb_CBStatusCounter1 : 0 : No overflow occur for | -| the second 16-bit | -| counter | -| 1 : Overflow occur for the| -| second 16-bit counter | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Counter not initialised to 2*16-bit mode. | -| See function "i_APCI1710_InitCounter" | -| -5: Firmware revision error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_Get16BitCBStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_CBStatusCounter0, - unsigned char *pb_CBStatusCounter1) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************/ - /* Test if 2*16-Bit mode */ - /*************************/ - - if ((devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 & 0x10) == 0x10) { - /*****************************/ - /* Test the Firmware version */ - /*****************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & 0xFFFF) >= - 0x3136) { - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - *pb_CBStatusCounter1 = - (unsigned char) ((dw_StatusReg >> 0) & - 1); - *pb_CBStatusCounter0 = - (unsigned char) ((dw_StatusReg >> 1) & - 1); - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */ - else { - /****************************/ - /* Firmware revision error */ - /****************************/ - - i_ReturnValue = -5; - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */ - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */ - else { - /********************************************/ - /* Counter not initialised to 2*16-bit mode */ - /* "i_APCI1710_InitCounter" */ - /********************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -4; - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */ - } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */ - else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */ - } /* if (b_ModulNbr < 4) */ - else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } /* if (b_ModulNbr < 4) */ - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetUDStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_UDStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the counter progress status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the | -| selected mode down | -| 1 : Counter progress in the | -| selected mode up | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetUDStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_UDStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModulNbr)); - - *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 2) & 1); - - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetInterruptUDLatchedStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_UDStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the counter progress latched status after a | -| index interrupt occur. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the | -| selected mode down | -| 1 : Counter progress in the | -| selected mode up | -| 2 : No index interrupt occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_UDStatus) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************************/ - /* Test if index interrupt occur */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_IndexInterruptOccur == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_IndexInterruptOccur = 0; - - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModulNbr)); - - *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 1) & 1); - } else { - /****************************/ - /* No index interrupt occur */ - /****************************/ - - *pb_UDStatus = 2; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_ReadFrequencyMeasurement | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned char *_ pb_Status, | - | PULONG_ pul_ReadValue) | - +----------------------------------------------------------------------------+ - | Task : Returns the status (pb_Status) and the number of | - | increments in the set time. | - | See function " i_APCI1710_InitFrequencyMeasurement " | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Number of the module to be | - | configured (0 to 3) | - +----------------------------------------------------------------------------+ - | Output Parameters : unsigned char *_ pb_Status : Returns the frequency | - | measurement status | - | 0 : Counting cycle not | - | started. | - | 1 : Counting cycle started. | - | 2 : Counting cycle stopped. | - | The measurement cycle is | - | completed. | - | unsigned char *_ pb_UDStatus : 0 : Counter progress in the | - | selected mode down | - | 1 : Counter progress in the | - | selected mode up | - | PULONG_ pul_ReadValue : Return the number of | - | increments in the defined | - | time base. | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: The selected module number is wrong | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - | -4: Frequency measurement logic not initialised. | - | See function "i_APCI1710_InitFrequencyMeasurement" | - +----------------------------------------------------------------------------+ - */ -static int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_Status, - unsigned char *pb_UDStatus, - unsigned int *pul_ReadValue) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int ui_16BitValue; - unsigned int dw_StatusReg; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************************/ - /* Test if frequency measurement initialised */ - /********************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_FrequencyMeasurementInit == 1) { - /******************/ - /* Test if enable */ - /******************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementEnable == 1) { - /*******************/ - /* Read the status */ - /*******************/ - - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + 32 + - (64 * b_ModulNbr)); - - /**************************/ - /* Test if frequency stop */ - /**************************/ - - if (dw_StatusReg & 1) { - *pb_Status = 2; - *pb_UDStatus = - (unsigned char) ((dw_StatusReg >> - 1) & 3); - - /******************/ - /* Read the value */ - /******************/ - - *pul_ReadValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 28 + - (64 * b_ModulNbr)); - - if (*pb_UDStatus == 0) { - /*************************/ - /* Test the counter mode */ - /*************************/ - - if ((devpriv->s_ModuleInfo[b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & APCI1710_16BIT_COUNTER) == APCI1710_16BIT_COUNTER) { - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFFU) != 0) { - ui_16BitValue - = - (unsigned int) - * - pul_ReadValue - & - 0xFFFFU; - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFF0000UL) - | - (0xFFFFU - - - ui_16BitValue); - } - - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFF0000UL) != 0) { - ui_16BitValue - = - (unsigned int) - ( - (*pul_ReadValue - >> - 16) - & - 0xFFFFU); - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFFUL) - | - ( - (0xFFFFU - ui_16BitValue) << 16); - } - } else { - if (*pul_ReadValue != 0) { - *pul_ReadValue - = - 0xFFFFFFFFUL - - - *pul_ReadValue; - } - } - } else { - if (*pb_UDStatus == 1) { - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFF0000UL) != 0) { - ui_16BitValue - = - (unsigned int) - ( - (*pul_ReadValue - >> - 16) - & - 0xFFFFU); - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFFUL) - | - ( - (0xFFFFU - ui_16BitValue) << 16); - } - } else { - if (*pb_UDStatus - == 2) { - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFFU) != 0) { - ui_16BitValue - = - (unsigned int) - * - pul_ReadValue - & - 0xFFFFU; - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFF0000UL) - | - (0xFFFFU - - - ui_16BitValue); - } - } - } - } - } else { - *pb_Status = 1; - *pb_UDStatus = 0; - } - } else { - *pb_Status = 0; - *pb_UDStatus = 0; - } - } else { - /***********************************************/ - /* Frequency measurement logic not initialised */ - /***********************************************/ - - DPRINTK("Frequency measurement logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} -/* - * Read and Get functions for INC_CPT - */ -static int i_APCI1710_InsnReadINCCPT(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_ReadType; - int i_ReturnValue = 0; - - ui_ReadType = CR_CHAN(insn->chanspec); - - devpriv->tsk_Current = current; /* Save the current process task structure */ - switch (ui_ReadType) { - case APCI1710_INCCPT_READLATCHREGISTERSTATUS: - i_ReturnValue = i_APCI1710_ReadLatchRegisterStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) CR_RANGE(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_READLATCHREGISTERVALUE: - i_ReturnValue = i_APCI1710_ReadLatchRegisterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]); - printk("Latch Register Value %d\n", data[0]); - break; - - case APCI1710_INCCPT_READ16BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Read16BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]); - break; - - case APCI1710_INCCPT_READ32BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Read32BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned int *) &data[0]); - break; - - case APCI1710_INCCPT_GETINDEXSTATUS: - i_ReturnValue = i_APCI1710_GetIndexStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GETREFERENCESTATUS: - i_ReturnValue = i_APCI1710_GetReferenceStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GETUASSTATUS: - i_ReturnValue = i_APCI1710_GetUASStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GETCBSTATUS: - i_ReturnValue = i_APCI1710_GetCBStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GET16BITCBSTATUS: - i_ReturnValue = i_APCI1710_Get16BitCBStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char *) &data[0], (unsigned char *) &data[1]); - break; - - case APCI1710_INCCPT_GETUDSTATUS: - i_ReturnValue = i_APCI1710_GetUDStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - - break; - - case APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS: - i_ReturnValue = i_APCI1710_GetInterruptUDLatchedStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_READFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_ReadFrequencyMeasurement(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char *) &data[0], - (unsigned char *) &data[1], (unsigned int *) &data[2]); - break; - - case APCI1710_INCCPT_READINTERRUPT: - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv->s_InterruptParameters. - ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - break; - - default: - printk("ReadType Parameter wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; - -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c deleted file mode 100644 index 6bbcb06cc27..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c +++ /dev/null @@ -1,866 +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. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : Inp_CPT.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 pulse encoder module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ -*/ - -#define APCI1710_SINGLE 0 -#define APCI1710_CONTINUOUS 1 - -#define APCI1710_PULSEENCODER_READ 0 -#define APCI1710_PULSEENCODER_WRITE 1 - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitPulseEncoder | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PulseEncoderNbr, | -| unsigned char_ b_InputLevelSelection, | -| unsigned char_ b_TriggerOutputAction, | -| ULONG_ ul_StartValue) | -+----------------------------------------------------------------------------+ -| Task : Configure the pulse encoder operating mode selected via| -| b_ModulNbr and b_PulseEncoderNbr. The pulse encoder | -| after each pulse decrement the counter value from 1. | -| | -| You must calling this function be for you call any | -| other function witch access of pulse encoders. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | -| (0 to 3) | -| unsigned char_ b_InputLevelSelection : Input level selection | -| (0 or 1) | -| 0 : Set pulse encoder| -| count the the low| -| level pulse. | -| 1 : Set pulse encoder| -| count the the | -| high level pulse.| -| unsigned char_ b_TriggerOutputAction : Digital TRIGGER output | -| action | -| 0 : No action | -| 1 : Set the trigger | -| output to "1" | -| (high) after the | -| passage from 1 to| -| 0 from pulse | -| encoder. | -| 2 : Set the trigger | -| output to "0" | -| (low) after the | -| passage from 1 to| -| 0 from pulse | -| encoder | -| ULONG_ ul_StartValue : Pulse encoder start value| -| (1 to 4294967295) - b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); - b_PulseEncoderNbr =(unsigned char) data[0]; - b_InputLevelSelection =(unsigned char) data[1]; - b_TriggerOutputAction =(unsigned char) data[2]; - ul_StartValue =(unsigned int) data[3]; - | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module is not a pulse encoder module | -| -3: Pulse encoder selection is wrong | -| -4: Input level selection is wrong | -| -5: Digital TRIGGER output action selection is wrong | -| -6: Pulse encoder start value is wrong | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_IntRegister; - unsigned char b_ModulNbr; - unsigned char b_PulseEncoderNbr; - unsigned char b_InputLevelSelection; - unsigned char b_TriggerOutputAction; - unsigned int ul_StartValue; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_PulseEncoderNbr = (unsigned char) data[0]; - b_InputLevelSelection = (unsigned char) data[1]; - b_TriggerOutputAction = (unsigned char) data[2]; - ul_StartValue = (unsigned int) data[3]; - - i_ReturnValue = insn->n; - - /***********************************/ - /* Test the selected module number */ - /***********************************/ - - if (b_ModulNbr <= 3) { - /*************************/ - /* Test if pulse encoder */ - /*************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - APCI1710_PULSE_ENCODER) == - APCI1710_PULSE_ENCODER) { - /******************************************/ - /* Test the selected pulse encoder number */ - /******************************************/ - - if (b_PulseEncoderNbr <= 3) { - /************************/ - /* Test the input level */ - /************************/ - - if ((b_InputLevelSelection == 0) - || (b_InputLevelSelection == 1)) { - /*******************************************/ - /* Test the ouput TRIGGER action selection */ - /*******************************************/ - - if ((b_TriggerOutputAction <= 2) - || (b_PulseEncoderNbr > 0)) { - if (ul_StartValue > 1) { - - dw_IntRegister = - inl(devpriv-> - s_BoardInfos. - ui_Address + - 20 + - (64 * b_ModulNbr)); - - /***********************/ - /* Set the start value */ - /***********************/ - - outl(ul_StartValue, - devpriv-> - s_BoardInfos. - ui_Address + - (b_PulseEncoderNbr - * 4) + - (64 * b_ModulNbr)); - - /***********************/ - /* Set the input level */ - /***********************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister & - (0xFFFFFFFFUL - - (1UL << (8 + b_PulseEncoderNbr)))) | ((1UL & (~b_InputLevelSelection)) << (8 + b_PulseEncoderNbr)); - - /*******************************/ - /* Test if output trigger used */ - /*******************************/ - - if ((b_TriggerOutputAction > 0) && (b_PulseEncoderNbr > 1)) { - /****************************/ - /* Enable the output action */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - | (1UL - << (4 + b_PulseEncoderNbr)); - - /*********************************/ - /* Set the output TRIGGER action */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - & - (0xFFFFFFFFUL - - - (1UL << (12 + b_PulseEncoderNbr)))) | ((1UL & (b_TriggerOutputAction - 1)) << (12 + b_PulseEncoderNbr)); - } else { - /*****************************/ - /* Disable the output action */ - /*****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - & - (0xFFFFFFFFUL - - - (1UL << (4 + b_PulseEncoderNbr))); - } - - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister, - devpriv-> - s_BoardInfos. - ui_Address + - 20 + - (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo - [b_PulseEncoderNbr]. - b_PulseEncoderInit - = 1; - } else { - /**************************************/ - /* Pulse encoder start value is wrong */ - /**************************************/ - - DPRINTK("Pulse encoder start value is wrong\n"); - i_ReturnValue = -6; - } - } else { - /****************************************************/ - /* Digital TRIGGER output action selection is wrong */ - /****************************************************/ - - DPRINTK("Digital TRIGGER output action selection is wrong\n"); - i_ReturnValue = -5; - } - } else { - /**********************************/ - /* Input level selection is wrong */ - /**********************************/ - - DPRINTK("Input level selection is wrong\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* Pulse encoder selection is wrong */ - /************************************/ - - DPRINTK("Pulse encoder selection is wrong\n"); - i_ReturnValue = -3; - } - } else { - /********************************************/ - /* The module is not a pulse encoder module */ - /********************************************/ - - DPRINTK("The module is not a pulse encoder module\n"); - i_ReturnValue = -2; - } - } else { - /********************************************/ - /* The module is not a pulse encoder module */ - /********************************************/ - - DPRINTK("The module is not a pulse encoder module\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnablePulseEncoder | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PulseEncoderNbr, | -| unsigned char_ b_CycleSelection, | -| unsigned char_ b_InterruptHandling) | -+----------------------------------------------------------------------------+ -| Task : Enableor disable the selected pulse encoder (b_PulseEncoderNbr) | -| from selected module (b_ModulNbr). Each input pulse | -| decrement the pulse encoder counter value from 1. | -| If you enabled the interrupt (b_InterruptHandling), a | -| interrupt is generated when the pulse encoder has run | -| down. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | -| (0 to 3) | -| unsigned char_ b_CycleSelection : APCI1710_CONTINUOUS: | -| Each time the | -| counting value is set| -| on "0", the pulse | -| encoder load the | -| start value after | -| the next pulse. | -| APCI1710_SINGLE: | -| If the counter is set| -| on "0", the pulse | -| encoder is stopped. | -| unsigned char_ b_InterruptHandling : Interrupts can be | -| generated, when the pulse| -| encoder has run down. | -| With this parameter the | -| user decides if | -| interrupts are used or | -| not. | -| APCI1710_ENABLE: | -| Interrupts are enabled | -| APCI1710_DISABLE: | -| Interrupts are disabled - - b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); - b_Action =(unsigned char) data[0]; - b_PulseEncoderNbr =(unsigned char) data[1]; - b_CycleSelection =(unsigned char) data[2]; - b_InterruptHandling =(unsigned char) data[3];| -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection is wrong | -| -3: Pulse encoder selection is wrong | -| -4: Pulse encoder not initialised. | -| See function "i_APCI1710_InitPulseEncoder" | -| -5: Cycle selection mode is wrong | -| -6: Interrupt handling mode is wrong | -| -7: Interrupt routine not installed. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned char b_ModulNbr; - unsigned char b_PulseEncoderNbr; - unsigned char b_CycleSelection; - unsigned char b_InterruptHandling; - unsigned char b_Action; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_Action = (unsigned char) data[0]; - b_PulseEncoderNbr = (unsigned char) data[1]; - b_CycleSelection = (unsigned char) data[2]; - b_InterruptHandling = (unsigned char) data[3]; - - /***********************************/ - /* Test the selected module number */ - /***********************************/ - - if (b_ModulNbr <= 3) { - /******************************************/ - /* Test the selected pulse encoder number */ - /******************************************/ - - if (b_PulseEncoderNbr <= 3) { - /*************************************/ - /* Test if pulse encoder initialised */ - /*************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo[b_PulseEncoderNbr]. - b_PulseEncoderInit == 1) { - switch (b_Action) { - - case APCI1710_ENABLE: - /****************************/ - /* Test the cycle selection */ - /****************************/ - - if (b_CycleSelection == - APCI1710_CONTINUOUS - || b_CycleSelection == - APCI1710_SINGLE) { - /*******************************/ - /* Test the interrupt handling */ - /*******************************/ - - if (b_InterruptHandling == - APCI1710_ENABLE - || b_InterruptHandling - == APCI1710_DISABLE) { - /******************************/ - /* Test if interrupt not used */ - /******************************/ - - if (b_InterruptHandling - == - APCI1710_DISABLE) - { - /*************************/ - /* Disable the interrupt */ - /*************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - & - (0xFFFFFFFFUL - - - (1UL << b_PulseEncoderNbr)); - } else { - - /************************/ - /* Enable the interrupt */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - | (1UL - << - b_PulseEncoderNbr); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - } - - if (i_ReturnValue >= 0) { - /***********************************/ - /* Enable or disable the interrupt */ - /***********************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister, - devpriv-> - s_BoardInfos. - ui_Address - + 20 + - (64 * b_ModulNbr)); - - /****************************/ - /* Enable the pulse encoder */ - /****************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - | (1UL - << - b_PulseEncoderNbr); - - /**********************/ - /* Set the cycle mode */ - /**********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - & - (0xFFFFFFFFUL - - - (1 << (b_PulseEncoderNbr + 4)))) | ((b_CycleSelection & 1UL) << (4 + b_PulseEncoderNbr)); - - /****************************/ - /* Enable the pulse encoder */ - /****************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister, - devpriv-> - s_BoardInfos. - ui_Address - + 16 + - (64 * b_ModulNbr)); - } - } else { - /************************************/ - /* Interrupt handling mode is wrong */ - /************************************/ - - DPRINTK("Interrupt handling mode is wrong\n"); - i_ReturnValue = -6; - } - } else { - /*********************************/ - /* Cycle selection mode is wrong */ - /*********************************/ - - DPRINTK("Cycle selection mode is wrong\n"); - i_ReturnValue = -5; - } - break; - - case APCI1710_DISABLE: - devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister & - (0xFFFFFFFFUL - - (1UL << b_PulseEncoderNbr)); - - /*****************************/ - /* Disable the pulse encoder */ - /*****************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister, - devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - break; - } /* switch End */ - - } else { - /*********************************/ - /* Pulse encoder not initialised */ - /*********************************/ - - DPRINTK("Pulse encoder not initialised\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* Pulse encoder selection is wrong */ - /************************************/ - - DPRINTK("Pulse encoder selection is wrong\n"); - i_ReturnValue = -3; - } - } else { - /*****************************/ - /* Module selection is wrong */ - /*****************************/ - - DPRINTK("Module selection is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadPulseEncoderStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PulseEncoderNbr, | -| unsigned char *_ pb_Status) | -+----------------------------------------------------------------------------+ -| Task APCI1710_PULSEENCODER_READ : Reads the pulse encoder status - and valuefrom selected pulse | -| encoder (b_PulseEncoderNbr) from selected module | -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ - unsigned char b_Type; data[0] - APCI1710_PULSEENCODER_WRITE - Writes a 32-bit value (ul_WriteValue) into the selected| -| pulse encoder (b_PulseEncoderNbr) from selected module | -| (b_ModulNbr). This operation set the new start pulse | -| encoder value. - APCI1710_PULSEENCODER_READ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| CRAREF() unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| data[1] unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | -| (0 to 3) - APCI1710_PULSEENCODER_WRITE - data[2] ULONG_ ul_WriteValue : 32-bit value to be | -| written | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_Status : Pulse encoder status. | -| 0 : No overflow occur| -| 1 : Overflow occur - PULONG_ pul_ReadValue : Pulse encoder value | | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection is wrong | -| -3: Pulse encoder selection is wrong | -| -4: Pulse encoder not initialised. | -| See function "i_APCI1710_InitPulseEncoder" | -+----------------------------------------------------------------------------+ -*/ - -/*_INT_ i_APCI1710_ReadPulseEncoderStatus (unsigned char_ b_BoardHandle, - unsigned char_ b_ModulNbr, - unsigned char_ b_PulseEncoderNbr, - - unsigned char *_ pb_Status) - */ -static int i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusRegister; - unsigned char b_ModulNbr; - unsigned char b_PulseEncoderNbr; - unsigned char *pb_Status; - unsigned char b_Type; - unsigned int *pul_ReadValue; - unsigned int ul_WriteValue; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_Type = (unsigned char) data[0]; - b_PulseEncoderNbr = (unsigned char) data[1]; - pb_Status = (unsigned char *) &data[0]; - pul_ReadValue = (unsigned int *) &data[1]; - - /***********************************/ - /* Test the selected module number */ - /***********************************/ - - if (b_ModulNbr <= 3) { - /******************************************/ - /* Test the selected pulse encoder number */ - /******************************************/ - - if (b_PulseEncoderNbr <= 3) { - /*************************************/ - /* Test if pulse encoder initialised */ - /*************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo[b_PulseEncoderNbr]. - b_PulseEncoderInit == 1) { - - switch (b_Type) { - case APCI1710_PULSEENCODER_READ: - /****************************/ - /* Read the status register */ - /****************************/ - - dw_StatusRegister = - inl(devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister | - dw_StatusRegister; - - *pb_Status = - (unsigned char) (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister >> (1 + - b_PulseEncoderNbr)) & 1; - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister & - (0xFFFFFFFFUL - (1 << (1 + - b_PulseEncoderNbr))); - - /******************/ - /* Read the value */ - /******************/ - - *pul_ReadValue = - inl(devpriv->s_BoardInfos. - ui_Address + - (4 * b_PulseEncoderNbr) + - (64 * b_ModulNbr)); - break; - - case APCI1710_PULSEENCODER_WRITE: - ul_WriteValue = (unsigned int) data[2]; - /*******************/ - /* Write the value */ - /*******************/ - - outl(ul_WriteValue, - devpriv->s_BoardInfos. - ui_Address + - (4 * b_PulseEncoderNbr) + - (64 * b_ModulNbr)); - - } /* end of switch */ - } else { - /*********************************/ - /* Pulse encoder not initialised */ - /*********************************/ - - DPRINTK("Pulse encoder not initialised\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* Pulse encoder selection is wrong */ - /************************************/ - - DPRINTK("Pulse encoder selection is wrong\n"); - i_ReturnValue = -3; - } - } else { - /*****************************/ - /* Module selection is wrong */ - /*****************************/ - - DPRINTK("Module selection is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -static int i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /***************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv->s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - return insn->n; - -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c deleted file mode 100644 index 5c830337db8..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c +++ /dev/null @@ -1,3582 +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. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : PWM.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 Wulse wide modulation module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +-----------------------------------------------------------------------+ - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ -*/ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_PWM_INIT 0 -#define APCI1710_PWM_GETINITDATA 1 - -#define APCI1710_PWM_DISABLE 0 -#define APCI1710_PWM_ENABLE 1 -#define APCI1710_PWM_NEWTIMING 2 - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitPWM | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char_ b_ClockSelection, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_LowTiming, | -| ULONG_ ul_HighTiming, | -| PULONG_ pul_RealLowTiming, | -| PULONG_ pul_RealHighTiming) | -+----------------------------------------------------------------------------+ -| Task : Configure the selected PWM (b_PWM) from selected module| -| (b_ModulNbr). The ul_LowTiming, ul_HighTiming and | -| ul_TimingUnit determine the low/high timing base for | -| the period. pul_RealLowTiming, pul_RealHighTiming | -| return the real timing value. | -| You must calling this function be for you call any | -| other function witch access of the PWM. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure| -| (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1). | -| unsigned char_ b_ClockSelection : Selection from PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC have a 30 MHz | -| PCI bus clock | -| - APCI1710_33MHZ : | -| The PC have a 33 MHz | -| PCI bus clock | -| - APCI1710_40MHZ | -| The APCI-1710 have a | -| integrated 40Mhz | -| quartz. | -| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| ULONG_ ul_LowTiming : Low base timing value. | -| ULONG_ ul_HighTiming : High base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealLowTiming : Real low base timing | -| value. | -| PULONG_ pul_RealHighTiming : Real high base timing | -| value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: The selected input clock is wrong | -| -6: Timing Unit selection is wrong | -| -7: Low base timing selection is wrong | -| -8: High base timing selection is wrong | -| -9: You can not used the 40MHz clock selection with | -| this board | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InitPWM(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char b_ClockSelection, - unsigned char b_TimingUnit, - unsigned int ul_LowTiming, - unsigned int ul_HighTiming, - unsigned int *pul_RealLowTiming, - unsigned int *pul_RealHighTiming) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int ul_LowTimerValue = 0; - unsigned int ul_HighTimerValue = 0; - unsigned int dw_Command; - double d_RealLowTiming = 0; - double d_RealHighTiming = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /******************/ - /* Test the clock */ - /******************/ - - if ((b_ClockSelection == APCI1710_30MHZ) || - (b_ClockSelection == APCI1710_33MHZ) || - (b_ClockSelection == APCI1710_40MHZ)) { - /************************/ - /* Test the timing unit */ - /************************/ - - if (b_TimingUnit <= 4) { - /*********************************/ - /* Test the low timing selection */ - /*********************************/ - - if (((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 266) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230650UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 9UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 242) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691043UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 520UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 8UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 200) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496729UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 7UL))) { - /**********************************/ - /* Test the High timing selection */ - /**********************************/ - - if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) { - /**************************/ - /* Test the board version */ - /**************************/ - - if (((b_ClockSelection == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_ClockSelection != APCI1710_40MHZ)) { - - /************************************/ - /* Calculate the low division fator */ - /************************************/ - - fpu_begin - (); - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - ul_LowTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - ( - (ul_LowTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealLowTiming - = - ( - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - } - - /*************************************/ - /* Calculate the high division fator */ - /*************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - ul_HighTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - ( - (ul_HighTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealHighTiming - = - ( - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - } - - fpu_end(); - /****************************/ - /* Save the clock selection */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - b_ClockSelection - = - b_ClockSelection; - - /************************/ - /* Save the timing unit */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_TimingUnit - = - b_TimingUnit; - - /****************************/ - /* Save the low base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_LowTiming - = - d_RealLowTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealLowTiming - = - *pul_RealLowTiming; - - /****************************/ - /* Save the high base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_HighTiming - = - d_RealHighTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealHighTiming - = - *pul_RealHighTiming; - - /************************/ - /* Write the low timing */ - /************************/ - - outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /*************************/ - /* Write the high timing */ - /*************************/ - - outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /***************************/ - /* Set the clock selection */ - /***************************/ - - dw_Command - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 8 - + - (20 * b_PWM) + (64 * b_ModulNbr)); - - dw_Command - = - dw_Command - & - 0x7F; - - if (b_ClockSelection == APCI1710_40MHZ) { - dw_Command - = - dw_Command - | - 0x80; - } - - /***************************/ - /* Set the clock selection */ - /***************************/ - - outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /*************/ - /* PWM init. */ - /*************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_PWMInit - = - 1; - } else { - /***************************************************/ - /* You can not used the 40MHz clock selection with */ - /* this board */ - /***************************************************/ - DPRINTK("You can not used the 40MHz clock selection with this board\n"); - i_ReturnValue - = - -9; - } - } else { - /***************************************/ - /* High base timing selection is wrong */ - /***************************************/ - DPRINTK("High base timing selection is wrong\n"); - i_ReturnValue = - -8; - } - } else { - /**************************************/ - /* Low base timing selection is wrong */ - /**************************************/ - DPRINTK("Low base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /**********************************/ - /* Timing unit selection is wrong */ - /**********************************/ - DPRINTK("Timing unit selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */ - else { - /*******************************/ - /* The selected clock is wrong */ - /*******************************/ - DPRINTK("The selected clock is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetPWMInitialisation | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char *_ pb_TimingUnit, | -| PULONG_ pul_LowTiming, | -| PULONG_ pul_HighTiming, | -| unsigned char *_ pb_StartLevel, | -| unsigned char *_ pb_StopMode, | -| unsigned char *_ pb_StopLevel, | -| unsigned char *_ pb_ExternGate, | -| unsigned char *_ pb_InterruptEnable, | -| unsigned char *_ pb_Enable) | -+----------------------------------------------------------------------------+ -| Task : Return the PWM (b_PWM) initialisation from selected | -| module (b_ModulNbr). You must calling the | -| "i_APCI1710_InitPWM" function be for you call this | -| function. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing Unit (0 to 4) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| PULONG_ pul_LowTiming : Low base timing value. | -| PULONG_ pul_HighTiming : High base timing value. | -| unsigned char *_ pb_StartLevel : Start period level | -| selection | -| 0 : The period start | -| with a low level | -| 1 : The period start | -| with a high level| -| unsigned char *_ pb_StopMode : Stop mode selection | -| 0 : The PWM is stopped | -| directly after the | -| "i_APCI1710_DisablePWM"| -| function and break the| -| last period | -| 1 : After the | -| "i_APCI1710_DisablePWM"| -| function the PWM is | -| stopped at the end | -| from last period cycle| -| unsigned char *_ pb_StopLevel : Stop PWM level selection | -| 0 : The output signal | -| keep the level after| -| the | -| "i_APCI1710_DisablePWM"| -| function | -| 1 : The output signal is| -| set to low after the| -| "i_APCI1710_DisablePWM"| -| function | -| 2 : The output signal is| -| set to high after | -| the | -| "i_APCI1710_DisablePWM"| -| function | -| unsigned char *_ pb_ExternGate : Extern gate action | -| selection | -| 0 : Extern gate signal | -| not used. | -| 1 : Extern gate signal | -| used. | -| unsigned char *_ pb_InterruptEnable : Enable or disable the PWM | -| interrupt. | -| - APCI1710_ENABLE : | -| Enable the PWM interrupt| -| A interrupt occur after | -| each period | -| - APCI1710_DISABLE : | -| Disable the PWM | -| interrupt | -| unsigned char *_ pb_Enable : Indicate if the PWM is | -| enabled or no | -| 0 : PWM not enabled | -| 1 : PWM enabled | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_GetPWMInitialisation(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char *pb_TimingUnit, - unsigned int *pul_LowTiming, - unsigned int *pul_HighTiming, - unsigned char *pb_StartLevel, - unsigned char *pb_StopMode, - unsigned char *pb_StopLevel, - unsigned char *pb_ExternGate, - unsigned char *pb_InterruptEnable, - unsigned char *pb_Enable) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_Command; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /***********************/ - /* Read the low timing */ - /***********************/ - - *pul_LowTiming = - inl(devpriv->s_BoardInfos. - ui_Address + 0 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - /************************/ - /* Read the high timing */ - /************************/ - - *pul_HighTiming = - inl(devpriv->s_BoardInfos. - ui_Address + 4 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - /********************/ - /* Read the command */ - /********************/ - - dw_Command = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - *pb_StartLevel = - (unsigned char) ((dw_Command >> 5) & 1); - *pb_StopMode = - (unsigned char) ((dw_Command >> 0) & 1); - *pb_StopLevel = - (unsigned char) ((dw_Command >> 1) & 1); - *pb_ExternGate = - (unsigned char) ((dw_Command >> 4) & 1); - *pb_InterruptEnable = - (unsigned char) ((dw_Command >> 3) & 1); - - if (*pb_StopLevel) { - *pb_StopLevel = - *pb_StopLevel + - (unsigned char) ((dw_Command >> - 2) & 1); - } - - /********************/ - /* Read the command */ - /********************/ - - dw_Command = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - *pb_Enable = - (unsigned char) ((dw_Command >> 0) & 1); - - *pb_TimingUnit = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo[b_PWM].b_TimingUnit; - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* - * Pwm Init and Get Pwm Initialisation - */ -static int i_APCI1710_InsnConfigPWM(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned char b_ConfigType; - int i_ReturnValue = 0; - b_ConfigType = CR_CHAN(insn->chanspec); - - switch (b_ConfigType) { - case APCI1710_PWM_INIT: - i_ReturnValue = i_APCI1710_InitPWM(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */ - (unsigned char) data[0], /* b_PWM */ - (unsigned char) data[1], /* b_ClockSelection */ - (unsigned char) data[2], /* b_TimingUnit */ - (unsigned int) data[3], /* ul_LowTiming */ - (unsigned int) data[4], /* ul_HighTiming */ - (unsigned int *) &data[0], /* pul_RealLowTiming */ - (unsigned int *) &data[1] /* pul_RealHighTiming */ - ); - break; - - case APCI1710_PWM_GETINITDATA: - i_ReturnValue = i_APCI1710_GetPWMInitialisation(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */ - (unsigned char) data[0], /* b_PWM */ - (unsigned char *) &data[0], /* pb_TimingUnit */ - (unsigned int *) &data[1], /* pul_LowTiming */ - (unsigned int *) &data[2], /* pul_HighTiming */ - (unsigned char *) &data[3], /* pb_StartLevel */ - (unsigned char *) &data[4], /* pb_StopMode */ - (unsigned char *) &data[5], /* pb_StopLevel */ - (unsigned char *) &data[6], /* pb_ExternGate */ - (unsigned char *) &data[7], /* pb_InterruptEnable */ - (unsigned char *) &data[8] /* pb_Enable */ - ); - break; - - default: - printk(" Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnablePWM | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char_ b_StartLevel, | -| unsigned char_ b_StopMode, | -| unsigned char_ b_StopLevel, | -| unsigned char_ b_ExternGate, | -| unsigned char_ b_InterruptEnable) | -+----------------------------------------------------------------------------+ -| Task : Enable the selected PWM (b_PWM) from selected module | -| (b_ModulNbr). You must calling the "i_APCI1710_InitPWM"| -| function be for you call this function. | -| If you enable the PWM interrupt, the PWM generate a | -| interrupt after each period. | -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -| unsigned char_ b_StartLevel : Start period level selection | -| 0 : The period start with a | -| low level | -| 1 : The period start with a | -| high level | -| unsigned char_ b_StopMode : Stop mode selection | -| 0 : The PWM is stopped | -| directly after the | -| "i_APCI1710_DisablePWM" | -| function and break the | -| last period | -| 1 : After the | -| "i_APCI1710_DisablePWM" | -| function the PWM is | -| stopped at the end from| -| last period cycle. | -| unsigned char_ b_StopLevel : Stop PWM level selection | -| 0 : The output signal keep | -| the level after the | -| "i_APCI1710_DisablePWM" | -| function | -| 1 : The output signal is set| -| to low after the | -| "i_APCI1710_DisablePWM" | -| function | -| 2 : The output signal is set| -| to high after the | -| "i_APCI1710_DisablePWM" | -| function | -| unsigned char_ b_ExternGate : Extern gate action selection | -| 0 : Extern gate signal not | -| used. | -| 1 : Extern gate signal used.| -| unsigned char_ b_InterruptEnable : Enable or disable the PWM | -| interrupt. | -| - APCI1710_ENABLE : | -| Enable the PWM interrupt | -| A interrupt occur after | -| each period | -| - APCI1710_DISABLE : | -| Disable the PWM interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -| -6: PWM start level selection is wrong | -| -7: PWM stop mode selection is wrong | -| -8: PWM stop level selection is wrong | -| -9: Extern gate signal selection is wrong | -| -10: Interrupt parameter is wrong | -| -11: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_EnablePWM(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char b_StartLevel, - unsigned char b_StopMode, - unsigned char b_StopLevel, - unsigned char b_ExternGate, - unsigned char b_InterruptEnable) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_Command; - - devpriv->tsk_Current = current; /* Save the current process task structure */ - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /**********************************/ - /* Test the start level selection */ - /**********************************/ - - if (b_StartLevel <= 1) { - /**********************/ - /* Test the stop mode */ - /**********************/ - - if (b_StopMode <= 1) { - /***********************/ - /* Test the stop level */ - /***********************/ - - if (b_StopLevel <= 2) { - /*****************************/ - /* Test the extern gate mode */ - /*****************************/ - - if (b_ExternGate - <= 1) { - /*****************************/ - /* Test the interrupt action */ - /*****************************/ - - if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) { - /******************************************/ - /* Test if interrupt function initialised */ - /******************************************/ - - /********************/ - /* Read the command */ - /********************/ - - dw_Command - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 8 - + - (20 * b_PWM) + (64 * b_ModulNbr)); - - dw_Command - = - dw_Command - & - 0x80; - - /********************/ - /* Make the command */ - /********************/ - - dw_Command - = - dw_Command - | - b_StopMode - | - (b_InterruptEnable - << - 3) - | - (b_ExternGate - << - 4) - | - (b_StartLevel - << - 5); - - if (b_StopLevel & 3) { - dw_Command - = - dw_Command - | - 2; - - if (b_StopLevel & 2) { - dw_Command - = - dw_Command - | - 4; - } - } - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_InterruptEnable - = - b_InterruptEnable; - - /*******************/ - /* Set the command */ - /*******************/ - - outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /******************/ - /* Enable the PWM */ - /******************/ - outl(1, devpriv->s_BoardInfos.ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); - } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */ - else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue - = - -10; - } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */ - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - else { - /*****************************************/ - /* Extern gate signal selection is wrong */ - /*****************************************/ - DPRINTK("Extern gate signal selection is wrong\n"); - i_ReturnValue - = - -9; - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */ - else { - /*************************************/ - /* PWM stop level selection is wrong */ - /*************************************/ - DPRINTK("PWM stop level selection is wrong\n"); - i_ReturnValue = - -8; - } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */ - } /* if (b_StopMode >= 0 && b_StopMode <= 1) */ - else { - /************************************/ - /* PWM stop mode selection is wrong */ - /************************************/ - DPRINTK("PWM stop mode selection is wrong\n"); - i_ReturnValue = -7; - } /* if (b_StopMode >= 0 && b_StopMode <= 1) */ - } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */ - else { - /**************************************/ - /* PWM start level selection is wrong */ - /**************************************/ - DPRINTK("PWM start level selection is wrong\n"); - i_ReturnValue = -6; - } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisablePWM (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM) | -+----------------------------------------------------------------------------+ -| Task : Disable the selected PWM (b_PWM) from selected module | -| (b_ModulNbr). The output signal level depend of the | -| initialisation by the "i_APCI1710_EnablePWM". | -| See the b_StartLevel, b_StopMode and b_StopLevel | -| parameters from this function. | -+----------------------------------------------------------------------------+ -| Input Parameters :BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -| -6: PWM not enabled see function | -| "i_APCI1710_EnablePWM" | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_DisablePWM(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /***********************/ - /* Test if PWM enabled */ - /***********************/ - - if (dw_Status & 0x1) { - /*******************/ - /* Disable the PWM */ - /*******************/ - outl(0, devpriv->s_BoardInfos. - ui_Address + 12 + - (20 * b_PWM) + - (64 * b_ModulNbr)); - } /* if (dw_Status & 0x1) */ - else { - /*******************/ - /* PWM not enabled */ - /*******************/ - DPRINTK("PWM not enabled\n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK(" PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetNewPWMTiming | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char_ b_ClockSelection, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_LowTiming, | -| ULONG_ ul_HighTiming) | -+----------------------------------------------------------------------------+ -| Task : Set a new timing. The ul_LowTiming, ul_HighTiming and | -| ul_TimingUnit determine the low/high timing base for | -| the period. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure| -| (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1). | -| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| ULONG_ ul_LowTiming : Low base timing value. | -| ULONG_ ul_HighTiming : High base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised | -| -6: Timing Unit selection is wrong | -| -7: Low base timing selection is wrong | -| -8: High base timing selection is wrong | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_SetNewPWMTiming(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char b_TimingUnit, - unsigned int ul_LowTiming, - unsigned int ul_HighTiming) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_ClockSelection; - int i_ReturnValue = 0; - unsigned int ul_LowTimerValue = 0; - unsigned int ul_HighTimerValue = 0; - unsigned int ul_RealLowTiming = 0; - unsigned int ul_RealHighTiming = 0; - unsigned int dw_Status; - unsigned int dw_Command; - double d_RealLowTiming = 0; - double d_RealHighTiming = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - b_ClockSelection = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PWMModuleInfo. - b_ClockSelection; - - /************************/ - /* Test the timing unit */ - /************************/ - - if (b_TimingUnit <= 4) { - /*********************************/ - /* Test the low timing selection */ - /*********************************/ - - if (((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 266) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230650UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 9UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 242) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691043UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 520UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 8UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 200) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496729UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 7UL))) { - /**********************************/ - /* Test the High timing selection */ - /**********************************/ - - if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) { - /************************************/ - /* Calculate the low division fator */ - /************************************/ - - fpu_begin(); - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - ul_LowTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - ( - (ul_LowTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealLowTiming - = - ( - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - } - - /*************************************/ - /* Calculate the high division fator */ - /*************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - ul_HighTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - ( - (ul_HighTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealHighTiming - = - ( - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - } - - fpu_end(); - - /************************/ - /* Save the timing unit */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_TimingUnit - = - b_TimingUnit; - - /****************************/ - /* Save the low base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_LowTiming - = - d_RealLowTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealLowTiming - = - ul_RealLowTiming; - - /****************************/ - /* Save the high base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_HighTiming - = - d_RealHighTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealHighTiming - = - ul_RealHighTiming; - - /************************/ - /* Write the low timing */ - /************************/ - - outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /*************************/ - /* Write the high timing */ - /*************************/ - - outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /***************************/ - /* Set the clock selection */ - /***************************/ - - dw_Command = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + 8 + - (20 * b_PWM) + (64 * b_ModulNbr)); - - dw_Command = - dw_Command - & 0x7F; - - if (b_ClockSelection == APCI1710_40MHZ) { - dw_Command - = - dw_Command - | - 0x80; - } - - /***************************/ - /* Set the clock selection */ - /***************************/ - - outl(dw_Command, - devpriv-> - s_BoardInfos. - ui_Address - + 8 + - (20 * b_PWM) + (64 * b_ModulNbr)); - } else { - /***************************************/ - /* High base timing selection is wrong */ - /***************************************/ - DPRINTK("High base timing selection is wrong\n"); - i_ReturnValue = - -8; - } - } else { - /**************************************/ - /* Low base timing selection is wrong */ - /**************************************/ - DPRINTK("Low base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /**********************************/ - /* Timing unit selection is wrong */ - /**********************************/ - DPRINTK("Timing unit selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* - * Pwm Enable Disable and Set New Timing - */ -static int i_APCI1710_InsnWritePWM(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned char b_WriteType; - int i_ReturnValue = 0; - b_WriteType = CR_CHAN(insn->chanspec); - - switch (b_WriteType) { - case APCI1710_PWM_ENABLE: - i_ReturnValue = i_APCI1710_EnablePWM(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], - (unsigned char) data[2], - (unsigned char) data[3], (unsigned char) data[4], (unsigned char) data[5]); - break; - - case APCI1710_PWM_DISABLE: - i_ReturnValue = i_APCI1710_DisablePWM(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_PWM_NEWTIMING: - i_ReturnValue = i_APCI1710_SetNewPWMTiming(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], (unsigned int) data[2], (unsigned int) data[3]); - break; - - default: - printk("Write Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetPWMStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char *_ pb_PWMOutputStatus, | -| unsigned char *_ pb_ExternGateStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the status from selected PWM (b_PWM) from | -| selected module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) - b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); - b_PWM =(unsigned char) data[0]; - - | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_PWMOutputStatus : Return the PWM output | -| level status. | -| 0 : The PWM output level| -| is low. | -| 1 : The PWM output level| -| is high. | -| unsigned char *_ pb_ExternGateStatus : Return the extern gate | -| level status. | -| 0 : The extern gate is | -| low. | -| 1 : The extern gate is | -| high. - pb_PWMOutputStatus =(unsigned char *) data[0]; - pb_ExternGateStatus =(unsigned char *) data[1]; | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -| -6: PWM not enabled see function "i_APCI1710_EnablePWM"| -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned char b_ModulNbr; - unsigned char b_PWM; - unsigned char *pb_PWMOutputStatus; - unsigned char *pb_ExternGateStatus; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_PWM = (unsigned char) CR_CHAN(insn->chanspec); - pb_PWMOutputStatus = (unsigned char *) &data[0]; - pb_ExternGateStatus = (unsigned char *) &data[1]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /***********************/ - /* Test if PWM enabled */ - /***********************/ - - if (dw_Status & 0x1) { - *pb_PWMOutputStatus = - (unsigned char) ((dw_Status >> 7) - & 1); - *pb_ExternGateStatus = - (unsigned char) ((dw_Status >> 6) - & 1); - } /* if (dw_Status & 0x1) */ - else { - /*******************/ - /* PWM not enabled */ - /*******************/ - - DPRINTK("PWM not enabled \n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -static int i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - return insn->n; - -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c deleted file mode 100644 index 6ef1d6a434d..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c +++ /dev/null @@ -1,845 +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. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : SSI.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 SSI counter module | - +-----------------------------------------------------------------------+ - | several changes done by S. Weber in 1998 and C. Guinot in 2000 | - +-----------------------------------------------------------------------+ -*/ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_BINARY_MODE 0x1 -#define APCI1710_GRAY_MODE 0x0 - -#define APCI1710_SSI_READ1VALUE 1 -#define APCI1710_SSI_READALLVALUE 2 - -#define APCI1710_SSI_SET_CHANNELON 0 -#define APCI1710_SSI_SET_CHANNELOFF 1 -#define APCI1710_SSI_READ_1CHANNEL 2 -#define APCI1710_SSI_READ_ALLCHANNEL 3 - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitSSI | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SSIProfile, | -| unsigned char_ b_PositionTurnLength, | -| unsigned char_ b_TurnCptLength, | -| unsigned char_ b_PCIInputClock, | -| ULONG_ ul_SSIOutputClock, | -| unsigned char_ b_SSICountingMode) | -+----------------------------------------------------------------------------+ -| Task : Configure the SSI operating mode from selected module | -| (b_ModulNbr). You must calling this function be for you| -| call any other function witch access of SSI. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_SSIProfile : Selection from SSI | -| profile length (2 to 32).| -| unsigned char_ b_PositionTurnLength : Selection from SSI | -| position data length | -| (1 to 31). | -| unsigned char_ b_TurnCptLength : Selection from SSI turn | -| counter data length | -| (1 to 31). | -| unsigned char b_PCIInputClock : Selection from PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC have a PCI bus | -| clock from 30 MHz | -| - APCI1710_33MHZ : | -| The PC have a PCI bus | -| clock from 33 MHz | -| ULONG_ ul_SSIOutputClock : Selection from SSI output| -| clock. | -| From 229 to 5 000 000 Hz| -| for 30 MHz selection. | -| From 252 to 5 000 000 Hz| -| for 33 MHz selection. | -| unsigned char b_SSICountingMode : SSI counting mode | -| selection | -| - APCI1710_BINARY_MODE : | -| Binary counting mode. | -| - APCI1710_GRAY_MODE : | -| Gray counting mode. - - b_ModulNbr = CR_AREF(insn->chanspec); - b_SSIProfile = (unsigned char) data[0]; - b_PositionTurnLength= (unsigned char) data[1]; - b_TurnCptLength = (unsigned char) data[2]; - b_PCIInputClock = (unsigned char) data[3]; - ul_SSIOutputClock = (unsigned int) data[4]; - b_SSICountingMode = (unsigned char) data[5]; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a SSI module | -| -4: The selected SSI profile length is wrong | -| -5: The selected SSI position data length is wrong | -| -6: The selected SSI turn counter data length is wrong | -| -7: The selected PCI input clock is wrong | -| -8: The selected SSI output clock is wrong | -| -9: The selected SSI counting mode parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int ui_TimerValue; - unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength, - b_PCIInputClock, b_SSICountingMode; - unsigned int ul_SSIOutputClock; - - b_ModulNbr = CR_AREF(insn->chanspec); - b_SSIProfile = (unsigned char) data[0]; - b_PositionTurnLength = (unsigned char) data[1]; - b_TurnCptLength = (unsigned char) data[2]; - b_PCIInputClock = (unsigned char) data[3]; - ul_SSIOutputClock = (unsigned int) data[4]; - b_SSICountingMode = (unsigned char) data[5]; - - i_ReturnValue = insn->n; - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if SSI counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { - /*******************************/ - /* Test the SSI profile length */ - /*******************************/ - - /* CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */ - if (b_SSIProfile >= 2 && b_SSIProfile < 33) { - /*************************************/ - /* Test the SSI position data length */ - /*************************************/ - - if (b_PositionTurnLength > 0 - && b_PositionTurnLength < 32) { - /*****************************************/ - /* Test the SSI turn counter data length */ - /*****************************************/ - - if (b_TurnCptLength > 0 - && b_TurnCptLength < 32) { - /***************************/ - /* Test the profile length */ - /***************************/ - - if ((b_TurnCptLength + - b_PositionTurnLength) - <= b_SSIProfile) { - /****************************/ - /* Test the PCI input clock */ - /****************************/ - - if (b_PCIInputClock == - APCI1710_30MHZ - || - b_PCIInputClock - == - APCI1710_33MHZ) - { - /*************************/ - /* Test the output clock */ - /*************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) { - if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) { - /**********************/ - /* Save configuration */ - /**********************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile - = - b_SSIProfile; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength - = - b_PositionTurnLength; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_TurnCptLength - = - b_TurnCptLength; - - /*********************************/ - /* Initialise the profile length */ - /*********************************/ - - if (b_SSICountingMode == APCI1710_BINARY_MODE) { - - outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); - } else { - - outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); - } - - /******************************/ - /* Calculate the output clock */ - /******************************/ - - ui_TimerValue - = - (unsigned int) - ( - ((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock); - - /************************/ - /* Initialise the timer */ - /************************/ - - outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr)); - - /********************************/ - /* Initialise the counting mode */ - /********************************/ - - outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIInit - = - 1; - } else { - /*****************************************************/ - /* The selected SSI counting mode parameter is wrong */ - /*****************************************************/ - - DPRINTK("The selected SSI counting mode parameter is wrong\n"); - i_ReturnValue - = - -9; - } - } else { - /******************************************/ - /* The selected SSI output clock is wrong */ - /******************************************/ - - DPRINTK("The selected SSI output clock is wrong\n"); - i_ReturnValue - = - -8; - } - } else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = - -7; - } - } else { - /********************************************/ - /* The selected SSI profile length is wrong */ - /********************************************/ - - DPRINTK("The selected SSI profile length is wrong\n"); - i_ReturnValue = -4; - } - } else { - /******************************************************/ - /* The selected SSI turn counter data length is wrong */ - /******************************************************/ - - DPRINTK("The selected SSI turn counter data length is wrong\n"); - i_ReturnValue = -6; - } - } else { - /**************************************************/ - /* The selected SSI position data length is wrong */ - /**************************************************/ - - DPRINTK("The selected SSI position data length is wrong\n"); - i_ReturnValue = -5; - } - } else { - /********************************************/ - /* The selected SSI profile length is wrong */ - /********************************************/ - - DPRINTK("The selected SSI profile length is wrong\n"); - i_ReturnValue = -4; - } - } else { - /**********************************/ - /* The module is not a SSI module */ - /**********************************/ - - DPRINTK("The module is not a SSI module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Read1SSIValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedSSI, | -| PULONG_ pul_Position, | -| PULONG_ pul_TurnCpt) - int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : - - - Read the selected SSI counter (b_SelectedSSI) from | -| selected module (b_ModulNbr). - or Read all SSI counter (b_SelectedSSI) from | -| selected module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_SelectedSSI : Selection from SSI | -| counter (0 to 2) - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi) - b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); -| -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_Position : SSI position in the turn | -| PULONG_ pul_TurnCpt : Number of turns - -pul_Position = (unsigned int *) &data[0]; - pul_TurnCpt = (unsigned int *) &data[1]; | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a SSI module | -| -4: SSI not initialised see function | -| "i_APCI1710_InitSSI" | -| -5: The selected SSI is wrong | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned char b_Cpt; - unsigned char b_Length; - unsigned char b_Schift; - unsigned char b_SSICpt; - unsigned int dw_And; - unsigned int dw_And1; - unsigned int dw_And2; - unsigned int dw_StatusReg; - unsigned int dw_CounterValue; - unsigned char b_ModulNbr; - unsigned char b_SelectedSSI; - unsigned char b_ReadType; - unsigned int *pul_Position; - unsigned int *pul_TurnCpt; - unsigned int *pul_Position1; - unsigned int *pul_TurnCpt1; - - i_ReturnValue = insn->n; - pul_Position1 = (unsigned int *) &data[0]; -/* For Read1 */ - pul_TurnCpt1 = (unsigned int *) &data[1]; -/* For Read all */ - pul_Position = (unsigned int *) &data[0]; /* 0-2 */ - pul_TurnCpt = (unsigned int *) &data[3]; /* 3-5 */ - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); - b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if SSI counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { - /***************************/ - /* Test if SSI initialised */ - /***************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_SSICounterInfo.b_SSIInit == 1) { - - switch (b_ReadType) { - - case APCI1710_SSI_READ1VALUE: - /****************************************/ - /* Test the selected SSI counter number */ - /****************************************/ - - if (b_SelectedSSI < 3) { - /************************/ - /* Start the conversion */ - /************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 8 + - (64 * b_ModulNbr)); - - do { - /*******************/ - /* Read the status */ - /*******************/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } while ((dw_StatusReg & 0x1) - != 0); - - /******************************/ - /* Read the SSI counter value */ - /******************************/ - - dw_CounterValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (b_SelectedSSI * 4) + - (64 * b_ModulNbr)); - - b_Length = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile / 2; - - if ((b_Length * 2) != - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile) { - b_Length++; - } - - b_Schift = - b_Length - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; - - *pul_Position1 = - dw_CounterValue >> - b_Schift; - - dw_And = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; - b_Cpt++) { - dw_And = dw_And * 2; - } - - *pul_Position1 = - *pul_Position1 & - ((dw_And) - 1); - - *pul_TurnCpt1 = - dw_CounterValue >> - b_Length; - - dw_And = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_TurnCptLength; - b_Cpt++) { - dw_And = dw_And * 2; - } - - *pul_TurnCpt1 = - *pul_TurnCpt1 & - ((dw_And) - 1); - } else { - /*****************************/ - /* The selected SSI is wrong */ - /*****************************/ - - DPRINTK("The selected SSI is wrong\n"); - i_ReturnValue = -5; - } - break; - - case APCI1710_SSI_READALLVALUE: - dw_And1 = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; b_Cpt++) { - dw_And1 = dw_And1 * 2; - } - - dw_And2 = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SSICounterInfo. - b_TurnCptLength; b_Cpt++) { - dw_And2 = dw_And2 * 2; - } - - /************************/ - /* Start the conversion */ - /************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 8 + - (64 * b_ModulNbr)); - - do { - /*******************/ - /* Read the status */ - /*******************/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } while ((dw_StatusReg & 0x1) != 0); - - for (b_SSICpt = 0; b_SSICpt < 3; - b_SSICpt++) { - /******************************/ - /* Read the SSI counter value */ - /******************************/ - - dw_CounterValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (b_SSICpt * 4) + - (64 * b_ModulNbr)); - - b_Length = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile / 2; - - if ((b_Length * 2) != - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile) { - b_Length++; - } - - b_Schift = - b_Length - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; - - pul_Position[b_SSICpt] = - dw_CounterValue >> - b_Schift; - pul_Position[b_SSICpt] = - pul_Position[b_SSICpt] & - ((dw_And1) - 1); - - pul_TurnCpt[b_SSICpt] = - dw_CounterValue >> - b_Length; - pul_TurnCpt[b_SSICpt] = - pul_TurnCpt[b_SSICpt] & - ((dw_And2) - 1); - } - break; - - default: - printk("Read Type Inputs Wrong\n"); - - } /* switch ending */ - - } else { - /***********************/ - /* SSI not initialised */ - /***********************/ - - DPRINTK("SSI not initialised\n"); - i_ReturnValue = -4; - } - } else { - /**********************************/ - /* The module is not a SSI module */ - /**********************************/ - - DPRINTK("The module is not a SSI module\n"); - i_ReturnValue = -3; - - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadSSI1DigitalInput | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_InputChannel, | -| unsigned char *_ pb_ChannelStatus) | -+----------------------------------------------------------------------------+ -| Task : - (0) Set the digital output from selected SSI module | -| (b_ModuleNbr) ON - (1) Set the digital output from selected SSI module | -| (b_ModuleNbr) OFF - (2)Read the status from selected SSI digital input | -| (b_InputChannel) - (3)Read the status from all SSI digital inputs from | -| selected SSI module (b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr CR_AREF : Module number to | -| configure (0 to 3) | -| unsigned char_ b_InputChannel CR_CHAN : Selection from digital | -| data[0] which IOTYPE input ( 0 to 2) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel | -| data[0] status | -| 0 : Channle is not active| -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a SSI module | -| -4: The selected SSI digital input is wrong | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr; - unsigned char b_InputChannel; - unsigned char *pb_ChannelStatus; - unsigned char *pb_InputStatus; - unsigned char b_IOType; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_IOType = (unsigned char) data[0]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if SSI counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { - switch (b_IOType) { - case APCI1710_SSI_SET_CHANNELON: - /*****************************/ - /* Set the digital output ON */ - /*****************************/ - - outl(1, devpriv->s_BoardInfos.ui_Address + 16 + - (64 * b_ModulNbr)); - break; - - case APCI1710_SSI_SET_CHANNELOFF: - /******************************/ - /* Set the digital output OFF */ - /******************************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 16 + - (64 * b_ModulNbr)); - break; - - case APCI1710_SSI_READ_1CHANNEL: - /******************************************/ - /* Test the digital imnput channel number */ - /******************************************/ - - b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec); - pb_ChannelStatus = (unsigned char *) &data[0]; - - if (b_InputChannel <= 2) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - *pb_ChannelStatus = - (unsigned char) (((~dw_StatusReg) >> (4 + - b_InputChannel)) - & 1); - } else { - /********************************/ - /* Selected digital input error */ - /********************************/ - - DPRINTK("Selected digital input error\n"); - i_ReturnValue = -4; - } - break; - - case APCI1710_SSI_READ_ALLCHANNEL: - /**************************/ - /* Read all digital input */ - /**************************/ - pb_InputStatus = (unsigned char *) &data[0]; - - dw_StatusReg = - inl(devpriv->s_BoardInfos.ui_Address + - (64 * b_ModulNbr)); - *pb_InputStatus = - (unsigned char) (((~dw_StatusReg) >> 4) & 7); - break; - - default: - printk("IO type wrong\n"); - - } /* switch end */ - } else { - /**********************************/ - /* The module is not a SSI module */ - /**********************************/ - - DPRINTK("The module is not a SSI module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c deleted file mode 100644 index 0b79531ac24..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c +++ /dev/null @@ -1,2065 +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. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : TOR.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 tor counter module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 27/01/99 | S. Weber | 40 MHz implementation | - +-----------------------------------------------------------------------+ - | 28/04/00 | S. Weber | Simple,double and quadruple mode implementation| - | | | Extern clock implementation | - +-----------------------------------------------------------------------+ - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ -*/ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_GATE_INPUT 10 - -#define APCI1710_TOR_SIMPLE_MODE 2 -#define APCI1710_TOR_DOUBLE_MODE 3 -#define APCI1710_TOR_QUADRUPLE_MODE 4 - -#define APCI1710_SINGLE 0 -#define APCI1710_CONTINUOUS 1 - -#define APCI1710_TOR_GETPROGRESSSTATUS 0 -#define APCI1710_TOR_GETCOUNTERVALUE 1 -#define APCI1710_TOR_READINTERRUPT 2 - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitTorCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_TimingInterval, | -| PULONG_ pul_RealTimingInterval) | -+----------------------------------------------------------------------------+ -| Task : Configure the selected tor counter (b_TorCounter) | -| from selected module (b_ModulNbr). | -| The ul_TimingInterval and ul_TimingUnit determine the | -| timing base for the measurement. | -| The pul_RealTimingInterval return the real timing | -| value. You must calling this function be for you call | -| any other function witch access of the tor counter. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| - CR_AREF unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| data[0] unsigned char_ b_TorCounter : Tor counter selection | -| (0 or 1). | -| data[1] unsigned char_ b_PCIInputClock : Selection from PCI bus clock| -| - APCI1710_30MHZ : | -| The PC have a PCI bus | -| clock from 30 MHz | -| - APCI1710_33MHZ : | -| The PC have a PCI bus | -| clock from 33 MHz | -| - APCI1710_40MHZ | -| The APCI-1710 have a | -| integrated 40Mhz | -| quartz. | -| - APCI1710_GATE_INPUT | -| Used the gate input for | -| the base clock. If you | -| have selected this option,| -| than it is not possibl to | -| used the gate input for | -| enabled the acquisition | -| data[2] unsigned char_ b_TimingUnit : Base timing unit (0 to 4) | -| 0 : ns | -| 1 : µs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| data[3] ULONG_ ul_TimingInterval : Base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealTimingInterval : Real base timing | -| data[0] value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: The selected PCI input clock is wrong | -| -6: Timing unit selection is wrong | -| -7: Base timing selection is wrong | -| -8: You can not used the 40MHz clock selection wich | -| this board | -| -9: You can not used the 40MHz clock selection wich | -| this TOR version | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int ul_TimerValue = 0; - unsigned int dw_Command; - double d_RealTimingInterval = 0; - unsigned char b_ModulNbr; - unsigned char b_TorCounter; - unsigned char b_PCIInputClock; - unsigned char b_TimingUnit; - unsigned int ul_TimingInterval; - unsigned int ul_RealTimingInterval = 0; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - - b_TorCounter = (unsigned char) data[0]; - b_PCIInputClock = (unsigned char) data[1]; - b_TimingUnit = (unsigned char) data[2]; - ul_TimingInterval = (unsigned int) data[3]; - printk("INPUT clock %d\n", b_PCIInputClock); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ) || - (b_PCIInputClock == - APCI1710_GATE_INPUT)) { - /************************/ - /* Test the timing unit */ - /************************/ - - if ((b_TimingUnit <= 4) - || (b_PCIInputClock == - APCI1710_GATE_INPUT)) { - /**********************************/ - /* Test the base timing selection */ - /**********************************/ - - if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 133) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230650UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 9UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 121) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691043UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 520UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 8UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 100) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496729UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 7UL)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && (ul_TimingInterval >= 2))) { - /**************************/ - /* Test the board version */ - /**************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) { - /************************/ - /* Test the TOR version */ - /************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3132)) || (b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) { - /*********************************/ - /* Test if not extern clock used */ - /*********************************/ - - if (b_PCIInputClock != APCI1710_GATE_INPUT) { - fpu_begin - (); - /****************************************/ - /* Calculate the timer 0 division fator */ - /****************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.00025 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.00025 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (0.00025 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.25 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.25 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - ( - (double) - 0.25 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - ul_TimingInterval - * - (250.0 - * - b_PCIInputClock); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (250.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (250000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - ( - (ul_TimingInterval - * - 60) - * - (250000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_TimingInterval * 60.0) * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock)) - / - 60; - d_RealTimingInterval - = - ( - (double) - ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock)) - / - 60.0; - - if ((double)(((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - } - - fpu_end(); - } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */ - else { - /*************************************************************/ - /* 2 Clock used for the overflow and the reload from counter */ - /*************************************************************/ - - ul_TimerValue - = - ul_TimingInterval - - - 2; - } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */ - - /****************************/ - /* Save the PCI input clock */ - /****************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - b_PCIInputClock - = - b_PCIInputClock; - - /************************/ - /* Save the timing unit */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_TimingUnit - = - b_TimingUnit; - - /************************/ - /* Save the base timing */ - /************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - d_TimingInterval - = - d_RealTimingInterval; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - ul_RealTimingInterval - = - ul_RealTimingInterval; - - /*******************/ - /* Get the command */ - /*******************/ - - dw_Command - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 4 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - dw_Command - = - (dw_Command - >> - 4) - & - 0xF; - - /******************/ - /* Test if 40 MHz */ - /******************/ - - if (b_PCIInputClock == APCI1710_40MHZ) { - /****************************/ - /* Set the 40 MHz selection */ - /****************************/ - - dw_Command - = - dw_Command - | - 0x10; - } - - /*****************************/ - /* Test if extern clock used */ - /*****************************/ - - if (b_PCIInputClock == APCI1710_GATE_INPUT) { - /****************************/ - /* Set the 40 MHz selection */ - /****************************/ - - dw_Command - = - dw_Command - | - 0x20; - } - - /*************************/ - /* Write the new command */ - /*************************/ - - outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /*******************/ - /* Disable the tor */ - /*******************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - /*************************/ - /* Set the timer 1 value */ - /*************************/ - - outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /*********************/ - /* Tor counter init. */ - /*********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_TorCounterInit - = - 1; - } else { - /***********************************************/ - /* TOR version error for 40MHz clock selection */ - /***********************************************/ - - DPRINTK("TOR version error for 40MHz clock selection\n"); - i_ReturnValue - = - -9; - } - } else { - /**************************************************************/ - /* You can not used the 40MHz clock selection wich this board */ - /**************************************************************/ - - DPRINTK("You can not used the 40MHz clock selection wich this board\n"); - i_ReturnValue = - -8; - } - } else { - /**********************************/ - /* Base timing selection is wrong */ - /**********************************/ - - DPRINTK("Base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /**********************************/ - /* Timing unit selection is wrong */ - /**********************************/ - - DPRINTK("Timing unit selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */ - else { - /**********************************/ - /* Tor Counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor Counter selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - data[0] = (unsigned int) ul_RealTimingInterval; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableTorCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned char_ b_InputMode, | -| unsigned char_ b_ExternGate, | -| unsigned char_ b_CycleMode, | -| unsigned char_ b_InterruptEnable) | -+----------------------------------------------------------------------------+ -| Task : Enable the tor counter (b_TorCounter) from selected | -| module (b_ModulNbr). You must calling the | -| "i_APCI1710_InitTorCounter" function be for you call | -| this function. | -| If you enable the tor counter interrupt, the | -| tor counter generate a interrupt after the timing cycle| -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter from this manual. | -| The b_CycleMode parameter determine if you will | -| measured a single or more cycle. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). | -| unsigned char_ b_InputMode : Input signal level selection | -| 0 : Tor count each low level | -| 1 : Tor count each high level| -| unsigned char_ b_ExternGate : Extern gate action selection | -| 0 : Extern gate signal not | -| used | -| 1 : Extern gate signal used. | -| If you selected the | -| single mode, each high | -| level signal start the | -| counter. | -| If you selected the | -| continuous mode, the | -| first high level signal | -| start the tor counter | -| | -| APCI1710_TOR_QUADRUPLE _MODE : | -| In the quadruple mode, the edge| -| analysis circuit generates a | -| counting pulse from each edge | -| of 2 signals which are phase | -| shifted in relation to each | -| other. | -| The gate input is used for the | -| signal B | -| | -| APCI1710_TOR_DOUBLE_MODE: | -| Functions in the same way as | -| the quadruple mode, except that| -| only two of the four edges are | -| analysed per period. | -| The gate input is used for the | -| signal B | -| | -| APCI1710_TOR_SIMPLE_MODE: | -| Functions in the same way as | -| the quadruple mode, except that| -| only one of the four edges is | -| analysed per period. | -| The gate input is used for the | -| signal B | -| | -| unsigned char_ b_CycleMode : Selected the tor counter | -| acquisition mode | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| tor counter interrupt. | -| APCI1710_ENABLE: | -| Enable the tor counter | -| interrupt | -| APCI1710_DISABLE: | -| Disable the tor counter | -| interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -| -6: Tor input signal selection is wrong | -| -7: Extern gate signal mode is wrong | -| -8: Tor counter acquisition mode cycle is wrong | -| -9: Interrupt parameter is wrong | -| -10:Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableTorCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter) | -+----------------------------------------------------------------------------+ -| Task : Disable the tor counter (b_TorCounter) from selected | -| module (b_ModulNbr). If you disable the tor counter | -| after a start cycle occur and you restart the tor | -| counter witch the " i_APCI1710_EnableTorCounter" | -| function, the status register is cleared | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -| -6: Tor counter not enabled see function | -| "i_APCI1710_EnableTorCounter" | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_DummyRead; - unsigned int dw_ConfigReg; - unsigned char b_ModulNbr, b_Action; - unsigned char b_TorCounter; - unsigned char b_InputMode; - unsigned char b_ExternGate; - unsigned char b_CycleMode; - unsigned char b_InterruptEnable; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_Action = (unsigned char) data[0]; /* enable or disable */ - b_TorCounter = (unsigned char) data[1]; - b_InputMode = (unsigned char) data[2]; - b_ExternGate = (unsigned char) data[3]; - b_CycleMode = (unsigned char) data[4]; - b_InterruptEnable = (unsigned char) data[5]; - i_ReturnValue = insn->n; - devpriv->tsk_Current = current; /* Save the current process task structure */ - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - switch (b_Action) /* Enable or Disable */ - { - case APCI1710_ENABLE: - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = - inl(devpriv->s_BoardInfos. - ui_Address + 8 + - (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /******************************/ - /* Test the input signal mode */ - /******************************/ - - if (b_InputMode == 0 || - b_InputMode == 1 || - b_InputMode == - APCI1710_TOR_SIMPLE_MODE - || b_InputMode == - APCI1710_TOR_DOUBLE_MODE - || b_InputMode == - APCI1710_TOR_QUADRUPLE_MODE) - { - /************************************/ - /* Test the extern gate signal mode */ - /************************************/ - - if (b_ExternGate == 0 - || b_ExternGate - == 1 - || b_InputMode > - 1) { - /*********************************/ - /* Test the cycle mode parameter */ - /*********************************/ - - if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) { - /***************************/ - /* Test the interrupt flag */ - /***************************/ - - if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) { - - /***************************/ - /* Save the interrupt mode */ - /***************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_InterruptEnable - = - b_InterruptEnable; - - /*******************/ - /* Get the command */ - /*******************/ - - dw_ConfigReg - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 4 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - dw_ConfigReg - = - (dw_ConfigReg - >> - 4) - & - 0x30; - - /********************************/ - /* Test if not direct mode used */ - /********************************/ - - if (b_InputMode > 1) { - /*******************************/ - /* Extern gate can not be used */ - /*******************************/ - - b_ExternGate - = - 0; - - /*******************************************/ - /* Enable the extern gate for the Signal B */ - /*******************************************/ - - dw_ConfigReg - = - dw_ConfigReg - | - 0x40; - - /***********************/ - /* Test if simple mode */ - /***********************/ - - if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) { - /**************************/ - /* Enable the sinple mode */ - /**************************/ - - dw_ConfigReg - = - dw_ConfigReg - | - 0x780; - - } /* if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) */ - - /***********************/ - /* Test if double mode */ - /***********************/ - - if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) { - /**************************/ - /* Enable the double mode */ - /**************************/ - - dw_ConfigReg - = - dw_ConfigReg - | - 0x180; - - } /* if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) */ - - b_InputMode - = - 0; - } /* if (b_InputMode > 1) */ - - /*******************/ - /* Set the command */ - /*******************/ - - dw_ConfigReg - = - dw_ConfigReg - | - b_CycleMode - | - (b_InterruptEnable - * - 2) - | - (b_InputMode - * - 4) - | - (b_ExternGate - * - 8); - - /*****************************/ - /* Clear the status register */ - /*****************************/ - - dw_DummyRead - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 0 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /***************************************/ - /* Clear the interrupt status register */ - /***************************************/ - - dw_DummyRead - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 12 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /********************/ - /* Set the commando */ - /********************/ - - outl(dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /****************/ - /* Set the gate */ - /****************/ - - outl(1, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue - = - -9; - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - else { - /***********************************************/ - /* Tor counter acquisition mode cycle is wrong */ - /***********************************************/ - - DPRINTK("Tor counter acquisition mode cycle is wrong\n"); - i_ReturnValue - = - -8; - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - else { - /***********************************/ - /* Extern gate input mode is wrong */ - /***********************************/ - - DPRINTK("Extern gate input mode is wrong\n"); - i_ReturnValue = - -7; - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - } /* if (b_InputMode >= 0 && b_InputMode <= 1) */ - else { - /***************************************/ - /* Tor input signal selection is wrong */ - /***************************************/ - - DPRINTK("Tor input signal selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } - break; - - case APCI1710_DISABLE: - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + - (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (dw_Status & 0x10) { - /***************************/ - /* Test if counter enabled */ - /***************************/ - - if (dw_Status & 0x1) { - /****************************/ - /* Clear the interrupt mode */ - /****************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_InterruptEnable - = - APCI1710_DISABLE; - - /******************/ - /* Clear the gate */ - /******************/ - - outl(0, devpriv-> - s_BoardInfos. - ui_Address + 8 + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - } /* if (dw_Status & 0x1) */ - else { - /***************************/ - /* Tor counter not enabled */ - /***************************/ - - DPRINTK("Tor counter not enabled \n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } /* if (dw_Status & 0x10) */ - else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } /* // if (dw_Status & 0x10) */ - - } /* switch */ - } /* if (b_TorCounter <= 1) */ - else { - /**********************************/ - /* Tor counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor counter selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_TorCounter <= 1) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module \n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error \n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetTorCounterInitialisation | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned char *_ pb_TimingUnit, | -| PULONG_ pul_TimingInterval, | -| unsigned char *_ pb_InputMode, | -| unsigned char *_ pb_ExternGate, | -| unsigned char *_ pb_CycleMode, | -| unsigned char *_ pb_Enable, | -| unsigned char *_ pb_InterruptEnable)| -+----------------------------------------------------------------------------+ -| Task : Enable the tor counter (b_TorCounter) from selected | -| module (b_ModulNbr). You must calling the | -| "i_APCI1710_InitTorCounter" function be for you call | -| this function. | -| If you enable the tor counter interrupt, the | -| tor counter generate a interrupt after the timing cycle| -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter from this manual. | -| The b_CycleMode parameter determine if you will | -| measured a single or more cycle. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1) - - b_ModulNbr = CR_AREF(insn->chanspec); - b_TorCounter = CR_CHAN(insn->chanspec); -. | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing unit (0 to 4) | -| 0 : ns | -| 1 : µs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| PULONG_ pul_TimingInterval : Base timing value. | -| unsigned char *_ pb_InputMode : Input signal level | -| selection | -| 0 : Tor count each low level | -| 1 : Tor count each high level| -| unsigned char *_ pb_ExternGate : Extern gate action | -| selection | -| 0 : Extern gate signal not | -| used | -| 1 : Extern gate signal used| -| unsigned char *_ pb_CycleMode : Tor counter acquisition | -| mode | -| unsigned char *_ pb_Enable : Indicate if the tor counter| -| is enabled or no | -| 0 : Tor counter disabled | -| 1 : Tor counter enabled | -| unsigned char *_ pb_InterruptEnable : Enable or disable the | -| tor counter interrupt. | -| APCI1710_ENABLE: | -| Enable the tor counter | -| interrupt | -| APCI1710_DISABLE: | -| Disable the tor counter | -| interrupt - pb_TimingUnit = (unsigned char *) &data[0]; - pul_TimingInterval = (unsigned int *) &data[1]; - pb_InputMode = (unsigned char *) &data[2]; - pb_ExternGate = (unsigned char *) &data[3]; - pb_CycleMode = (unsigned char *) &data[4]; - pb_Enable = (unsigned char *) &data[5]; - pb_InterruptEnable = (unsigned char *) &data[6]; - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned char b_ModulNbr; - unsigned char b_TorCounter; - unsigned char *pb_TimingUnit; - unsigned int *pul_TimingInterval; - unsigned char *pb_InputMode; - unsigned char *pb_ExternGate; - unsigned char *pb_CycleMode; - unsigned char *pb_Enable; - unsigned char *pb_InterruptEnable; - - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_TorCounter = CR_CHAN(insn->chanspec); - - pb_TimingUnit = (unsigned char *) &data[0]; - pul_TimingInterval = (unsigned int *) &data[1]; - pb_InputMode = (unsigned char *) &data[2]; - pb_ExternGate = (unsigned char *) &data[3]; - pb_CycleMode = (unsigned char *) &data[4]; - pb_Enable = (unsigned char *) &data[5]; - pb_InterruptEnable = (unsigned char *) &data[6]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - *pb_Enable = dw_Status & 1; - - /********************/ - /* Get the commando */ - /********************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 4 + - (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - *pb_CycleMode = - (unsigned char) ((dw_Status >> 4) & 1); - *pb_InterruptEnable = - (unsigned char) ((dw_Status >> 5) & 1); - - /******************************************************/ - /* Test if extern gate used for clock or for signal B */ - /******************************************************/ - - if (dw_Status & 0x600) { - /*****************************************/ - /* Test if extern gate used for signal B */ - /*****************************************/ - - if (dw_Status & 0x400) { - /***********************/ - /* Test if simple mode */ - /***********************/ - - if ((dw_Status & 0x7800) - == 0x7800) { - *pb_InputMode = - APCI1710_TOR_SIMPLE_MODE; - } - - /***********************/ - /* Test if double mode */ - /***********************/ - - if ((dw_Status & 0x7800) - == 0x1800) { - *pb_InputMode = - APCI1710_TOR_DOUBLE_MODE; - } - - /**************************/ - /* Test if quadruple mode */ - /**************************/ - - if ((dw_Status & 0x7800) - == 0x0000) { - *pb_InputMode = - APCI1710_TOR_QUADRUPLE_MODE; - } - } /* if (dw_Status & 0x400) */ - else { - *pb_InputMode = 1; - } /* // if (dw_Status & 0x400) */ - - /************************/ - /* Extern gate not used */ - /************************/ - - *pb_ExternGate = 0; - } /* if (dw_Status & 0x600) */ - else { - *pb_InputMode = - (unsigned char) ((dw_Status >> 6) - & 1); - *pb_ExternGate = - (unsigned char) ((dw_Status >> 7) - & 1); - } /* if (dw_Status & 0x600) */ - - *pb_TimingUnit = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo[b_TorCounter]. - b_TimingUnit; - - *pul_TimingInterval = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo[b_TorCounter]. - ul_RealTimingInterval; - } else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } - - } /* if (b_TorCounter <= 1) */ - else { - /**********************************/ - /* Tor counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor counter selection is wrong \n"); - i_ReturnValue = -4; - } /* if (b_TorCounter <= 1) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadTorCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned int_ ui_TimeOut, | -| unsigned char *_ pb_TorCounterStatus, | -| PULONG_ pul_TorCounterValue) | -+----------------------------------------------------------------------------+ -| Task case APCI1710_TOR_GETPROGRESSSTATUS: Return the tor counter -(b_TorCounter) status (pb_TorCounterStatus) from selected tor counter | -| module (b_ModulNbr). - - case APCI1710_TOR_GETCOUNTERVALUE : - Return the tor counter (b_TorCounter) status | -| (pb_TorCounterStatus) and the timing value | -| (pul_TorCounterValue) after a conting cycle stop | -| from selected tor counter module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). - b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - b_TorCounter = (unsigned char) data[1]; - ui_TimeOut = (unsigned int) data[2]; | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TorCounterStatus : Return the tor counter | -| status. | -| 0 : Conting cycle not started| -| Software gate not set. | -| 1 : Conting cycle started. | -| Software gate set. | -| 2 : Conting cycle stopped. | -| The conting cycle is | -| terminate. | -| 3 : A overflow occur. You | -| must change the base | -| timing witch the | -| function | -| "i_APCI1710_InitTorCounter"| -| 4 : Timeeout occur | -| unsigned int * pul_TorCounterValue : Tor counter value. - pb_TorCounterStatus=(unsigned char *) &data[0]; - pul_TorCounterValue=(unsigned int *) &data[1]; | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -| -6: Tor counter not enabled see function | -| "i_APCI1710_EnableTorCounter" | -| -7: Timeout parameter is wrong (0 to 65535) | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_TimeOut = 0; - unsigned char b_ModulNbr; - unsigned char b_TorCounter; - unsigned char b_ReadType; - unsigned int ui_TimeOut; - unsigned char *pb_TorCounterStatus; - unsigned int *pul_TorCounterValue; - - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - b_TorCounter = (unsigned char) data[1]; - ui_TimeOut = (unsigned int) data[2]; - pb_TorCounterStatus = (unsigned char *) &data[0]; - pul_TorCounterValue = (unsigned int *) &data[1]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ReadType == APCI1710_TOR_READINTERRUPT) { - - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters. - ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - return insn->n; - } - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (dw_Status & 0x10) { - /***************************/ - /* Test if counter enabled */ - /***************************/ - - if (dw_Status & 0x1) { - - switch (b_ReadType) { - - case APCI1710_TOR_GETPROGRESSSTATUS: - /*******************/ - /* Read the status */ - /*******************/ - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - dw_Status = - dw_Status & 0xF; - - /*****************/ - /* Test if start */ - /*****************/ - - if (dw_Status & 1) { - if (dw_Status & - 2) { - if (dw_Status & 4) { - /************************/ - /* Tor counter overflow */ - /************************/ - - *pb_TorCounterStatus - = - 3; - } else { - /***********************/ - /* Tor counter started */ - /***********************/ - - *pb_TorCounterStatus - = - 2; - } - } else { - /***********************/ - /* Tor counter started */ - /***********************/ - - *pb_TorCounterStatus - = - 1; - } - } else { - /***************************/ - /* Tor counter not started */ - /***************************/ - - *pb_TorCounterStatus - = 0; - } - break; - - case APCI1710_TOR_GETCOUNTERVALUE: - - /*****************************/ - /* Test the timout parameter */ - /*****************************/ - - if ((ui_TimeOut >= 0) - && (ui_TimeOut - <= - 65535UL)) - { - for (;;) { - /*******************/ - /* Read the status */ - /*******************/ - - dw_Status - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 4 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - /********************/ - /* Test if overflow */ - /********************/ - - if ((dw_Status & 4) == 4) { - /******************/ - /* Overflow occur */ - /******************/ - - *pb_TorCounterStatus - = - 3; - - /******************/ - /* Read the value */ - /******************/ - - *pul_TorCounterValue - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 0 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - break; - } /* if ((dw_Status & 4) == 4) */ - else { - /*******************************/ - /* Test if measurement stopped */ - /*******************************/ - - if ((dw_Status & 2) == 2) { - /***********************/ - /* A stop signal occur */ - /***********************/ - - *pb_TorCounterStatus - = - 2; - - /******************/ - /* Read the value */ - /******************/ - - *pul_TorCounterValue - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 0 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - break; - } /* if ((dw_Status & 2) == 2) */ - else { - /*******************************/ - /* Test if measurement started */ - /*******************************/ - - if ((dw_Status & 1) == 1) { - /************************/ - /* A start signal occur */ - /************************/ - - *pb_TorCounterStatus - = - 1; - } /* if ((dw_Status & 1) == 1) */ - else { - /***************************/ - /* Measurement not started */ - /***************************/ - - *pb_TorCounterStatus - = - 0; - } /* if ((dw_Status & 1) == 1) */ - } /* if ((dw_Status & 2) == 2) */ - } /* if ((dw_Status & 8) == 8) */ - - if (dw_TimeOut == ui_TimeOut) { - /*****************/ - /* Timeout occur */ - /*****************/ - - break; - } else { - /*************************/ - /* Increment the timeout */ - /*************************/ - - dw_TimeOut - = - dw_TimeOut - + - 1; - - mdelay(1000); - } - } /* for (;;) */ - - /*************************/ - /* Test if timeout occur */ - /*************************/ - - if ((*pb_TorCounterStatus != 3) && (dw_TimeOut == ui_TimeOut) && (ui_TimeOut != 0)) { - /*****************/ - /* Timeout occur */ - /*****************/ - - *pb_TorCounterStatus - = - 4; - } - } else { - /******************************/ - /* Timeout parameter is wrong */ - /******************************/ - - DPRINTK("Timeout parameter is wrong\n"); - i_ReturnValue = - -7; - } - break; - - default: - printk("Inputs wrong\n"); - } /* switch end */ - } /* if (dw_Status & 0x1) */ - else { - /***************************/ - /* Tor counter not enabled */ - /***************************/ - - DPRINTK("Tor counter not enabled\n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } - } /* if (b_TorCounter <= 1) */ - else { - /**********************************/ - /* Tor counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor counter selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_TorCounter <= 1) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c deleted file mode 100644 index fb56360444e..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c +++ /dev/null @@ -1,1044 +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. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : TTL.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 TTL I/O module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 13/05/98 | S. Weber | TTL digital input / output implementation | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | | | | - | | | | - +-----------------------------------------------------------------------+ -*/ - -#define APCI1710_TTL_INIT 0 -#define APCI1710_TTL_INITDIRECTION 1 - -#define APCI1710_TTL_READCHANNEL 0 -#define APCI1710_TTL_READPORT 1 - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitTTLIODirection | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PortAMode, | -| unsigned char_ b_PortBMode, | -| unsigned char_ b_PortCMode, | -| unsigned char_ b_PortDMode) | -+----------------------------------------------------------------------------+ -| Task APCI1710_TTL_INIT (using defaults) : Configure the TTL I/O operating mode from selected | -| module (b_ModulNbr). You must calling this function be| -| for you call any other function witch access of TTL. | - APCI1710_TTL_INITDIRECTION(user inputs for direction) - -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_InitType = (unsigned char) data[0]; - b_PortAMode = (unsigned char) data[1]; - b_PortBMode = (unsigned char) data[2]; - b_PortCMode = (unsigned char) data[3]; - b_PortDMode = (unsigned char) data[4];| -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL module | -| -4: Function not available for this version | -| -5: Port A mode selection is wrong | -| -6: Port B mode selection is wrong | -| -7: Port C mode selection is wrong | -| -8: Port D mode selection is wrong | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned char b_ModulNbr; - unsigned char b_InitType; - unsigned char b_PortAMode; - unsigned char b_PortBMode; - unsigned char b_PortCMode; - unsigned char b_PortDMode; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_InitType = (unsigned char) data[0]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - switch (b_InitType) { - case APCI1710_TTL_INIT: - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit = 1; - - /***************************/ - /* Set TTL port A to input */ - /***************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[0] = 0; - - /***************************/ - /* Set TTL port B to input */ - /***************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[1] = 0; - - /***************************/ - /* Set TTL port C to input */ - /***************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[2] = 0; - - /****************************/ - /* Set TTL port D to output */ - /****************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[3] = 1; - - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(0x8, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - break; - - case APCI1710_TTL_INITDIRECTION: - - b_PortAMode = (unsigned char) data[1]; - b_PortBMode = (unsigned char) data[2]; - b_PortCMode = (unsigned char) data[3]; - b_PortDMode = (unsigned char) data[4]; - - /********************/ - /* Test the version */ - /********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & 0xFFFF) >= - 0x3230) { - /************************/ - /* Test the port A mode */ - /************************/ - - if ((b_PortAMode == 0) - || (b_PortAMode == 1)) { - /************************/ - /* Test the port B mode */ - /************************/ - - if ((b_PortBMode == 0) - || (b_PortBMode == 1)) { - /************************/ - /* Test the port C mode */ - /************************/ - - if ((b_PortCMode == 0) - || (b_PortCMode - == 1)) { - /************************/ - /* Test the port D mode */ - /************************/ - - if ((b_PortDMode == 0) || (b_PortDMode == 1)) { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_TTLInit - = - 1; - - /***********************/ - /* Set TTL port A mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [0] - = - b_PortAMode; - - /***********************/ - /* Set TTL port B mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [1] - = - b_PortBMode; - - /***********************/ - /* Set TTL port C mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [2] - = - b_PortCMode; - - /***********************/ - /* Set TTL port D mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [3] - = - b_PortDMode; - - /*************************/ - /* Set the configuration */ - /*************************/ - - outl((b_PortAMode << 0) | (b_PortBMode << 1) | (b_PortCMode << 2) | (b_PortDMode << 3), devpriv->s_BoardInfos.ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /**********************************/ - /* Port D mode selection is wrong */ - /**********************************/ - - DPRINTK("Port D mode selection is wrong\n"); - i_ReturnValue - = - -8; - } - } else { - /**********************************/ - /* Port C mode selection is wrong */ - /**********************************/ - - DPRINTK("Port C mode selection is wrong\n"); - i_ReturnValue = - -7; - } - } else { - /**********************************/ - /* Port B mode selection is wrong */ - /**********************************/ - - DPRINTK("Port B mode selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /**********************************/ - /* Port A mode selection is wrong */ - /**********************************/ - - DPRINTK("Port A mode selection is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*******************************************/ - /* Function not available for this version */ - /*******************************************/ - - DPRINTK("Function not available for this version\n"); - i_ReturnValue = -4; - } - break; - - DPRINTK("\n"); - default: - printk("Bad Config Type\n"); - } /* switch end */ - } else { - /**********************************/ - /* The module is not a TTL module */ - /**********************************/ - - DPRINTK("The module is not a TTL module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadTTLIOChannelValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedPort, | -| unsigned char_ b_InputChannel, | -| unsigned char *_ pb_ChannelStatus) | -+----------------------------------------------------------------------------+ -| Task : Read the status from selected TTL digital input | -| (b_InputChannel) -+----------------------------------------------------------------------------+ -| Task : Read the status from digital input port | -| (b_SelectedPort) from selected TTL module (b_ModulNbr) | -+----------------------------------------------------------------------------+ - -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 7) | -| unsigned char_ b_SelectedPort, : Selection from TTL I/O | -| port (0 to 2) | -| 0 : Port A selection | -| 1 : Port B selection | -| 2 : Port C selection | -| 3 : Port D selection | -| unsigned char_ b_InputChannel : Selection from digital | -| input ( 0 to 2) -APCI1710_TTL_READCHANNEL - b_ModulNbr = CR_AREF(insn->chanspec); - b_SelectedPort= CR_RANGE(insn->chanspec); - b_InputChannel= CR_CHAN(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - - APCI1710_TTL_READPORT| - b_ModulNbr = CR_AREF(insn->chanspec); - b_SelectedPort= CR_RANGE(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] - - unsigned char *_ pb_ChannelStatus : Digital input channel | -| status | -| 0 : Channle is not active| -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL module | -| -4: The selected TTL input port is wrong | -| -5: The selected TTL digital input is wrong | -| -6: TTL I/O not initialised | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr; - unsigned char b_SelectedPort; - unsigned char b_InputChannel; - unsigned char b_ReadType; - unsigned char *pb_ChannelStatus; - unsigned char *pb_PortValue; - - i_ReturnValue = insn->n; - b_ReadType = (unsigned char) data[0]; - b_ModulNbr = CR_AREF(insn->chanspec); - b_SelectedPort = CR_RANGE(insn->chanspec); - b_InputChannel = CR_CHAN(insn->chanspec); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - switch (b_ReadType) { - - case APCI1710_TTL_READCHANNEL: - pb_ChannelStatus = (unsigned char *) &data[0]; - /********************************/ - /* Test the TTL I/O port number */ - /********************************/ - - if (((b_SelectedPort <= 2) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) == - 0x3130)) - || ((b_SelectedPort <= 3) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3230))) { - /******************************************/ - /* Test the digital imnput channel number */ - /******************************************/ - - if (((b_InputChannel <= 7) - && (b_SelectedPort < 3)) - || ((b_InputChannel <= 1) - && (b_SelectedPort == - 3))) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == - 1) { - /***********************************/ - /* Test if TTL port used for input */ - /***********************************/ - - if (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) == 0x3130) || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - (64 * b_ModulNbr)); - - *pb_ChannelStatus - = - (unsigned char) ( - (dw_StatusReg - >> - (8 * b_SelectedPort)) >> b_InputChannel) & 1; - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = - -4; - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -6; - } - } else { - /********************************/ - /* Selected digital input error */ - /********************************/ - - DPRINTK("Selected digital input error\n"); - i_ReturnValue = -5; - } - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = -4; - } - break; - - case APCI1710_TTL_READPORT: - pb_PortValue = (unsigned char *) &data[0]; - /********************************/ - /* Test the TTL I/O port number */ - /********************************/ - - if (((b_SelectedPort <= 2) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) == - 0x3130)) - || ((b_SelectedPort <= 3) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3230))) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == 1) { - /***********************************/ - /* Test if TTL port used for input */ - /***********************************/ - - if (((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] - & - 0xFFFF) - == 0x3130) - || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - - *pb_PortValue = - (unsigned char) ( - (dw_StatusReg >> - (8 * b_SelectedPort)) & 0xFF); - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = -4; - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = -4; - } - break; - - default: - printk("Bad ReadType\n"); - - } /* End Switch */ - } else { - /**********************************/ - /* The module is not a TTL module */ - /**********************************/ - - DPRINTK("The module is not a TTL module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnReadTTLIOAllPortValue(comedi_device -*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from all digital input ports | -| (port A, port B and port C) from selected TTL | -| module (b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_PortValue : Digital TTL inputs port | -| status | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL module | -| -4: TTL I/O not initialised | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr; - unsigned int *pul_PortValue; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - i_ReturnValue = insn->n; - pul_PortValue = (unsigned int *) &data[0]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == 1) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - /**********************/ - /* Test if TTL Rev1.0 */ - /**********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & 0xFFFF) == - 0x3130) { - *pul_PortValue = - dw_StatusReg & 0xFFFFFFUL; - } else { - /**************************************/ - /* Test if port A not used for output */ - /**************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[0] == 1) { - *pul_PortValue = - dw_StatusReg & - 0x3FFFF00UL; - } - - /**************************************/ - /* Test if port B not used for output */ - /**************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[1] == 1) { - *pul_PortValue = - dw_StatusReg & - 0x3FF00FFUL; - } - - /**************************************/ - /* Test if port C not used for output */ - /**************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[2] == 1) { - *pul_PortValue = - dw_StatusReg & - 0x300FFFFUL; - } - - /**************************************/ - /* Test if port D not used for output */ - /**************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[3] == 1) { - *pul_PortValue = - dw_StatusReg & - 0xFFFFFFUL; - } - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /**********************************/ - /* The module is not a TTL module */ - /**********************************/ - DPRINTK("The module is not a TTL module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetTTLIOChlOn | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_OutputChannel) -int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Sets or resets the output witch has been passed with the | -| parameter b_Channel. Setting an output means setting | -| an ouput high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel : Selection from digital output | -| channel (0 or 1) | -| 0 : PD0 | -| 1 : PD1 | -| 2 to 9 : PA | -| 10 to 17: PB | -| 18 to 25: PC | - - b_ModulNbr = CR_AREF(insn->chanspec); - b_OutputChannel= CR_CHAN(insn->chanspec); - ui_State = data[0]; /* ON or OFF */ -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL I/O module | -| -4: The selected digital output is wrong | -| -5: TTL I/O not initialised see function | -| " i_APCI1710_InitTTLIO" -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - unsigned char b_ModulNbr; - unsigned char b_OutputChannel; - unsigned int ui_State; - - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_OutputChannel = CR_CHAN(insn->chanspec); - ui_State = data[0]; /* ON or OFF */ - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == 1) { - /***********************************/ - /* Test the TTL I/O channel number */ - /***********************************/ - - if (((b_OutputChannel <= 1) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) == - 0x3130)) - || ((b_OutputChannel <= 25) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3230))) { - /****************************************************/ - /* Test if the selected channel is a output channel */ - /****************************************************/ - - if (((b_OutputChannel <= 1) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [3] == 1)) - || ((b_OutputChannel >= 2) - && (b_OutputChannel <= - 9) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [0] == 1)) - || ((b_OutputChannel >= 10) - && (b_OutputChannel <= - 17) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [1] == 1)) - || ((b_OutputChannel >= 18) - && (b_OutputChannel <= - 25) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [2] == 1))) { - /************************/ - /* Test if PD0 selected */ - /************************/ - - if (b_OutputChannel == 0) { - - outl(ui_State, - devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } else { - /************************/ - /* Test if PD1 selected */ - /************************/ - - if (b_OutputChannel == - 1) { - - outl(ui_State, - devpriv-> - s_BoardInfos. - ui_Address - + 4 + - (64 * b_ModulNbr)); - } else { - b_OutputChannel - = - b_OutputChannel - - 2; - - /********************/ - /* Read all channel */ - /********************/ - - dw_StatusReg = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - (64 * b_ModulNbr)); - if (ui_State) /* ON */ - { - dw_StatusReg - = - (dw_StatusReg - >> - ((b_OutputChannel / 8) * 8)) & 0xFF; - dw_StatusReg - = - dw_StatusReg - | - (1 - << - (b_OutputChannel - % - 8)); - } else /* Off */ - { - dw_StatusReg - = - (dw_StatusReg - >> - ((b_OutputChannel / 8) * 8)) & 0xFF; - dw_StatusReg - = - dw_StatusReg - & - (0xFF - - - (1 << (b_OutputChannel % 8))); - - } - - /****************************/ - /* Set the new output value */ - /****************************/ - - outl(dw_StatusReg, devpriv->s_BoardInfos.ui_Address + 8 + ((b_OutputChannel / 8) * 4) + (64 * b_ModulNbr)); - } - } - } else { - /************************************/ - /* The selected TTL output is wrong */ - /************************************/ - - DPRINTK(" The selected TTL output is wrong\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* The selected TTL output is wrong */ - /************************************/ - - DPRINTK("The selected TTL output is wrong\n"); - i_ReturnValue = -4; - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /**************************************/ - /* The module is not a TTL I/O module */ - /**************************************/ - - DPRINTK("The module is not a TTL I/O module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index f25e0085219..dc87df03220 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -85,10 +85,9 @@ static int addi_auto_attach(struct comedi_device *dev, dev->board_name = this_board->pc_DriverName; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -205,7 +204,6 @@ static int addi_auto_attach(struct comedi_device *dev, s->len_chanlist = devpriv->s_EeParameters.i_NbrDiChannel; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_config = this_board->di_config; s->insn_read = this_board->di_read; s->insn_write = this_board->di_write; @@ -224,7 +222,6 @@ static int addi_auto_attach(struct comedi_device *dev, s->len_chanlist = devpriv->s_EeParameters.i_NbrDoChannel; s->range_table = &range_digital; - s->io_bits = 0xf; /* all bits output */ /* insn_config - for digital output memory */ s->insn_config = this_board->do_config; diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index f1be5ade996..5c6a11c35de 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -113,171 +113,19 @@ struct addi_board { struct comedi_insn *, unsigned int *); }; -/* MODULE INFO STRUCTURE */ - -union str_ModuleInfo { - /* Incremental counter infos */ - struct { - union { - struct { - unsigned char b_ModeRegister1; - unsigned char b_ModeRegister2; - unsigned char b_ModeRegister3; - unsigned char b_ModeRegister4; - } s_ByteModeRegister; - unsigned int dw_ModeRegister1_2_3_4; - } s_ModeRegister; - - struct { - unsigned int b_IndexInit:1; - unsigned int b_CounterInit:1; - unsigned int b_ReferenceInit:1; - unsigned int b_IndexInterruptOccur:1; - unsigned int b_CompareLogicInit:1; - unsigned int b_FrequencyMeasurementInit:1; - unsigned int b_FrequencyMeasurementEnable:1; - } s_InitFlag; - - } s_SiemensCounterInfo; - - /* SSI infos */ - struct { - unsigned char b_SSIProfile; - unsigned char b_PositionTurnLength; - unsigned char b_TurnCptLength; - unsigned char b_SSIInit; - } s_SSICounterInfo; - - /* TTL I/O infos */ - struct { - unsigned char b_TTLInit; - unsigned char b_PortConfiguration[4]; - } s_TTLIOInfo; - - /* Digital I/O infos */ - struct { - unsigned char b_DigitalInit; - unsigned char b_ChannelAMode; - unsigned char b_ChannelBMode; - unsigned char b_OutputMemoryEnabled; - unsigned int dw_OutputMemory; - } s_DigitalIOInfo; - - /*********************/ - /* 82X54 timer infos */ - /*********************/ - - struct { - struct { - unsigned char b_82X54Init; - unsigned char b_InputClockSelection; - unsigned char b_InputClockLevel; - unsigned char b_OutputLevel; - unsigned char b_HardwareGateLevel; - unsigned int dw_ConfigurationWord; - } s_82X54TimerInfo[3]; - unsigned char b_InterruptMask; - } s_82X54ModuleInfo; - - /*********************/ - /* Chronometer infos */ - /*********************/ - - struct { - unsigned char b_ChronoInit; - unsigned char b_InterruptMask; - unsigned char b_PCIInputClock; - unsigned char b_TimingUnit; - unsigned char b_CycleMode; - double d_TimingInterval; - unsigned int dw_ConfigReg; - } s_ChronoModuleInfo; - - /***********************/ - /* Pulse encoder infos */ - /***********************/ - - struct { - struct { - unsigned char b_PulseEncoderInit; - } s_PulseEncoderInfo[4]; - unsigned int dw_SetRegister; - unsigned int dw_ControlRegister; - unsigned int dw_StatusRegister; - } s_PulseEncoderModuleInfo; - - /* Tor conter infos */ - struct { - struct { - unsigned char b_TorCounterInit; - unsigned char b_TimingUnit; - unsigned char b_InterruptEnable; - double d_TimingInterval; - unsigned int ul_RealTimingInterval; - } s_TorCounterInfo[2]; - unsigned char b_PCIInputClock; - } s_TorCounterModuleInfo; - - /* PWM infos */ - struct { - struct { - unsigned char b_PWMInit; - unsigned char b_TimingUnit; - unsigned char b_InterruptEnable; - double d_LowTiming; - double d_HighTiming; - unsigned int ul_RealLowTiming; - unsigned int ul_RealHighTiming; - } s_PWMInfo[2]; - unsigned char b_ClockSelection; - } s_PWMModuleInfo; - - /* ETM infos */ - struct { - struct { - unsigned char b_ETMEnable; - unsigned char b_ETMInterrupt; - } s_ETMInfo[2]; - unsigned char b_ETMInit; - unsigned char b_TimingUnit; - unsigned char b_ClockSelection; - double d_TimingInterval; - unsigned int ul_Timing; - } s_ETMModuleInfo; - - /* CDA infos */ - struct { - unsigned char b_CDAEnable; - unsigned char b_CDAInterrupt; - unsigned char b_CDAInit; - unsigned char b_FctSelection; - unsigned char b_CDAReadFIFOOverflow; - } s_CDAModuleInfo; - -}; - -/* Private structure for the addi_apci3120 driver */ struct addi_private { int iobase; int i_IobaseAmcc; /* base+size for AMCC chip */ int i_IobaseAddon; /* addon base address */ int i_IobaseReserved; - unsigned char b_AiContinuous; /* we do unlimited AI */ unsigned int ui_AiActualScan; /* how many scans we finished */ unsigned int ui_AiNbrofChannels; /* how many channels is measured */ - unsigned int ui_AiScanLength; /* Length of actual scanlist */ - unsigned int *pui_AiChannelList; /* actual chanlist */ unsigned int ui_AiChannelList[32]; /* actual chanlist */ unsigned int ui_AiReadData[32]; - unsigned int ui_AiTimer0; /* Timer Constant for Timer0 */ - unsigned int ui_AiTimer1; /* Timer constant for Timer1 */ - unsigned int ui_AiFlags; - unsigned int ui_AiDataLength; - unsigned int ui_AiNbrofScans; /* number of scans to do */ unsigned short us_UseDma; /* To use Dma or not */ unsigned char b_DmaDoubleBuffer; /* we can use double buffering */ unsigned int ui_DmaActualBuffer; /* which buffer is used now */ - short *ul_DmaBufferVirtual[2]; /* pointers to begin of DMA buffer */ + unsigned short *ul_DmaBufferVirtual[2]; /* pointers to DMA buffer */ unsigned int ul_DmaBufferHw[2]; /* hw address of DMA buff */ unsigned int ui_DmaBufferSize[2]; /* size of dma buffer in bytes */ unsigned int ui_DmaBufferUsesize[2]; /* which size we may now used for transfer */ @@ -289,7 +137,7 @@ struct addi_private { unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */ unsigned char b_Timer2Mode; /* Specify the timer 2 mode */ unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */ - unsigned char b_AiCyclicAcquisition; /* indicate cyclic acquisition */ + unsigned int ai_running:1; unsigned char b_InterruptMode; /* eoc eos or dma */ unsigned char b_EocEosInterrupt; /* Enable disable eoc eos interrupt */ unsigned int ui_EocEosConversionTime; @@ -299,31 +147,6 @@ struct addi_private { /* Pointer to the current process */ struct task_struct *tsk_Current; - /* Hardware board infos for 1710 */ - struct { - unsigned int ui_Address; /* Board address */ - unsigned int ui_FlashAddress; - unsigned char b_InterruptNbr; /* Board interrupt number */ - unsigned char b_SlotNumber; /* PCI slot number */ - unsigned char b_BoardVersion; - unsigned int dw_MolduleConfiguration[4]; /* Module config */ - } s_BoardInfos; - - /* Interrupt infos */ - struct { - unsigned int ul_InterruptOccur; /* 0 : No interrupt occur */ - /* > 0 : Interrupt occur */ - unsigned int ui_Read; /* Read FIFO */ - unsigned int ui_Write; /* Write FIFO */ - struct { - unsigned char b_OldModuleMask; - unsigned int ul_OldInterruptMask; /* Interrupt mask */ - unsigned int ul_OldCounterLatchValue; /* Interrupt counter value */ - } s_FIFOInterruptParameters[APCI1710_SAVE_INTERRUPT]; - } s_InterruptParameters; - - union str_ModuleInfo s_ModuleInfo[4]; - /* Parameters read from EEPROM overriding static board info */ struct { int i_NbrAiChannel; /* num of A/D chans */ diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c index dc031c494a2..aafc172f3a9 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c @@ -22,6 +22,8 @@ * for more details. */ +#include <linux/delay.h> + #define NVRAM_USER_DATA_START 0x100 #define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c deleted file mode 100644 index b1a7ec1035e..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c +++ /dev/null @@ -1,1314 +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. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1710 | Compiler : GCC | - | Module name : hwdrv_apci1710.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1710 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#define COMEDI_SUBD_PWM 12 /* Pulse width Measurement */ -#define COMEDI_SUBD_SSI 13 /* Synchronous serial interface */ -#define COMEDI_SUBD_TOR 14 /* Tor counter */ -#define COMEDI_SUBD_CHRONO 15 /* Chrono meter */ -#define COMEDI_SUBD_PULSEENCODER 16 /* Pulse Encoder INP CPT */ -#define COMEDI_SUBD_INCREMENTALCOUNTER 17 /* Incremental Counter */ - -#define APCI1710_BOARD_NAME "apci1710" -#define APCI1710_BOARD_DEVICE_ID 0x818F -#define APCI1710_ADDRESS_RANGE 256 -#define APCI1710_CONFIG_ADDRESS_RANGE 8 -#define APCI1710_INCREMENTAL_COUNTER 0x53430000UL -#define APCI1710_SSI_COUNTER 0x53490000UL -#define APCI1710_TTL_IO 0x544C0000UL -#define APCI1710_DIGITAL_IO 0x44490000UL -#define APCI1710_82X54_TIMER 0x49430000UL -#define APCI1710_CHRONOMETER 0x43480000UL -#define APCI1710_PULSE_ENCODER 0x495A0000UL -#define APCI1710_TOR_COUNTER 0x544F0000UL -#define APCI1710_PWM 0x50570000UL -#define APCI1710_ETM 0x45540000UL -#define APCI1710_CDA 0x43440000UL -#define APCI1710_DISABLE 0 -#define APCI1710_ENABLE 1 -#define APCI1710_SYNCHRONOUS_MODE 1 -#define APCI1710_ASYNCHRONOUS_MODE 0 - -#include "APCI1710_Inp_cpt.c" - -#include "APCI1710_Ssi.c" -#include "APCI1710_Tor.c" -#include "APCI1710_Ttl.c" -#include "APCI1710_Dig_io.c" -#include "APCI1710_82x54.c" -#include "APCI1710_Chrono.c" -#include "APCI1710_Pwm.c" -#include "APCI1710_INCCPT.c" - -static const struct comedi_lrange range_apci1710_ttl = { - 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1) - } -}; - -static const struct comedi_lrange range_apci1710_ssi = { - 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1) - } -}; - -static const struct comedi_lrange range_apci1710_inccpt = { - 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1) - } -}; - -static void i_ADDI_AttachPCI1710(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int ret = 0; - int n_subdevices = 9; - - ret = comedi_alloc_subdevices(dev, n_subdevices); - if (ret) - return; - - /* Allocate and Initialise Timer Subdevice Structures */ - s = &dev->subdevices[0]; - - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 3; - s->maxdata = 0; - s->len_chanlist = 3; - s->range_table = &range_digital; - s->insn_write = i_APCI1710_InsnWriteEnableDisableTimer; - s->insn_read = i_APCI1710_InsnReadAllTimerValue; - s->insn_config = i_APCI1710_InsnConfigInitTimer; - s->insn_bits = i_APCI1710_InsnBitsTimer; - - /* Allocate and Initialise DIO Subdevice Structures */ - s = &dev->subdevices[1]; - - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 7; - s->maxdata = 1; - s->len_chanlist = 7; - s->range_table = &range_digital; - s->insn_config = i_APCI1710_InsnConfigDigitalIO; - s->insn_read = i_APCI1710_InsnReadDigitalIOChlValue; - s->insn_bits = i_APCI1710_InsnBitsDigitalIOPortOnOff; - s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff; - - /* Allocate and Initialise Chrono Subdevice Structures */ - s = &dev->subdevices[2]; - - s->type = COMEDI_SUBD_CHRONO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 0; - s->len_chanlist = 4; - s->range_table = &range_digital; - s->insn_write = i_APCI1710_InsnWriteEnableDisableChrono; - s->insn_read = i_APCI1710_InsnReadChrono; - s->insn_config = i_APCI1710_InsnConfigInitChrono; - s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO; - - /* Allocate and Initialise PWM Subdevice Structures */ - s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 3; - s->maxdata = 1; - s->len_chanlist = 3; - s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ - s->insn_config = i_APCI1710_InsnConfigPWM; - s->insn_read = i_APCI1710_InsnReadGetPWMStatus; - s->insn_write = i_APCI1710_InsnWritePWM; - s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt; - - /* Allocate and Initialise TTLIO Subdevice Structures */ - s = &dev->subdevices[4]; - s->type = COMEDI_SUBD_TTLIO; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 8; - s->maxdata = 1; - s->len_chanlist = 8; - s->range_table = &range_apci1710_ttl; /* to pass arguments in range */ - s->insn_config = i_APCI1710_InsnConfigInitTTLIO; - s->insn_bits = i_APCI1710_InsnBitsReadTTLIO; - s->insn_write = i_APCI1710_InsnWriteSetTTLIOChlOnOff; - s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue; - - /* Allocate and Initialise TOR Subdevice Structures */ - s = &dev->subdevices[5]; - s->type = COMEDI_SUBD_TOR; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 8; - s->maxdata = 1; - s->len_chanlist = 8; - s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ - s->insn_config = i_APCI1710_InsnConfigInitTorCounter; - s->insn_read = i_APCI1710_InsnReadGetTorCounterInitialisation; - s->insn_write = i_APCI1710_InsnWriteEnableDisableTorCounter; - s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue; - - /* Allocate and Initialise SSI Subdevice Structures */ - s = &dev->subdevices[6]; - s->type = COMEDI_SUBD_SSI; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 1; - s->len_chanlist = 4; - s->range_table = &range_apci1710_ssi; - s->insn_config = i_APCI1710_InsnConfigInitSSI; - s->insn_read = i_APCI1710_InsnReadSSIValue; - s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO; - - /* Allocate and Initialise PULSEENCODER Subdevice Structures */ - s = &dev->subdevices[7]; - s->type = COMEDI_SUBD_PULSEENCODER; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 1; - s->len_chanlist = 4; - s->range_table = &range_digital; - s->insn_config = i_APCI1710_InsnConfigInitPulseEncoder; - s->insn_write = i_APCI1710_InsnWriteEnableDisablePulseEncoder; - s->insn_bits = i_APCI1710_InsnBitsReadWritePulseEncoder; - s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder; - - /* Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures */ - s = &dev->subdevices[8]; - s->type = COMEDI_SUBD_INCREMENTALCOUNTER; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 500; - s->maxdata = 1; - s->len_chanlist = 500; - s->range_table = &range_apci1710_inccpt; - s->insn_config = i_APCI1710_InsnConfigINCCPT; - s->insn_write = i_APCI1710_InsnWriteINCCPT; - s->insn_read = i_APCI1710_InsnReadINCCPT; - s->insn_bits = i_APCI1710_InsnBitsINCCPT; -} - -static int i_APCI1710_Reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - int ret; - unsigned int dw_Dummy; - - /*********************************/ - /* Read all module configuration */ - /*********************************/ - ret = inl(devpriv->s_BoardInfos.ui_Address + 60); - devpriv->s_BoardInfos.dw_MolduleConfiguration[0] = ret; - - ret = inl(devpriv->s_BoardInfos.ui_Address + 124); - devpriv->s_BoardInfos.dw_MolduleConfiguration[1] = ret; - - ret = inl(devpriv->s_BoardInfos.ui_Address + 188); - devpriv->s_BoardInfos.dw_MolduleConfiguration[2] = ret; - - ret = inl(devpriv->s_BoardInfos.ui_Address + 252); - devpriv->s_BoardInfos.dw_MolduleConfiguration[3] = ret; - - /* outl(0x80808082,devpriv->s_BoardInfos.ui_Address+0x60); */ - outl(0x83838383, devpriv->s_BoardInfos.ui_Address + 0x60); - - devpriv->s_BoardInfos.b_BoardVersion = 1; - - /* Enable the interrupt for the controller */ - dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38); - outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38); - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function's Name : __void__ v_APCI1710_InterruptFunction | -| (unsigned char b_Interrupt, __CPPARGS) | -+----------------------------------------------------------------------------+ -| Task : APCI-1710 interrupt function | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char b_Interrupt : Interrupt number | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 : OK | -| -1 : Error | -+----------------------------------------------------------------------------+ -*/ - -static void v_APCI1710_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct addi_private *devpriv = dev->private; - unsigned char b_ModuleCpt = 0; - unsigned char b_InterruptFlag = 0; - unsigned char b_PWMCpt = 0; - unsigned char b_TorCounterCpt = 0; - unsigned char b_PulseIncoderCpt = 0; - unsigned int ui_16BitValue; - unsigned int ul_InterruptLatchReg = 0; - unsigned int ul_LatchRegisterValue = 0; - unsigned int ul_82X54InterruptStatus; - unsigned int ul_StatusRegister; - - union str_ModuleInfo *ps_ModuleInfo; - - printk("APCI1710 Interrupt\n"); - for (b_ModuleCpt = 0; b_ModuleCpt < 4; b_ModuleCpt++, ps_ModuleInfo++) { - - /**************************/ - /* 1199/0225 to 0100/0226 */ - /**************************/ - ps_ModuleInfo = &devpriv->s_ModuleInfo[b_ModuleCpt]; - - /***********************/ - /* Test if 82X54 timer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - - /* printk("TIMER Interrupt Occurred\n"); */ - ul_82X54InterruptStatus = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if ((ul_82X54InterruptStatus & ps_ModuleInfo-> - s_82X54ModuleInfo. - b_InterruptMask) != 0) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - (ul_82X54InterruptStatus & - ps_ModuleInfo->s_82X54ModuleInfo. - b_InterruptMask) << 4; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write].ul_OldCounterLatchValue = 0; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - - } /* if ((ul_82X54InterruptStatus & 0x7) != 0) */ - } /* 82X54 timer */ - - /***************************/ - /* Test if increm. counter */ - /***************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) { - - ul_InterruptLatchReg = inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModuleCpt)); - - /*********************/ - /* Test if interrupt */ - /*********************/ - - if ((ul_InterruptLatchReg & 0x22) && (ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & 0x80)) { - /************************************/ - /* Test if strobe latch I interrupt */ - /************************************/ - - if (ul_InterruptLatchReg & 2) { - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos. - ui_Address + 4 + - (64 * b_ModuleCpt)); - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 1UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - - /*************************************/ - /* Test if strobe latch II interrupt */ - /*************************************/ - - if (ul_InterruptLatchReg & 0x20) { - - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos. - ui_Address + 8 + - (64 * b_ModuleCpt)); - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 2UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - - ul_InterruptLatchReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if index interrupt */ - /***************************/ - - if (ul_InterruptLatchReg & 0x8) { - ps_ModuleInfo-> - s_SiemensCounterInfo. - s_InitFlag.b_IndexInterruptOccur = 1; - - if (ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & - APCI1710_INDEX_AUTO_MODE) { - - outl(ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos. - ui_Address + 20 + - (64 * b_ModuleCpt)); - } - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if ((ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_ENABLE_INDEX_INT) == - APCI1710_ENABLE_INDEX_INT) { - devpriv->s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 4UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - - /*****************************/ - /* Test if compare interrupt */ - /*****************************/ - - if (ul_InterruptLatchReg & 0x10) { - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if ((ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_ENABLE_COMPARE_INT) == - APCI1710_ENABLE_COMPARE_INT) { - devpriv->s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 8UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - - /*******************************************/ - /* Test if frequency measurement interrupt */ - /*******************************************/ - - if (ul_InterruptLatchReg & 0x20) { - /*******************/ - /* Read the status */ - /*******************/ - - ul_StatusRegister = inl(devpriv->s_BoardInfos. - ui_Address + 32 + (64 * b_ModuleCpt)); - - /******************/ - /* Read the value */ - /******************/ - - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos.ui_Address + - 28 + (64 * b_ModuleCpt)); - - switch ((ul_StatusRegister >> 1) & 3) { - case 0: - /*************************/ - /* Test the counter mode */ - /*************************/ - - if ((devpriv->s_ModuleInfo[b_ModuleCpt]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 & - APCI1710_16BIT_COUNTER) - == APCI1710_16BIT_COUNTER) { - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & - 0xFFFFU) != 0) { - ui_16BitValue = - (unsigned int) - ul_LatchRegisterValue - & 0xFFFFU; - ul_LatchRegisterValue = - (ul_LatchRegisterValue - & 0xFFFF0000UL) - | (0xFFFFU - - ui_16BitValue); - } - - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & - 0xFFFF0000UL) != - 0) { - ui_16BitValue = - (unsigned int) ( - (ul_LatchRegisterValue - >> 16) & - 0xFFFFU); - ul_LatchRegisterValue = - (ul_LatchRegisterValue - & 0xFFFFUL) | - ((0xFFFFU - - ui_16BitValue) - << 16); - } - } else { - if (ul_LatchRegisterValue != 0) { - ul_LatchRegisterValue = - 0xFFFFFFFFUL - - ul_LatchRegisterValue; - } - } - break; - - case 1: - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & - 0xFFFF0000UL) != 0) { - ui_16BitValue = - (unsigned int) ( - (ul_LatchRegisterValue - >> 16) & - 0xFFFFU); - ul_LatchRegisterValue = - (ul_LatchRegisterValue & - 0xFFFFUL) | ((0xFFFFU - - ui_16BitValue) - << 16); - } - break; - - case 2: - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & 0xFFFFU) != - 0) { - ui_16BitValue = - (unsigned int) - ul_LatchRegisterValue & - 0xFFFFU; - ul_LatchRegisterValue = - (ul_LatchRegisterValue & - 0xFFFF0000UL) | (0xFFFFU - - ui_16BitValue); - } - break; - } - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = 0x10000UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - - } - } /* Incremental counter */ - - /***************/ - /* Test if CDA */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_CDA) { - /******************************************/ - /* Test if CDA enable and functionality 0 */ - /******************************************/ - - if ((devpriv->s_ModuleInfo[b_ModuleCpt]. - s_CDAModuleInfo. - b_CDAEnable == APCI1710_ENABLE) - && (devpriv->s_ModuleInfo[b_ModuleCpt]. - s_CDAModuleInfo.b_FctSelection == 0)) { - /****************************/ - /* Get the interrupt status */ - /****************************/ - - ul_StatusRegister = inl(devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModuleCpt)); - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if (ul_StatusRegister & 1) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 0x80000UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = 0; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } /* if (ul_StatusRegister & 1) */ - - } - } /* CDA */ - - /***********************/ - /* Test if PWM counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_PWM) { - for (b_PWMCpt = 0; b_PWMCpt < 2; b_PWMCpt++) { - /*************************************/ - /* Test if PWM interrupt initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModuleCpt]. - s_PWMModuleInfo. - s_PWMInfo[b_PWMCpt]. - b_InterruptEnable == APCI1710_ENABLE) { - /*****************************/ - /* Read the interrupt status */ - /*****************************/ - - ul_StatusRegister = - inl(devpriv->s_BoardInfos. - ui_Address + 16 + - (20 * b_PWMCpt) + - (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if (ul_StatusRegister & 0x1) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - 0x4000UL << b_PWMCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % - APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, - devpriv->tsk_Current, - 0); - - } /* if (ul_StatusRegister & 0x1) */ - } /* if (APCI1710_ENABLE) */ - } /* for (b_PWMCpt == 0; b_PWMCpt < 0; b_PWMCpt ++) */ - } /* PWM counter */ - - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - for (b_TorCounterCpt = 0; b_TorCounterCpt < 2; - b_TorCounterCpt++) { - /*************************************/ - /* Test if tor interrupt initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModuleCpt]. - s_TorCounterModuleInfo. - s_TorCounterInfo[b_TorCounterCpt]. - b_InterruptEnable == APCI1710_ENABLE) { - /*****************************/ - /* Read the interrupt status */ - /*****************************/ - - ul_StatusRegister = - inl(devpriv->s_BoardInfos. - ui_Address + 12 + - (16 * b_TorCounterCpt) + - (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if (ul_StatusRegister & 0x1) { - /******************************/ - /* Read the tor counter value */ - /******************************/ - - ul_LatchRegisterValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 0 + - (16 * b_TorCounterCpt) + - (64 * b_ModuleCpt)); - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - 0x1000UL << - b_TorCounterCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue - = ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % - APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, - devpriv->tsk_Current, - 0); - } /* if (ul_StatusRegister & 0x1) */ - } /* if (APCI1710_ENABLE) */ - } /* for (b_TorCounterCpt == 0; b_TorCounterCpt < 0; b_TorCounterCpt ++) */ - } /* Tor counter */ - - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - - /* printk("APCI1710 Chrono Interrupt\n"); */ - /*****************************/ - /* Read the interrupt status */ - /*****************************/ - - ul_InterruptLatchReg = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if ((ul_InterruptLatchReg & 0x8) == 0x8) { - /****************************/ - /* Clear the interrupt flag */ - /****************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 32 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if continuous mode */ - /***************************/ - - if (ps_ModuleInfo-> - s_ChronoModuleInfo. - b_CycleMode == APCI1710_ENABLE) { - /********************/ - /* Clear the status */ - /********************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 36 + - (64 * b_ModuleCpt)); - } - - /*************************/ - /* Read the timing value */ - /*************************/ - - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos.ui_Address + - 4 + (64 * b_ModuleCpt)); - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if (ps_ModuleInfo-> - s_ChronoModuleInfo.b_InterruptMask) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 0x80; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - } /* Chronometer */ - - /*************************/ - /* Test if pulse encoder */ - /*************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_PULSE_ENCODER) { - /****************************/ - /* Read the status register */ - /****************************/ - - ul_StatusRegister = inl(devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModuleCpt)); - - if (ul_StatusRegister & 0xF) { - for (b_PulseIncoderCpt = 0; - b_PulseIncoderCpt < 4; - b_PulseIncoderCpt++) { - /*************************************/ - /* Test if pulse encoder initialised */ - /*************************************/ - - if ((ps_ModuleInfo-> - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo - [b_PulseIncoderCpt]. - b_PulseEncoderInit == 1) - && (((ps_ModuleInfo->s_PulseEncoderModuleInfo.dw_SetRegister >> b_PulseIncoderCpt) & 1) == 1) && (((ul_StatusRegister >> (b_PulseIncoderCpt)) & 1) == 1)) { - devpriv->s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - 0x100UL << - b_PulseIncoderCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue - = ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % - APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, - devpriv->tsk_Current, - 0); - - } - } - } - } /* pulse encoder */ - - } - return; - -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index 1128c22e751..28450f65a13 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -1,46 +1,24 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-035 | Compiler : GCC | - | Module name : hwdrv_apci035.c | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-035 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ /* Card Specific information */ #define APCI035_ADDRESS_RANGE 255 @@ -106,99 +84,66 @@ static struct comedi_lrange range_apci035_ai = { } }; -static int i_WatchdogNbr = 0; -static int i_Temp = 0; +static int i_WatchdogNbr; +static int i_Temp; static int i_Flag = 1; + /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Watchdog | -| data[1] : Watchdog number -| data[2] : Time base Unit | -| data[3] : Reload Value | -| data[4] : External Trigger | -| 1:Enable -| 0:Disable -| data[5] :External Trigger Level -| 00 Trigger Disabled -| 01 Trigger Enabled (Low level) -| 10 Trigger Enabled (High Level) -| 11 Trigger Enabled (High/Low level) -| data[6] : External Gate | -| 1:Enable -| 0:Disable -| data[7] : External Gate level -| 00 Gate Disabled -| 01 Gate Enabled (Low level) -| 10 Gate Enabled (High Level) -| data[8] :Warning Relay -| 1: ENABLE -| 0: DISABLE -| data[9] :Warning Delay available -| data[10] :Warning Relay Time unit -| data[11] :Warning Relay Time Reload value -| data[12] :Reset Relay -| 1 : ENABLE -| 0 : DISABLE -| data[13] :Interrupt -| 1 : ENABLE -| 0 : DISABLE -| -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Timer , Counter or Watchdog + * + * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog + * data[1] Watchdog number + * data[2] Time base Unit + * data[3] Reload Value + * data[4] External Trigger, 1 = Enable, 0 = Disable + * data[5] External Trigger Level + * 00 = Trigger Disabled + * 01 = Trigger Enabled (Low level) + * 10 = Trigger Enabled (High Level) + * 11 = Trigger Enabled (High/Low level) + * data[6] External Gate, 1 = Enable, 0 = Disable + * data[7] External Gate level + * 00 = Gate Disabled + * 01 = Gate Enabled (Low level) + * 10 = Gate Enabled (High Level) + * data[8] Warning Relay, 1 = Enable, 0 = Disable + * data[9] Warning Delay available + * data[10] Warning Relay Time unit + * data[11] Warning Relay Time Reload value + * data[12] Reset Relay, 1 = Enable, 0 = Disable + * data[13] Interrupt, 1 = Enable, 0 = Disable + */ +static int apci035_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; - unsigned int ui_Command = 0; - unsigned int ui_Mode = 0; + unsigned int ui_Status; + unsigned int ui_Command; + unsigned int ui_Mode; i_Temp = 0; devpriv->tsk_Current = current; devpriv->b_TimerSelectMode = data[0]; i_WatchdogNbr = data[1]; - if (data[0] == 0) { + if (data[0] == 0) ui_Mode = 2; - } else { + else ui_Mode = 0; - } -/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */ + ui_Command = 0; -/* ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/************************/ -/* Set the reload value */ -/************************/ + + /* Set the reload value */ outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); -/*********************/ -/* Set the time unit */ -/*********************/ + + /* Set the time unit */ outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8); if (data[0] == ADDIDATA_TIMER) { - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -206,101 +151,82 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Enable the timer mode */ /* - Set the timer mode */ - /******************************/ ui_Command = (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; - } /* if (data[0] == ADDIDATA_TIMER) */ - else { - if (data[0] == ADDIDATA_WATCHDOG) { + } else if (data[0] == ADDIDATA_WATCHDOG) { - /******************************/ - /* Set the mode : */ - /* - Disable the hardware */ - /* - Disable the counter mode */ - /* - Disable the warning */ - /* - Disable the reset */ - /* - Disable the timer mode */ - /******************************/ + /* Set the mode : */ + /* - Disable the hardware */ + /* - Disable the counter mode */ + /* - Disable the warning */ + /* - Disable the reset */ + /* - Disable the timer mode */ - ui_Command = ui_Command & 0xFFF819E2UL; + ui_Command = ui_Command & 0xFFF819E2UL; - } else { - printk("\n The parameter for Timer/watchdog selection is in error\n"); - return -EINVAL; - } + } else { + dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n"); + return -EINVAL; } + outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/********************************/ -/* Disable the hardware trigger */ -/********************************/ + + /* Disable the hardware trigger */ ui_Command = ui_Command & 0xFFFFF89FUL; if (data[4] == ADDIDATA_ENABLE) { - /**********************************/ + /* Set the hardware trigger level */ - /**********************************/ ui_Command = ui_Command | (data[5] << 5); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*****************************/ -/* Disable the hardware gate */ -/*****************************/ + + /* Disable the hardware gate */ ui_Command = ui_Command & 0xFFFFF87FUL; if (data[6] == ADDIDATA_ENABLE) { -/*******************************/ -/* Set the hardware gate level */ -/*******************************/ + + /* Set the hardware gate level */ ui_Command = ui_Command | (data[7] << 7); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Disable the hardware output */ -/*******************************/ + + /* Disable the hardware output */ ui_Command = ui_Command & 0xFFFFF9FBUL; -/*********************************/ -/* Set the hardware output level */ -/*********************************/ + + /* Set the hardware output level */ ui_Command = ui_Command | (data[8] << 2); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); if (data[9] == ADDIDATA_ENABLE) { - /************************/ + /* Set the reload value */ - /************************/ outl(data[11], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24); - /**********************/ + /* Set the time unite */ - /**********************/ outl(data[10], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28); } - ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*******************************/ + /* Disable the hardware output */ - /*******************************/ ui_Command = ui_Command & 0xFFFFF9F7UL; - /*********************************/ + /* Set the hardware output level */ - /*********************************/ ui_Command = ui_Command | (data[12] << 3); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*************************************/ - /** Enable the watchdog interrupt **/ - /*************************************/ - ui_Command = 0; + + /* Enable the watchdog interrupt */ ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Set the interrupt selection */ -/*******************************/ + + /* Set the interrupt selection */ ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); @@ -310,82 +236,63 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_StartStopWriteTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 - Stop Selected Timer/Watchdog | -| 1 - Start Selected Timer/Watchdog | -| 2 - Trigger Selected Timer/Watchdog | -| 3 - Stop All Timer/Watchdog | -| 4 - Start All Timer/Watchdog | -| 5 - Trigger All Timer/Watchdog | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop The Selected Timer , or Watchdog + * + * data[0] + * 0 - Stop Selected Timer/Watchdog + * 1 - Start Selected Timer/Watch*dog + * 2 - Trigger Selected Timer/Watchdog + * 3 - Stop All Timer/Watchdog + * 4 - Start All Timer/Watchdog + * 5 - Trigger All Timer/Watchdog + */ +static int apci035_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Command = 0; - int i_Count = 0; + unsigned int ui_Command; + int i_Count; if (data[0] == 1) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /**********************/ + /* Start the hardware */ - /**********************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[0]==1) */ + } if (data[0] == 2) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /***************************/ + /* Set the trigger command */ - /***************************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } - if (data[0] == 0) /* Stop The Watchdog */ - { + if (data[0] == 0) { /* Stop The Watchdog */ ui_Command = 0; -/* -* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); -* ui_Command = ui_Command & 0xFFFFF9FEUL; -*/ + /* + * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); + * ui_Command = ui_Command & 0xFFFFF9FEUL; + */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[1]==0) */ - if (data[0] == 3) /* stop all Watchdogs */ - { + } + if (data[0] == 3) { + /* stop all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x2UL; - } else { + else ui_Command = 0x10UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + @@ -393,30 +300,29 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } } - if (data[0] == 4) /* start all Watchdogs */ - { + if (data[0] == 4) { + /* start all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x1UL; - } else { + else ui_Command = 0x8UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } } - if (data[0] == 5) /* trigger all Watchdogs */ - { + if (data[0] == 5) { + /* trigger all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x4UL; - } else { + else ui_Command = 0x20UL; - } i_WatchdogNbr = i_Count; outl(ui_Command, @@ -429,109 +335,61 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : software trigger status -| data[1] : hardware trigger status -| data[2] : Software clear status -| data[3] : Overflow status -| data[4] : Timer actual value -| - -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Selected Timer , Counter or Watchdog + * + * data[0] software trigger status + * data[1] hardware trigger status + * data[2] Software clear status + * data[3] Overflow status + * data[4] Timer actual value + */ +static int apci035_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; /* Status register */ + unsigned int ui_Status; /* Status register */ i_WatchdogNbr = insn->unused[0]; - /******************/ /* Get the status */ - /******************/ - ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); - /***********************************/ /* Get the software trigger status */ - /***********************************/ - data[0] = ((ui_Status >> 1) & 1); - /***********************************/ + /* Get the hardware trigger status */ - /***********************************/ data[1] = ((ui_Status >> 2) & 1); - /*********************************/ + /* Get the software clear status */ - /*********************************/ data[2] = ((ui_Status >> 3) & 1); - /***************************/ + /* Get the overflow status */ - /***************************/ data[3] = ((ui_Status >> 0) & 1); - if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { + if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Analog Input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| data[0] : Warning delay value -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Analog Input Subdevice + * + * data[0] Warning delay value + */ +static int apci035_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; devpriv->tsk_Current = current; outl(0x200 | 0, devpriv->iobase + 128 + 0x4); outl(0, devpriv->iobase + 128 + 0); -/********************************/ -/* Initialise the warning value */ -/********************************/ + + /* Initialise the warning value */ outl(0x300 | 0, devpriv->iobase + 128 + 0x4); outl((data[0] << 8), devpriv->iobase + 128 + 0); outl(0x200000UL, devpriv->iobase + 128 + 12); @@ -540,145 +398,88 @@ static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -| data[0] : Digital Value Of Input | -| | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read value of the selected channel + * + * data[0] Digital Value Of Input + */ +static int apci035_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_CommandRegister = 0; + unsigned int ui_CommandRegister; -/******************/ -/* Set the start */ -/******************/ + /* Set the start */ ui_CommandRegister = 0x80000; - /******************************/ + /* Write the command register */ - /******************************/ outl(ui_CommandRegister, devpriv->iobase + 128 + 8); -/***************************************/ -/* Read the digital value of the input */ -/***************************************/ + /* Read the digital value of the input */ data[0] = inl(devpriv->iobase + 128 + 28); return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task :Resets the registers of the card | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_Reset(struct comedi_device *dev) +static int apci035_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; - int i_Count = 0; + int i_Count; for (i_Count = 1; i_Count <= 4; i_Count++) { i_WatchdogNbr = i_Count; - outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */ + + /* stop all timers */ + outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ return 0; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI035_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt processing Routine | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI035_Interrupt(int irq, void *d) +static void apci035_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; - unsigned int ui_StatusRegister1 = 0; - unsigned int ui_StatusRegister2 = 0; - unsigned int ui_ReadCommand = 0; - unsigned int ui_ChannelNumber = 0; - unsigned int ui_DigitalTemperature = 0; + unsigned int ui_StatusRegister1; + unsigned int ui_StatusRegister2; + unsigned int ui_ReadCommand; + unsigned int ui_ChannelNumber; + unsigned int ui_DigitalTemperature; if (i_Temp == 1) { i_WatchdogNbr = i_Flag; i_Flag = i_Flag + 1; } - /**************************************/ + /* Read the interrupt status register of temperature Warning */ - /**************************************/ ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); - /**************************************/ - /* Read the interrupt status register for Watchdog/timer */ - /**************************************/ + /* Read the interrupt status register for Watchdog/timer */ ui_StatusRegister2 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); - if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */ - { - /**********************************/ + /* Test if warning relay interrupt */ + if ((((ui_StatusRegister1) & 0x8) == 0x8)) { + /* Disable the temperature warning */ - /**********************************/ ui_ReadCommand = inl(devpriv->iobase + 128 + 12); ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL; outl(ui_ReadCommand, devpriv->iobase + 128 + 12); - /***************************/ + /* Read the channel number */ - /***************************/ ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); - /**************************************/ + /* Read the digital temperature value */ - /**************************************/ ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */ - else { - if ((ui_StatusRegister2 & 0x1) == 0x1) { - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } - } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + + } else if ((ui_StatusRegister2 & 0x1) == 0x1) { + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + } return; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 054910511e9..a633957890d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -1,48 +1,25 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1500 | Compiler : GCC | - | Module name : hwdrv_apci1500.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1500 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/********* Definitions for APCI-1500 card *****/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ /* Card Specific information */ #define APCI1500_ADDRESS_RANGE 4 @@ -141,99 +118,45 @@ enum { APCI1500_RW_PORT_B_PATTERN_MASK }; -static int i_TimerCounter1Init = 0; -static int i_TimerCounter2Init = 0; -static int i_WatchdogCounter3Init = 0; -static int i_Event1Status = 0, i_Event2Status = 0; -static int i_TimerCounterWatchdogInterrupt = 0; -static int i_Logic = 0, i_CounterLogic = 0; -static int i_InterruptMask = 0; -static int i_InputChannel = 0; -static int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = 0, - i_WatchdogCounter3Enabled = 0; +static int i_TimerCounter1Init; +static int i_TimerCounter2Init; +static int i_WatchdogCounter3Init; +static int i_Event1Status, i_Event2Status; +static int i_TimerCounterWatchdogInterrupt; +static int i_Logic, i_CounterLogic; +static int i_InterruptMask; +static int i_InputChannel; +static int i_TimerCounter1Enabled, i_TimerCounter2Enabled, + i_WatchdogCounter3Enabled; /* - +----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : An event can be generated for each port. | -| The first event is related to the first 8 channels | -| (port 1) and the second to the following 6 channels | -| (port 2). An interrupt is generated when one or both | -| events have occurred | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] :Number of the input port on | -| which the event will take place | -| (1 or 2) -| data[1] : The event logic for port 1 has | -| three possibilities | -| :0 APCI1500_AND :This logic | -| links | -| the inputs | -| with an AND | -| logic. | -| 1 APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| OR logic. | -| 2 APCI1500_OR_PRIORITY | -| :This logic | -| links | -| the inputs | -| with a | -| priority | -| OR logic. | -| Input 1 | -| has the | -| highest | -| priority | -| level and | -| input 8 | -| the smallest| -| For the second port the user has| -| 1 possibility: | -| APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| polarity | -| OR logic | -| data[2] : These 8-character word for port1| -| and 6-character word for port 2 | -| give the mask of the event. | -| Each place gives the state | -| of the input channels and can | -| have one of these six characters| -| | -| 0 : This input must be on 0 | -| 1 : This input must be on 1 | -| 2 : This input reacts to | -| a falling edge | -| 3 : This input reacts to a | -| rising edge | -| 4 : This input reacts to both edges | -| -| 5 : This input is not | -| used for event | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * An event can be generated for each port. The first event is related to the + * first 8 channels (port 1) and the second to the following 6 channels (port 2) + * An interrupt is generated when one or both events have occurred. + * + * data[0] Number of the input port on which the event will take place (1 or 2) + * data[1] The event logic for port 1 has three possibilities: + * APCI1500_AND This logic links the inputs with an AND logic. + * APCI1500_OR This logic links the inputs with a OR logic. + * APCI1500_OR_PRIORITY This logic links the inputs with a priority OR + * logic. Input 1 has the highest priority level + * and input 8 the smallest. + * For the second port the user has 1 possibility: + * APCI1500_OR This logic links the inputs with a polarity OR logic + * data[2] These 8-character word for port1 and 6-character word for port 2 + * give the mask of the event. Each place gives the state of the input + * channels and can have one of these six characters + * 0 This input must be on 0 + * 1 This input must be on 1 + * 2 This input reacts to a falling edge + * 3 This input reacts to a rising edge + * 4 This input reacts to both edges + * 5 This input is not used for event + */ +static int apci1500_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0; @@ -241,14 +164,10 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, int i_PatternTransitionCount = 0, i_RegValue; int i; - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if (data[0] == 1) { @@ -259,7 +178,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_MaxChannel = 6; } /* if(data[0]==2) */ else { - printk("\nThe specified port event does not exist\n"); + dev_warn(dev->hw_dev, + "The specified port event does not exist\n"); return -EINVAL; } /* else if(data[0]==2) */ } /* else if (data[0] == 1) */ @@ -274,7 +194,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, data[1] = APCI1500_OR_PRIORITY; break; default: - printk("\nThe specified interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The specified interrupt logic does not exist\n"); return -EINVAL; } /* switch(data[1]); */ @@ -318,37 +239,30 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, case 5: break; default: - printk("\nThe option indicated in the event mask does not exist\n"); + dev_warn(dev->hw_dev, + "The option indicated in the event mask does not exist\n"); return -EINVAL; } /* switch(i_EventMask) */ } /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */ if (data[0] == 1) { - /****************************/ /* Test the interrupt logic */ - /****************************/ if (data[1] == APCI1500_AND || data[1] == APCI1500_OR || data[1] == APCI1500_OR_PRIORITY) { - /**************************************/ /* Tests if a transition was declared */ /* for a OR PRIORITY logic */ - /**************************************/ if (data[1] == APCI1500_OR_PRIORITY && i_PatternTransition != 0) { - /********************************************/ - /* Transition error on an OR PRIORITY logic */ - /********************************************/ - printk("\nTransition error on an OR PRIORITY logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an OR PRIORITY logic\n"); return -EINVAL; } /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */ - /*************************************/ /* Tests if more than one transition */ /* was declared for an AND logic */ - /*************************************/ if (data[1] == APCI1500_AND) { for (i_Count = 0; i_Count < 8; i_Count++) { @@ -360,29 +274,21 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* for (i_Count = 0; i_Count < 8; i_Count++) */ if (i_PatternTransitionCount > 1) { - /****************************************/ - /* Transition error on an AND logic */ - /****************************************/ - printk("\n Transition error on an AND logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an AND logic\n"); return -EINVAL; } /* if (i_PatternTransitionCount > 1) */ } /* if (data[1]== APCI1500_AND) */ - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the polarity register of port 1 */ - /**********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -390,20 +296,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the pattern mask register of */ /* port 1 */ - /*********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternMask, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************/ /* Selects the pattern transition register */ /* of port 1 */ - /********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -411,10 +313,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -422,17 +322,13 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Port A new mode */ - /**********************/ i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9; outb(i_RegValue, @@ -441,53 +337,40 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_Event1Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ } /* if (data[0]== 1) */ - /************************************/ /* Test if event setting for port 2 */ - /************************************/ if (data[0] == 2) { - /************************/ /* Test the event logic */ - /************************/ if (data[1] == APCI1500_OR) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the mode specification mask */ /* register of port B */ - /****************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -495,10 +378,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port B */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -507,37 +388,29 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************/ /* Selects error channels 1 and 2 */ - /**********************************/ i_PatternMask = (i_PatternMask | 0xC0); i_PatternPolarity = (i_PatternPolarity | 0xC0); i_PatternTransition = (i_PatternTransition | 0xC0); - /**********************************************/ /* Selects the polarity register of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternPolarity, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern transition register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternTransition, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern Mask register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + @@ -546,20 +419,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -569,23 +438,20 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); i_Event2Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if (data[1] == APCI1500_OR) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* elseif (data[1] == APCI1500_OR) */ } /* if(data[0]==2) */ @@ -594,31 +460,15 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Allows or disallows a port event | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -| data[0] :0 Start input event -| 1 Stop input event -| data[1] :No of port (1 or 2) -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Allows or disallows a port event + * + * data[0] 0 = Start input event, 1 = Stop input event + * data[1] Number of port (1 or 2) + */ +static int apci1500_di_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_Event1InterruptStatus = 0, i_Event2InterruptStatus = @@ -626,48 +476,30 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, switch (data[0]) { case START: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -680,185 +512,142 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 1; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[0] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[0] == 2) */ break; case STOP: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event1InterruptStatus = 0; } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 0; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[1] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[1] == 2) */ break; default: - printk("\nThe option of START/STOP logic does not exist\n"); + dev_warn(dev->hw_dev, + "The option of START/STOP logic does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -866,35 +655,17 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Initialisation | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Initialisation(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Return the status of the digital input + */ +static int apci1500_di_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_DummyRead = 0; - /******************/ /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -902,16 +673,12 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -943,9 +710,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -975,9 +740,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -992,9 +755,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1004,9 +765,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1016,9 +775,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1028,9 +785,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ @@ -1051,37 +806,15 @@ static int apci1500_di_insn_bits(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalOutputErrorInterrupt -| (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn -| *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures the digital output memory and the digital -| output error interrupt | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| data[0] :1:Memory on | -| 0:Memory off | -| data[1] :1 Enable the voltage error interrupt -| :0 Disable the voltage error interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the digital output memory and the digital output error interrupt + * + * data[1] 1 = Enable the voltage error interrupt + * 2 = Disable the voltage error interrupt + */ +static int apci1500_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; @@ -1090,31 +823,15 @@ static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *de } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To Write | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Writes port value to the selected port + */ +static int apci1500_do_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - static unsigned int ui_Temp = 0; + static unsigned int ui_Temp; unsigned int ui_Temp1; unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ @@ -1165,7 +882,9 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==0) */ @@ -1242,12 +961,15 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==1); */ else { - printk("\nSpecified functionality does not exist\n"); + dev_warn(dev->hw_dev, + "Specified functionality does not exist\n"); return -EINVAL; } /* if else data[3]==1) */ } /* if else data[3]==0) */ @@ -1256,57 +978,23 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device -| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status data[0] : 2 APCI1500_1_8_KHZ -| 1 APCI1500_3_6_KHZ | -| 0 APCI1500_115_KHZ -| data[1] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[2] : 0 Counter -| 1 Timer/Watchdog -| data[3] : This parameter has | -| two meanings. | -| - If the counter/timer | -| is used as a counter | -| the limit value of | -| the counter is given | -| | -| - If the counter/timer | -| is used as a timer, | -| the divider factor | -| for the output is | -| given. -| data[4] : 0 APCI1500_CONTINUOUS -| 1 APCI1500_SINGLE -| data[5] : 0 Software Trigger -| 1 Hardware Trigger -| -| data[6] :0 Software gate -| 1 Hardware gate -| data[7] :0 Interrupt Disable -| 1 Interrupt Enable -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Watchdog + * + * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ + * data[1] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[2] 0 = Counter, 1 = Timer/Watchdog + * data[3] This parameter has two meanings. If the counter/timer is used as + * a counter the limit value of the counter is given. If the counter/timer + * is used as a timer, the divider factor for the output is given. + * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE + * data[5] 0 = Software Trigger, 1 = Hardware Trigger + * data[6] 0 = Software gate, 1 = Hardware gate + * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable + */ +static int apci1500_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_TimerCounterMode, i_MasterConfiguration; @@ -1319,7 +1007,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[0]==0||data[0]==1||data[0]==2) */ else { if (data[0] != 3) { - printk("\nThe option for input clock selection does not exist\n"); + dev_warn(dev->hw_dev, + "The option for input clock selection does not exist\n"); return -EINVAL; } /* if(data[0]!=3) */ } /* elseif(data[0]==0||data[0]==1||data[0]==2) */ @@ -1335,7 +1024,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1348,139 +1038,110 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ i_TimerCounterMode = data[2] | data[4] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 1 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 1 and triggers timer/counter 1 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x40; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 1 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1496,7 +1157,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1509,7 +1171,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1522,7 +1185,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[5] = APCI1500_HARDWARE_TRIGGER; break; default: - printk("\nThis choice for software or hardware trigger does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware trigger does not exist\n"); return -EINVAL; } /* switch(data[5]) */ @@ -1535,140 +1199,111 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 2 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 2 and triggers timer/counter 2 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x20; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 2 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1684,7 +1319,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_WATCHDOG; break; default: - printk("\nThis choice is not a watchdog nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a watchdog nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1697,7 +1333,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1710,146 +1347,109 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ - /*****************************/ /* Test if used for watchdog */ - /*****************************/ if (data[2] == APCI1500_WATCHDOG) { - /*****************************/ /* - Enables the output line */ /* - Enables retrigger */ /* - Pulses output */ - /*****************************/ i_TimerCounterMode = data[2] | data[4] | 0x54; } /* if (data[2] == APCI1500_WATCHDOG) */ else { i_TimerCounterMode = data[2] | data[4] | data[6] | 7; } /* elseif (data[2] == APCI1500_WATCHDOG) */ - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of watchdog/counter 3 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables watchdog/counter 3 and triggers watchdog/counter 3 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x10; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************/ /* Test if COUNTER */ - /********************/ if (data[2] == APCI1500_COUNTER) { - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Disable the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Trigger the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1858,12 +1458,14 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1871,44 +1473,25 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, break; default: - printk("\nThe specified counter\timer option does not exist\n"); + dev_warn(dev->hw_dev, + "The specified counter/timer option does not exist\n"); + return -EINVAL; } /* switch(data[1]) */ i_CounterLogic = data[2]; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopTriggerTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, -| struct comedi_insn *insn,unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Start / Stop or trigger the timer counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[1] : 0 start -| 1 stop -| 2 Trigger -| data[2] : 0 Counter -| 1 Timer/Watchdog -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop or trigger the timer counter or Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[1] 0 = Start, 1 = Stop, 2 = Trigger + * data[2] 0 = Counter, 1 = Timer/Watchdog + */ +static int apci1500_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; @@ -1924,13 +1507,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 1 */ - /**************************/ i_TimerCounter1Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1939,20 +1518,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 1 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1965,23 +1541,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter1Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter1Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1990,13 +1560,15 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -2011,13 +1583,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 2 */ - /**************************/ i_TimerCounter2Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2026,20 +1594,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 2 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2051,23 +1616,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter2Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter2Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2076,12 +1635,14 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -2096,13 +1657,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts Watchdog/counter 3 */ - /**************************/ i_WatchdogCounter3Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2112,20 +1669,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device } /* if( i_WatchdogCounter3init==1) */ else { - printk("\nWatchdog/Counter3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog/Counter3 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop Watchdog/counter 3 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2140,23 +1694,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case 0: /* triggering counter 3 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_WatchdogCounter3Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_WatchdogCounter3Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2165,7 +1713,8 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "Counter3 not configured\n"); return -EINVAL; } break; @@ -2173,9 +1722,7 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device /* triggering Watchdog 3 */ if (i_WatchdogCounter3Init == 1) { - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2184,55 +1731,40 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdog 3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog 3 not configured\n"); return -EINVAL; } break; default: - printk("\nWrong choice of watchdog/counter3\n"); + dev_warn(dev->hw_dev, + "Wrong choice of watchdog/counter3\n"); return -EINVAL; } /* switch(data[2]) */ break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; default: - printk("\nThe specified choice for counter/watchdog/timer does not exist\n"); + dev_warn(dev->hw_dev, + "The specified choice for counter/watchdog/timer does not exist\n"); return -EINVAL; } /* switch(data[0]) */ return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadCounterTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + */ +static int apci1500_timer_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; @@ -2242,23 +1774,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/timer1 */ if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter1Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter1Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2266,9 +1792,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR1_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2285,7 +1809,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nTimer/Counter1 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter1 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter1Init==1) */ break; @@ -2293,23 +1818,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/timer2 */ if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter2Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2317,9 +1836,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR2_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2336,7 +1853,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nTimer/Counter2 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter2 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter2Init==1) */ break; @@ -2344,23 +1862,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/watchdog2 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_WatchdogCounter3Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2368,9 +1880,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR3_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2387,12 +1897,14 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdogCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "WatchdogCounter3 not configured\n"); return -EINVAL; } /* elseif( i_WatchdogCounter3Init==1) */ break; default: - printk("\nThe choice of timer/counter/watchdog does not exist\n"); + dev_warn(dev->hw_dev, + "The choice of timer/counter/watchdog does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -2400,31 +1912,15 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadInterruptMask | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read the interrupt mask | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | - - -+----------------------------------------------------------------------------+ -| Output Parameters : -- data[0]:The interrupt mask value data[1]:Channel no -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read the interrupt mask + * + * data[0] The interrupt mask value + * data[1] Channel Number + */ +static int apci1500_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { data[0] = i_InterruptMask; data[1] = i_InputChannel; @@ -2433,31 +1929,12 @@ static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigureInterrupt | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Configures the interrupt registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer | -| - -+----------------------------------------------------------------------------+ -| Output Parameters : -- -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the interrupt registers + */ +static int apci1500_do_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Status; @@ -2474,140 +1951,101 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, i_Constant = 0x00; } /* if{data[0]==0) */ else { - printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n"); + dev_warn(dev->hw_dev, + "The parameter passed to driver is in error for enabling the voltage interrupt\n"); return -EINVAL; } /* else if(data[0]==0) */ } /* elseif(data[0]==1) */ - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Writes the new configuration (APCI1500_OR) */ - /*********************************************/ i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************/ /* Authorises the interrupt on the board */ - /*****************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the pattern polarity register of port B */ - /***************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the pattern transition register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************************/ /* Selects the pattern mask register of port B */ - /***********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Enables the PCI interrupt */ - /*****************************/ outl(0x3000, devpriv->i_IobaseAmcc + 0x38); ui_Status = inl(devpriv->i_IobaseAmcc + 0x10); ui_Status = inl(devpriv->i_IobaseAmcc + 0x38); @@ -2616,24 +2054,7 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1500_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1500_Interrupt(int irq, void *d) +static void apci1500_interrupt(int irq, void *d) { struct comedi_device *dev = d; @@ -2642,44 +2063,28 @@ static void v_APCI1500_Interrupt(int irq, void *d) int i_RegValue = 0; i_InterruptMask = 0; - /***********************************/ /* Read the board interrupt status */ - /***********************************/ ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38); - /***************************************/ /* Test if board generated a interrupt */ - /***************************************/ if ((ui_InterruptStatus & 0x800000) == 0x800000) { - /************************/ /* Disable all Interrupt */ - /************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ /* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ /* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2693,9 +2098,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the interrupt vector register of port A */ - /***************************************************/ outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2711,45 +2114,32 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* elseif(i_Logic==APCI1500_OR_PRIORITY) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - printk("\n\n\n"); - /****************/ /* Reads port B */ - /****************/ i_RegValue = inb((unsigned int) devpriv->iobase + APCI1500_Z8536_PORT_B); i_RegValue = i_RegValue & 0xC0; - /**************************************/ /* Tests if this is an external error */ - /**************************************/ if (i_RegValue) { /* Disable the interrupt */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outl(0x0, devpriv->i_IobaseAmcc + 0x38); if (i_RegValue & 0x80) { @@ -2767,46 +2157,34 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if (i_RegValue) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 4; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2814,23 +2192,17 @@ static void v_APCI1500_Interrupt(int irq, void *d) i_InterruptMask = i_InterruptMask | 8; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2844,42 +2216,23 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if ((i_RegValue & 0x60) == 0x60) */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - /***********************/ /* Enable all Interrupts */ - /***********************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */ else { - printk("\nInterrupt from unknown source\n"); + dev_warn(dev->hw_dev, + "Interrupt from unknown source\n"); } /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */ return; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Reset(struct comedi_device *dev) +static int apci1500_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_DummyRead = 0; @@ -2898,9 +2251,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) i_TimerCounter2Enabled = 0; i_WatchdogCounter3Enabled = 0; - /******************/ /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2908,16 +2259,12 @@ static int i_APCI1500_Reset(struct comedi_device *dev) outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2949,9 +2296,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2981,9 +2326,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -2998,9 +2341,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3010,9 +2351,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3022,9 +2361,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3034,71 +2371,43 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* reset all the digital outputs */ outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); -/*******************************/ /* Disable the board interrupt */ -/*******************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 3*/ -/*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index e3cc429403c..0ba5385226a 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -1,74 +1,34 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1564 | Compiler : GCC | - | Module name : hwdrv_apci1564.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1564 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/********* Definitions for APCI-1564 card *****/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ + +#include "../addi_watchdog.h" #define APCI1564_ADDRESS_RANGE 128 -/* DIGITAL INPUT-OUTPUT DEFINE */ -/* Input defines */ -#define APCI1564_DIGITAL_IP 0x04 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE1 4 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE2 8 -#define APCI1564_DIGITAL_IP_IRQ 16 - -/* Output defines */ -#define APCI1564_DIGITAL_OP 0x18 -#define APCI1564_DIGITAL_OP_RW 0 -#define APCI1564_DIGITAL_OP_INTERRUPT 4 -#define APCI1564_DIGITAL_OP_IRQ 12 - /* Digital Input IRQ Function Selection */ #define ADDIDATA_OR 0 #define ADDIDATA_AND 1 -/* Digital Input Interrupt Status */ -#define APCI1564_DIGITAL_IP_INTERRUPT_STATUS 12 - -/* Digital Output Interrupt Status */ -#define APCI1564_DIGITAL_OP_INTERRUPT_STATUS 8 - /* Digital Input Interrupt Enable Disable. */ #define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4 #define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE 0xfffffffb @@ -80,143 +40,105 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY #define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xfffffffd /* TIMER COUNTER WATCHDOG DEFINES */ - #define ADDIDATA_TIMER 0 #define ADDIDATA_COUNTER 1 #define ADDIDATA_WATCHDOG 2 -#define APCI1564_DIGITAL_OP_WATCHDOG 0x28 -#define APCI1564_TIMER 0x48 -#define APCI1564_COUNTER1 0x0 -#define APCI1564_COUNTER2 0x20 -#define APCI1564_COUNTER3 0x40 -#define APCI1564_COUNTER4 0x60 -#define APCI1564_TCW_SYNC_ENABLEDISABLE 0 -#define APCI1564_TCW_RELOAD_VALUE 4 -#define APCI1564_TCW_TIMEBASE 8 -#define APCI1564_TCW_PROG 12 -#define APCI1564_TCW_TRIG_STATUS 16 -#define APCI1564_TCW_IRQ 20 -#define APCI1564_TCW_WARN_TIMEVAL 24 -#define APCI1564_TCW_WARN_TIMEBASE 28 +#define APCI1564_COUNTER1 0 +#define APCI1564_COUNTER2 1 +#define APCI1564_COUNTER3 2 +#define APCI1564_COUNTER4 3 + +/* + * devpriv->i_IobaseAmcc Register Map + */ +#define APCI1564_DI_REG 0x04 +#define APCI1564_DI_INT_MODE1_REG 0x08 +#define APCI1564_DI_INT_MODE2_REG 0x0c +#define APCI1564_DI_INT_STATUS_REG 0x10 +#define APCI1564_DI_IRQ_REG 0x14 +#define APCI1564_DO_REG 0x18 +#define APCI1564_DO_INT_CTRL_REG 0x1c +#define APCI1564_DO_INT_STATUS_REG 0x20 +#define APCI1564_DO_IRQ_REG 0x24 +#define APCI1564_WDOG_REG 0x28 +#define APCI1564_WDOG_RELOAD_REG 0x2c +#define APCI1564_WDOG_TIMEBASE_REG 0x30 +#define APCI1564_WDOG_CTRL_REG 0x34 +#define APCI1564_WDOG_STATUS_REG 0x38 +#define APCI1564_WDOG_IRQ_REG 0x3c +#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x40 +#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x44 +#define APCI1564_TIMER_REG 0x48 +#define APCI1564_TIMER_RELOAD_REG 0x4c +#define APCI1564_TIMER_TIMEBASE_REG 0x50 +#define APCI1564_TIMER_CTRL_REG 0x54 +#define APCI1564_TIMER_STATUS_REG 0x58 +#define APCI1564_TIMER_IRQ_REG 0x5c +#define APCI1564_TIMER_WARN_TIMEVAL_REG 0x60 +#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64 + +/* + * dev>iobase Register Map + */ +#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20)) +#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20)) +#define APCI1564_TCW_TIMEBASE_REG(x) (0x08 + ((x) * 0x20)) +#define APCI1564_TCW_CTRL_REG(x) (0x0c + ((x) * 0x20)) +#define APCI1564_TCW_STATUS_REG(x) (0x10 + ((x) * 0x20)) +#define APCI1564_TCW_IRQ_REG(x) (0x14 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20)) /* Global variables */ -static unsigned int ui_InterruptStatus_1564 = 0; +static unsigned int ui_InterruptStatus_1564; static unsigned int ui_InterruptData, ui_Type; /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures the digital input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 1 Enable Digital Input Interrupt | -| 0 Disable Digital Input Interrupt | -| data[1] : 0 ADDIDATA Interrupt OR LOGIC | -| : 1 ADDIDATA Interrupt AND LOGIC | -| data[2] : Interrupt mask for the mode 1 | -| data[3] : Interrupt mask for the mode 2 | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the digital input Subdevice + * + * data[0] 1 = Enable interrupt, 0 = Disable interrupt + * data[1] 0 = ADDIDATA Interrupt OR LOGIC, 1 = ADDIDATA Interrupt AND LOGIC + * data[2] Interrupt mask for the mode 1 + * data[3] Interrupt mask for the mode 2 + */ +static int apci1564_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; devpriv->tsk_Current = current; - /*******************************/ + /* Set the digital input logic */ - /*******************************/ if (data[0] == ADDIDATA_ENABLE) { data[2] = data[2] << 4; data[3] = data[3] << 4; - outl(data[2], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - if (data[1] == ADDIDATA_OR) { - outl(0x4, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* if (data[1] == ADDIDATA_OR) */ - else { - outl(0x6, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[1] == ADDIDATA_OR) */ - } /* if (data[0] == ADDIDATA_ENABLE) */ - else { - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[0] == ADDIDATA_ENABLE) */ - - return insn->n; -} - -static int apci1564_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); + outl(data[2], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + if (data[1] == ADDIDATA_OR) + outl(0x4, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + else + outl(0x6, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } else { + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[1] : 1 Enable VCC Interrupt | -| 0 Disable VCC Interrupt | -| data[2] : 1 Enable CC Interrupt | -| 0 Disable CC Interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Digital Output Subdevice. + * + * data[1] 0 = Disable VCC Interrupt, 1 = Enable VCC Interrupt + * data[2] 0 = Disable CC Interrupt, 1 = Enable CC Interrupt + */ +static int apci1564_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command = 0; @@ -225,95 +147,46 @@ static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } /* if ((data[0]!=0) && (data[0]!=1)) */ - if (data[0]) { + } + + if (data[0]) devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0]) */ - else { + else devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0]) */ - if (data[1] == ADDIDATA_ENABLE) { + + if (data[1] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x1; - } /* if (data[1] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFE; - } /* else if (data[1] == ADDIDATA_ENABLE) */ - if (data[2] == ADDIDATA_ENABLE) { + + if (data[2] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x2; - } /* if (data[2] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFD; - } /* else if (data[2] == ADDIDATA_ENABLE) */ - outl(ul_Command, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); - ui_InterruptData = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); + + outl(ul_Command, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + ui_InterruptData = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); devpriv->tsk_Current = current; return insn->n; } -static int apci1564_do_insn_bits(struct comedi_device *dev, +/* + * Configures The Timer, Counter or Watchdog + * + * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt + * data[2] Time Unit + * data[3] Reload Value + * data[4] Timer Mode + * data[5] Timer Counter Watchdog Number + * data[6] Counter Direction + */ +static int apci1564_timer_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - - outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - } - - data[1] = s->state; - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Counter | -| 2 Configure As Watchdog | -| data[1] : 1 Enable Interrupt | -| 0 Disable Interrupt | -| data[2] : Time Unit | -| data[3] : Reload Value | -| data[4] : Timer Mode | -| data[5] : Timer Counter Watchdog Number| - data[6] : Counter Direction -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; devpriv->tsk_Current = current; @@ -321,89 +194,59 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; /* Disable the watchdog */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); /* Loading the Reload value */ - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_RELOAD_VALUE); - } /* if (data[0]==ADDIDATA_WATCHDOG) */ - else if (data[0] == ADDIDATA_TIMER) { + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG); + } else if (data[0] == ADDIDATA_TIMER) { /* First Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Stop The Timer */ + /* Stop The Timer */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { - outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ); - outl(0x0, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_IRQ); + /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ + outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_IRQ_REG); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_IRQ); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_IRQ); - } /* if (data[1]==1) */ - else { - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* disable Timer interrupt */ - } /* else if (data[1]==1) */ + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)); + } else { + /* disable Timer interrupt */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } /* Loading Timebase */ - - outl(data[2], - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_TIMEBASE); + outl(data[2], devpriv->i_IobaseAmcc + APCI1564_TIMER_TIMEBASE_REG); /* Loading the Reload value */ - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_RELOAD_VALUE); + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG); - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - ul_Command1 = - (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* mode 2 */ - } /* else if (data[0]==ADDIDATA_TIMER) */ - else if (data[0] == ADDIDATA_COUNTER) { + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; + /* mode 2 */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } else if (data[0] == ADDIDATA_COUNTER) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; devpriv->b_ModeSelectRegister = data[5]; /* First Stop The Counter */ - ul_Command1 = - inl(devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); /* Stop The Timer */ + /* Stop The Timer */ + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); - /************************/ /* Set the reload value */ - /************************/ - outl(data[3], - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_RELOAD_VALUE); + outl(data[3], dev->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1)); - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -411,65 +254,36 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Disable the timer mode */ /* - Enable the counter mode */ - /******************************/ + ul_Command1 = (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | (unsigned int) ((unsigned int) data[4] << 16UL); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); /* Enable or Disable Interrupt */ ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); - /*****************************/ /* Set the Up/Down selection */ - /*****************************/ ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); - } /* else if (data[0]==ADDIDATA_COUNTER) */ - else { - printk(" Invalid subdevice."); - } /* else if (data[0]==ADDIDATA_WATCHDOG) */ + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + } else { + dev_err(dev->class_dev, "Invalid subdevice.\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_StartStopWriteTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : 1 Start | -| 0 Stop | -| 2 Trigger | -| Clear (Only Counter) | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop The Selected Timer, Counter or Watchdog + * + * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter) + */ +static int apci1564_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -477,203 +291,121 @@ static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *d if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { switch (data[1]) { case 0: /* stop the watchdog */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); /* disable the watchdog */ + /* disable the watchdog */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 1: /* start the watchdog */ - outl(0x0001, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0001, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 2: /* Software trigger */ - outl(0x0201, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0201, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; default: - printk("\nSpecified functionality does not exist\n"); + dev_err(dev->class_dev, "Specified functionality does not exist.\n"); return -EINVAL; - } /* switch (data[1]) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Timer */ - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* if (data[1]==1) */ - else if (data[1] == 0) { + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } else if (data[1] == 0) { /* Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* else if(data[1]==0) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_PROG); + inl(dev->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); if (data[1] == 1) { /* Start the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - } /* if (data[1] == 1) */ - else if (data[1] == 0) { + } else if (data[1] == 0) { /* Stops the Counter subdevice */ ul_Command1 = 0; - } /* else if (data[1] == 0) */ - else if (data[1] == 2) { + } else if (data[1] == 2) { /* Clears the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; - } /* else if (data[1] == 3) */ - outl(ul_Command1, - devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_PROG); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ + } + outl(ul_Command1, dev->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | - -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Selected Timer, Counter or Watchdog + */ +static int apci1564_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { /* Stores the status of the Watchdog */ - data[0] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_TRIG_STATUS) & 0x1; - data[1] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_STATUS_REG) & 0x1; + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { /* Stores the status of the Timer */ - data[0] = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_TRIG_STATUS) & 0x1; + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_STATUS_REG) & 0x1; /* Stores the Actual value of the Timer */ - data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { /* Read the Counter Actual Value. */ data[0] = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + - APCI1564_TCW_SYNC_ENABLEDISABLE); + inl(dev->iobase + + APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1)); ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_TRIG_STATUS); + inl(dev->iobase + + APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1)); - /***********************************/ /* Get the software trigger status */ - /***********************************/ data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); - /***********************************/ /* Get the hardware trigger status */ - /***********************************/ data[2] = (unsigned char) ((ul_Command1 >> 2) & 1); - /*********************************/ /* Get the software clear status */ - /*********************************/ data[3] = (unsigned char) ((ul_Command1 >> 3) & 1); - /***************************/ /* Get the overflow status */ - /***************************/ data[4] = (unsigned char) ((ul_Command1 >> 0) & 1); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ - else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) + } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG) && (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) { - printk("\n Invalid Subdevice !!!\n"); - } /* else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) */ + dev_err(dev->class_dev, "Invalid Subdevice!\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadInterruptStatus | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task :Reads the interrupt status register | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Reads the interrupt status register + */ +static int apci1564_do_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { *data = ui_Type; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1564_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler for the interruptible digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1564_Interrupt(int irq, void *d) + * Interrupt handler for the interruptible digital inputs + */ +static void apci1564_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -682,79 +414,63 @@ static void v_APCI1564_Interrupt(int irq, void *d) unsigned int ui_C1, ui_C2, ui_C3, ui_C4; unsigned int ul_Command2 = 0; - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ) & 0x01; - ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ) & 0x01; - ui_Timer = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_IRQ) & 0x01; - ui_C1 = inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ) & 0x1; - ui_C2 = inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ) & 0x1; - ui_C3 = inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_IRQ) & 0x1; - ui_C4 = inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_IRQ) & 0x1; + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG) & 0x01; + ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01; + ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01; + ui_C1 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1; + ui_C2 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1; + ui_C3 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1; + ui_C4 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1; if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0 && ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) { - printk("\nInterrupt from unknown source\n"); - } /* if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) */ + dev_err(dev->class_dev, "Interrupt from unknown source.\n"); + } if (ui_DI == 1) { - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); ui_InterruptStatus_1564 = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_STATUS); + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0; - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); /* enable the interrupt */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + /* enable the interrupt */ + outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); return; } if (ui_DO == 1) { - /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ - ui_Type = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; + /* Check for Digital Output interrupt Type */ + /* 1: VCC interrupt */ + /* 2: CC interrupt */ + ui_Type = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_STATUS_REG) & 0x3; /* Disable the Interrupt */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); /* Sends signal to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - - } /* if (ui_DO) */ + } if (ui_Timer == 1) { devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (devpriv->b_TimerSelectMode) { /* Disable Timer Interrupt */ - ul_Command2 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command2 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Timer Interrupt */ - outl(ul_Command2, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + outl(ul_Command2, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); } - }/* if (ui_Timer == 1) */ - + } if (ui_C1 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -762,21 +478,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); } - } /* if (ui_C1 == 1) */ + } if (ui_C2 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -784,21 +497,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); } - } /* if ((ui_C2 == 1) */ + } if (ui_C3 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -806,21 +516,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); } - } /* if ((ui_C3 == 1) */ + } if (ui_C4 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -828,60 +535,17 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); } - } /* if (ui_C4 == 1) */ + } return; } - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1564_Reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); /* disable the interrupts */ - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - devpriv->b_DigitalOutputRegister = 0; - ui_Type = 0; - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP); /* Resets the output channels */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_RELOAD_VALUE); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); - - outl(0x0, devpriv->iobase + APCI1564_COUNTER1 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER2 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER3 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER4 + APCI1564_TCW_PROG); - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index a89e505c8a3..764c8f17f8f 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -40,6 +40,8 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY +----------+-----------+------------------------------------------------+ */ +#include <linux/delay.h> + /* * ADDON RELATED ADDITIONS */ @@ -246,10 +248,10 @@ static const struct comedi_lrange range_apci3120_ao = { +----------------------------------------------------------------------------+ */ -static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -302,11 +304,11 @@ static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, * If the last argument of function "check"is 1 then it only checks * the channel list is ok or not. */ -static int i_APCI3120_SetupChannelList(struct comedi_device *dev, - struct comedi_subdevice *s, - int n_chan, - unsigned int *chanlist, - char check) +static int apci3120_setup_chan_list(struct comedi_device *dev, + struct comedi_subdevice *s, + int n_chan, + unsigned int *chanlist, + char check) { struct addi_private *devpriv = dev->private; unsigned int i; /* , differencial=0, bipolar=0; */ @@ -356,10 +358,10 @@ static int i_APCI3120_SetupChannelList(struct comedi_device *dev, * as per configured if no conversion time is set uses default * conversion time 10 microsec. */ -static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -415,10 +417,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, inw(devpriv->iobase + APCI3120_RESET_FIFO); /* Initialize the sequence array */ - - /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */ - - if (!i_APCI3120_SetupChannelList(dev, s, 1, + if (!apci3120_setup_chan_list(dev, s, 1, &insn->chanspec, 0)) return -EINVAL; @@ -510,7 +509,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - if (!i_APCI3120_SetupChannelList(dev, s, + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, devpriv->ui_AiChannelList, 0)) return -EINVAL; @@ -604,17 +603,16 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, } -static int i_APCI3120_Reset(struct comedi_device *dev) +static int apci3120_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; unsigned int i; unsigned short us_TmpValue; - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + devpriv->ai_running = 0; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; devpriv->b_InterruptMode = APCI3120_EOC_MODE; devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */ - devpriv->b_OutputMemoryStatus = 0; /* variables used in timer subdevice */ devpriv->b_Timer2Mode = 0; @@ -661,7 +659,7 @@ static int i_APCI3120_Reset(struct comedi_device *dev) return 0; } -static int i_APCI3120_ExttrigEnable(struct comedi_device *dev) +static int apci3120_exttrig_enable(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; @@ -670,7 +668,7 @@ static int i_APCI3120_ExttrigEnable(struct comedi_device *dev) return 0; } -static int i_APCI3120_ExttrigDisable(struct comedi_device *dev) +static int apci3120_exttrig_disable(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; @@ -679,8 +677,8 @@ static int i_APCI3120_ExttrigDisable(struct comedi_device *dev) return 0; } -static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; @@ -703,7 +701,7 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */ /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->us_OutputRegister = 0; /* stop counters */ @@ -721,21 +719,19 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, inw(dev->iobase + APCI3120_RD_STATUS); devpriv->ui_AiActualScan = 0; s->async->cur_chan = 0; - devpriv->b_AiContinuous = 0; devpriv->ui_DmaActualBuffer = 0; - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + devpriv->ai_running = 0; devpriv->b_InterruptMode = APCI3120_EOC_MODE; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } -static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3120_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - const struct addi_board *this_board = comedi_board(dev); int err = 0; /* Step 1 : check if triggers are trivially valid */ @@ -768,20 +764,16 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000); - if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */ - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->convert_arg) - err |= cfc_check_trigger_arg_min( - &cmd->convert_arg, 10000); - } else { + if (cmd->scan_begin_src == TRIG_TIMER) { + if (cmd->convert_arg) err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - 10000); - } + 10000); + } else { + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); } err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, - this_board->i_AiChannelList); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); @@ -793,15 +785,10 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->convert_src == TRIG_TIMER) { - - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } + if (cmd->scan_begin_src == TRIG_TIMER && + cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) { + cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg; + err |= -EINVAL; } if (err) @@ -816,22 +803,19 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, * If DMA is configured does DMA initialization otherwise does the * acquisition with EOS interrupt. */ -static int i_APCI3120_CyclicAnalogInput(int mode, - struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_cyclic_ai(int mode, + struct comedi_device *dev, + struct comedi_subdevice *s) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned char b_Tmp; unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 = 0, dmalen1 = 0, ui_TimerValue2 = 0, ui_TimerValue0, ui_ConvertTiming; unsigned short us_TmpValue; - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */ - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - /*******************/ /* Resets the FIFO */ /*******************/ @@ -841,12 +825,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /* inw(dev->iobase+APCI3120_RD_STATUS); */ /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - /***************************/ - /* Acquisition initialized */ - /***************************/ - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE; - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ + devpriv->ai_running = 1; /* clear software registers */ devpriv->b_TimerSelectMode = 0; @@ -893,17 +872,17 @@ static int i_APCI3120_CyclicAnalogInput(int mode, devpriv->ui_DmaActualBuffer = 0; /* value for timer2 minus -2 has to be done .....dunno y?? */ - ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2; - ui_ConvertTiming = devpriv->ui_AiTimer0; + ui_TimerValue2 = cmd->stop_arg - 2; + ui_ConvertTiming = cmd->convert_arg; if (mode == 2) - ui_DelayTiming = devpriv->ui_AiTimer1; + ui_DelayTiming = cmd->scan_begin_arg; /**********************************/ /* Initializes the sequence array */ /**********************************/ - if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels, - devpriv->pui_AiChannelList, 0)) + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, + cmd->chanlist, 0)) return -EINVAL; us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); @@ -955,7 +934,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /*** EL241003 End ******************************************************************************/ if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) - i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */ + apci3120_exttrig_enable(dev); /* activate EXT trigger */ switch (mode) { case 1: /* init timer0 in mode 2 */ @@ -1040,7 +1019,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - if (!devpriv->b_AiContinuous) { + if (cmd->stop_src == TRIG_COUNT) { /* * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to * disable it (Set Bit D14 to 0) @@ -1108,6 +1087,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, } } else { /* If DMA Enabled */ + unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short); /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ /* inw(dev->iobase+0); reset EOC bit */ @@ -1126,37 +1106,38 @@ static int i_APCI3120_CyclicAnalogInput(int mode, dmalen0 = devpriv->ui_DmaBufferSize[0]; dmalen1 = devpriv->ui_DmaBufferSize[1]; - if (!devpriv->b_AiContinuous) { - - if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */ - dmalen0 = - devpriv->ui_AiNbrofScans * - devpriv->ui_AiScanLength * 2; - } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */ - dmalen1 = - devpriv->ui_AiNbrofScans * - devpriv->ui_AiScanLength * 2 - dmalen0; + if (cmd->stop_src == TRIG_COUNT) { + /* + * Must we fill full first buffer? And must we fill + * full second buffer when first is once filled? + */ + if (dmalen0 > (cmd->stop_arg * scan_bytes)) { + dmalen0 = cmd->stop_arg * scan_bytes; + } else if (dmalen1 > (cmd->stop_arg * scan_bytes - + dmalen0)) + dmalen1 = cmd->stop_arg * scan_bytes - + dmalen0; } - if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) { + if (cmd->flags & TRIG_WAKE_EOS) { /* don't we want wake up every scan? */ - if (dmalen0 > (devpriv->ui_AiScanLength * 2)) { - dmalen0 = devpriv->ui_AiScanLength * 2; - if (devpriv->ui_AiScanLength & 1) + if (dmalen0 > scan_bytes) { + dmalen0 = scan_bytes; + if (cmd->scan_end_arg & 1) dmalen0 += 2; } - if (dmalen1 > (devpriv->ui_AiScanLength * 2)) { - dmalen1 = devpriv->ui_AiScanLength * 2; - if (devpriv->ui_AiScanLength & 1) + if (dmalen1 > scan_bytes) { + dmalen1 = scan_bytes; + if (cmd->scan_end_arg & 1) dmalen1 -= 2; if (dmalen1 < 4) dmalen1 = 4; } } else { /* isn't output buff smaller that our DMA buff? */ - if (dmalen0 > (devpriv->ui_AiDataLength)) - dmalen0 = devpriv->ui_AiDataLength; - if (dmalen1 > (devpriv->ui_AiDataLength)) - dmalen1 = devpriv->ui_AiDataLength; + if (dmalen0 > s->async->prealloc_bufsz) + dmalen0 = s->async->prealloc_bufsz; + if (dmalen1 > s->async->prealloc_bufsz) + dmalen1 = s->async->prealloc_bufsz; } devpriv->ui_DmaBufferUsesize[0] = dmalen0; devpriv->ui_DmaBufferUsesize[1] = dmalen1; @@ -1294,8 +1275,8 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ } - if ((devpriv->us_UseDma == APCI3120_DISABLE) - && !devpriv->b_AiContinuous) { + if (devpriv->us_UseDma == APCI3120_DISABLE && + cmd->stop_src == TRIG_COUNT) { /* set gate 2 to start conversion */ devpriv->us_OutputRegister = devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2; @@ -1331,57 +1312,24 @@ static int i_APCI3120_CyclicAnalogInput(int mode, * Does asynchronous acquisition. * Determines the mode 1 or 2. */ -static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; /* loading private structure with cmd structure inputs */ - devpriv->ui_AiFlags = cmd->flags; devpriv->ui_AiNbrofChannels = cmd->chanlist_len; - devpriv->ui_AiScanLength = cmd->scan_end_arg; - devpriv->pui_AiChannelList = cmd->chanlist; - - /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */ - devpriv->ui_AiDataLength = s->async->prealloc_bufsz; - - if (cmd->stop_src == TRIG_COUNT) - devpriv->ui_AiNbrofScans = cmd->stop_arg; - else - devpriv->ui_AiNbrofScans = 0; - - devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */ - devpriv->ui_AiTimer1 = 0; - if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1)) - devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */ - /* stopped using cancel */ if (cmd->start_src == TRIG_EXT) devpriv->b_ExttrigEnable = APCI3120_ENABLE; else devpriv->b_ExttrigEnable = APCI3120_DISABLE; - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* mode 1 or 3 */ - if (cmd->convert_src == TRIG_TIMER) { - /* mode 1 */ - - devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ - /* return this_board->ai_cmd(1,dev,s); */ - return i_APCI3120_CyclicAnalogInput(1, dev, s); - } - - } - if ((cmd->scan_begin_src == TRIG_TIMER) - && (cmd->convert_src == TRIG_TIMER)) { - /* mode 2 */ - devpriv->ui_AiTimer1 = cmd->scan_begin_arg; - devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ - /* return this_board->ai_cmd(2,dev,s); */ - return i_APCI3120_CyclicAnalogInput(2, dev, s); - } - return -1; + if (cmd->scan_begin_src == TRIG_FOLLOW) + return apci3120_cyclic_ai(1, dev, s); + else /* TRIG_TIMER */ + return apci3120_cyclic_ai(2, dev, s); } /* @@ -1389,15 +1337,16 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, */ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { struct addi_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; devpriv->ui_AiActualScan += - (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength; + (s->async->cur_chan + num_samples) / cmd->scan_end_arg; s->async->cur_chan += num_samples; - s->async->cur_chan %= devpriv->ui_AiScanLength; + s->async->cur_chan %= cmd->scan_end_arg; cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); } @@ -1408,11 +1357,12 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, * For continuous DMA it reinitializes the DMA operation. * For single mode DMA it stop the acquisition. */ -static void v_APCI3120_InterruptDma(int irq, void *d) +static void apci3120_interrupt_dma(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int next_dma_buf, samplesinbuf; unsigned long low_word, high_word, var; unsigned int ui_Tmp; @@ -1427,9 +1377,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) } if (samplesinbuf & 1) { comedi_error(dev, "Odd count of bytes in DMA ring!"); - i_APCI3120_StopCyclicAcquisition(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; - + apci3120_cancel(dev, s); return; } samplesinbuf = samplesinbuf >> 1; /* number of received samples */ @@ -1490,16 +1438,15 @@ static void v_APCI3120_InterruptDma(int irq, void *d) devpriv->ul_DmaBufferVirtual[devpriv-> ui_DmaActualBuffer], samplesinbuf); - if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) { + if (!(cmd->flags & TRIG_WAKE_EOS)) { s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); } } - if (!devpriv->b_AiContinuous) - if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { + if (cmd->stop_src == TRIG_COUNT) + if (devpriv->ui_AiActualScan >= cmd->stop_arg) { /* all data sampled */ - i_APCI3120_StopCyclicAcquisition(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + apci3120_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); return; @@ -1563,19 +1510,17 @@ static void v_APCI3120_InterruptDma(int irq, void *d) * This function handles EOS interrupt. * This function copies the acquired data(from FIFO) to Comedi buffer. */ -static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) +static int apci3120_interrupt_handle_eos(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; int n_chan, i; - struct comedi_subdevice *s = &dev->subdevices[0]; int err = 1; n_chan = devpriv->ui_AiNbrofChannels; - s->async->events = 0; - for (i = 0; i < n_chan; i++) - err &= comedi_buf_put(s->async, inw(dev->iobase + 0)); + err &= comedi_buf_put(s, inw(dev->iobase + 0)); s->async->events |= COMEDI_CB_EOS; @@ -1587,15 +1532,15 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) return 0; } -static void v_APCI3120_Interrupt(int irq, void *d) +static void apci3120_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; unsigned short int_daq; unsigned int int_amcc, ui_Check, i; unsigned short us_TmpValue; unsigned char b_DummyRead; - struct comedi_subdevice *s = &dev->subdevices[0]; ui_Check = 1; @@ -1613,7 +1558,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->b_ExttrigEnable = APCI3120_DISABLE; } /* clear the timer 2 interrupt */ @@ -1651,9 +1596,9 @@ static void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */ - if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { + if (devpriv->ai_running) { ui_Check = 0; - i_APCI3120_InterruptHandleEos(dev); + apci3120_interrupt_handle_eos(dev); devpriv->ui_AiActualScan++; devpriv->b_ModeSelectRegister = devpriv-> @@ -1693,8 +1638,6 @@ static void v_APCI3120_Interrupt(int irq, void *d) switch (devpriv->b_Timer2Mode) { case APCI3120_COUNTER: - - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; @@ -1709,8 +1652,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) dev->iobase + APCI3120_WR_ADDRESS); /* stop timer 0 and timer 1 */ - i_APCI3120_StopCyclicAcquisition(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + apci3120_cancel(dev, s); /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ s->async->events |= COMEDI_CB_EOA; @@ -1749,7 +1691,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) } if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) { - if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { + if (devpriv->ai_running) { /****************************/ /* Clear Timer Write TC int */ @@ -1763,7 +1705,8 @@ static void v_APCI3120_Interrupt(int irq, void *d) /* Clears the timer status register */ /************************************/ inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - v_APCI3120_InterruptDma(irq, d); /* do some data transfer */ + /* do some data transfer */ + apci3120_interrupt_dma(irq, d); } else { /* Stops the Timer */ outw(devpriv-> @@ -1785,7 +1728,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) * data[1] = Timer constant * data[2] = Timer2 interrupt (1)enable or(0) disable */ -static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, +static int apci3120_config_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1930,7 +1873,7 @@ static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, * = 1 Timer * = 2 Watch dog */ -static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, +static int apci3120_write_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -2102,7 +2045,7 @@ static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, * for watchdog: data[0] = 0 (still running) * = 1 (run down) */ -static int i_APCI3120_InsnReadTimer(struct comedi_device *dev, +static int apci3120_read_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -2173,29 +2116,24 @@ static int apci3120_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - unsigned int val; - /* The do channels are bits 7:4 of the do register */ - val = devpriv->b_DigitalOutputRegister >> 4; - if (mask) { - val &= ~mask; - val |= (bits & mask); - devpriv->b_DigitalOutputRegister = val << 4; + if (comedi_dio_update_state(s, data)) { + /* The do channels are bits 7:4 of the do register */ + devpriv->b_DigitalOutputRegister = s->state << 4; - outb(val << 4, devpriv->iobase + APCI3120_DIGITAL_OUTPUT); + outb(devpriv->b_DigitalOutputRegister, + devpriv->iobase + APCI3120_DIGITAL_OUTPUT); } - data[1] = val; + data[1] = s->state; return insn->n; } -static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Range, ui_Channel; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 32dce0329fd..f540394d17b 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -623,16 +623,11 @@ static int apci3200_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; s->state = inl(devpriv->i_IobaseAddon) & 0xf; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, devpriv->i_IobaseAddon); - } data[1] = s->state; @@ -1273,7 +1268,7 @@ static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, return 0; } -static int i_APCI3200_Reset(struct comedi_device *dev) +static int apci3200_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_Temp; @@ -1327,10 +1322,10 @@ static int i_APCI3200_Reset(struct comedi_device *dev) * data[7] : Channel current source from eeprom * data[8] : Channle gain factor from eeprom */ -static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { unsigned int ui_DummyValue = 0; int i_ConvertCJCCalibration; @@ -1341,7 +1336,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, if (s_BoardInfos[dev->minor].i_Initialised == 0) /* END JK 06.07.04: Management of sevrals boards */ { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ @@ -1591,7 +1586,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, break; default: printk("\nThe parameters passed are in error\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* switch(insn->unused[0]) */ @@ -1631,10 +1626,10 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, * = 2 RTD 3 wire connection * = 3 RTD 4 wire connection */ -static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Config = 0, ul_Temp = 0; @@ -1975,7 +1970,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, } /* switch(data[11]) */ } /* elseif(data[12]==0 || data[12]==1) */ if (i_err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_ScanType!=1) */ @@ -2084,7 +2079,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, /* END JK 06.07.04: Management of sevrals boards */ insn->unused[0] = 0; - i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy); + apci3200_ai_read(dev, s, insn, &ui_Dummy); } return insn->n; @@ -2100,10 +2095,10 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, * data[1] : calibration offset * data[2] : calibration gain */ -static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_bits_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; @@ -2112,12 +2107,12 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, /* if(i_Initialised==0) */ if (s_BoardInfos[dev->minor].i_Initialised == 0) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ if (data[0] != 0 && data[0] != 1) { printk("\nError in selection of functionality\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(data[0]!=0 && data[0]!=1) */ @@ -2207,18 +2202,18 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, return insn->n; } -static int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return insn->n; } -static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3200_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; @@ -2226,12 +2221,11 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, unsigned int ui_ConvertTimeBase = 0; unsigned int ui_DelayTime = 0; unsigned int ui_DelayTimeBase = 0; - int i_Triggermode = 0; - int i_TriggerEdge = 0; int i_NbrOfChannel = 0; int i_Cpt = 0; double d_ConversionTimeForAllChannels = 0.0; double d_SCANTimeNewUnit = 0.0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -2246,7 +2240,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, err |= -EINVAL; if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 1; } @@ -2258,23 +2252,37 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, /* Step 2b : and mutually compatible */ - if (cmd->start_src == TRIG_EXT) { - i_TriggerEdge = cmd->start_arg & 0xFFFF; - i_Triggermode = cmd->start_arg >> 16; - if (i_TriggerEdge < 1 || i_TriggerEdge > 3) { - err++; - printk("\nThe trigger edge selection is in error\n"); + if (err) { + apci3200_reset(dev); + return 2; + } + + /* Step 3: check if arguments are trivially valid */ + + switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* validate the trigger edge selection */ + arg = cmd->start_arg & 0xffff; + if (arg < 1 || arg > 3) { + cmd->start_arg &= ~0xffff; + cmd->start_arg |= 1; + err |= -EINVAL; } - if (i_Triggermode != 2) { - err++; - printk("\nThe trigger mode selection is in error\n"); + /* validate the trigger mode selection */ + arg = cmd->start_arg >> 16; + if (arg != 2) { + cmd->start_arg &= ~(0xffff << 16); + cmd->start_arg |= (2 << 16); + err |= -EINVAL; } + break; } - if (err) { - i_APCI3200_Reset(dev); - return 2; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + /* i_FirstChannel=cmd->chanlist[0]; */ s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0]; /* i_LastChannel=cmd->chanlist[1]; */ @@ -2313,7 +2321,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, printk("\nThe Delay time value is in error\n"); } if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 3; } fpu_begin(); @@ -2371,15 +2379,15 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 4; } return 0; } -static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3200_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; @@ -2415,8 +2423,8 @@ static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, * Does asynchronous acquisition * Determines the mode 1 or 2. */ -static int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3200_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -2595,8 +2603,8 @@ static int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; unsigned int ui_StatusRegister = 0; - struct comedi_subdevice *s = &dev->subdevices[0]; /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /* comedi_async *async = s->async; */ @@ -2624,7 +2632,6 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /* This value is not used */ /* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */ - s->async->events = 0; /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /*************************************/ @@ -2695,8 +2702,7 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) s->async->events |= COMEDI_CB_EOS; /* Test if enougth memory is available and allocate it for 7 values */ - /* n = comedi_buf_write_alloc(s->async, 7*sizeof(unsigned int)); */ - n = comedi_buf_write_alloc(s->async, + n = comedi_buf_write_alloc(s, (7 + 12) * sizeof(unsigned int)); /* If not enough memory available, event is set to Comedi Buffer Error */ @@ -2705,12 +2711,12 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) s->async->events |= COMEDI_CB_ERROR; } /* Write all 7 scan values in the comedi buffer */ - comedi_buf_memcpy_to(s->async, 0, + comedi_buf_memcpy_to(s, 0, (unsigned int *) s_BoardInfos[dev->minor]. ui_ScanValueArray, (7 + 12) * sizeof(unsigned int)); /* Update comedi buffer pinters indexes */ - comedi_buf_write_free(s->async, + comedi_buf_write_free(s, (7 + 12) * sizeof(unsigned int)); /* Send events */ @@ -2735,7 +2741,7 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) return 0; } -static void v_APCI3200_Interrupt(int irq, void *d) +static void apci3200_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index ebc1534a8df..e82c3fcd048 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -16,10 +16,10 @@ * data[2] : Time Unit * data[3] : Reload Value */ -static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_config_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -86,10 +86,10 @@ static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, * 0 Stop * 2 Trigger */ -static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_write_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -102,11 +102,7 @@ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *d ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Watchdog */ outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); - } - - else if (data[1] == 0) /* Stop The Watchdog */ - { - /* Stop The Watchdog */ + } else if (data[1] == 0) { /* Stop The Watchdog */ ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); @@ -153,10 +149,10 @@ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *d * 2 Watchdog * data[1] : Timer Counter Watchdog Number */ -static int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_read_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c index 43c2c10a7c3..4da9db35b8e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -1,3 +1,4 @@ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -26,13 +27,13 @@ static const struct addi_board apci035_boardtypes[] = { .i_Timer = 1, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI035_Interrupt, - .reset = i_APCI035_Reset, - .ai_config = i_APCI035_ConfigAnalogInput, - .ai_read = i_APCI035_ReadAnalogInput, - .timer_config = i_APCI035_ConfigTimerWatchdog, - .timer_write = i_APCI035_StartStopWriteTimerWatchdog, - .timer_read = i_APCI035_ReadTimerWatchdog, + .interrupt = apci035_interrupt, + .reset = apci035_reset, + .ai_config = apci035_ai_config, + .ai_read = apci035_ai_read, + .timer_config = apci035_timer_config, + .timer_write = apci035_timer_write, + .timer_read = apci035_timer_read, }, }; @@ -57,7 +58,7 @@ static int apci035_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci035_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci035_pci_table) = { +static const struct pci_device_id apci035_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x0300) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 8a93542faed..1b2e7c040c9 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -22,6 +22,7 @@ * more details. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -197,7 +198,7 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev, 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, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -261,7 +262,7 @@ static irqreturn_t apci1032_interrupt(int irq, void *d) outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG); s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff; - comedi_buf_put(s->async, s->state); + comedi_buf_put(s, s->state); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); @@ -289,10 +290,9 @@ static int apci1032_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -325,13 +325,14 @@ static int apci1032_auto_attach(struct comedi_device *dev, s = &dev->subdevices[1]; if (dev->irq) { dev->read_subdev = s; - s->type = COMEDI_SUBD_DI | SDF_CMD_READ; - s->subdev_flags = SDF_READABLE; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; s->n_chan = 1; s->maxdata = 1; s->range_table = &range_digital; s->insn_config = apci1032_cos_insn_config; s->insn_bits = apci1032_cos_insn_bits; + s->len_chanlist = 1; s->do_cmdtest = apci1032_cos_cmdtest; s->do_cmd = apci1032_cos_cmd; s->cancel = apci1032_cos_cancel; @@ -364,7 +365,7 @@ static int apci1032_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1032_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci1032_pci_table) = { +static const struct pci_device_id apci1032_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1003) }, { 0 } }; @@ -379,5 +380,5 @@ static struct pci_driver apci1032_pci_driver = { module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1032, 32 channel DI boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index b52cfe01e6c..eab75eb2647 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -1,3 +1,4 @@ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -19,19 +20,19 @@ static const struct addi_board apci1500_boardtypes[] = { .i_NbrDoChannel = 16, .i_DoMaxdata = 0xffff, .i_Timer = 1, - .interrupt = v_APCI1500_Interrupt, - .reset = i_APCI1500_Reset, - .di_config = i_APCI1500_ConfigDigitalInputEvent, - .di_read = i_APCI1500_Initialisation, - .di_write = i_APCI1500_StartStopInputEvent, + .interrupt = apci1500_interrupt, + .reset = apci1500_reset, + .di_config = apci1500_di_config, + .di_read = apci1500_di_read, + .di_write = apci1500_di_write, .di_bits = apci1500_di_insn_bits, - .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt, - .do_write = i_APCI1500_WriteDigitalOutput, - .do_bits = i_APCI1500_ConfigureInterrupt, - .timer_config = i_APCI1500_ConfigCounterTimerWatchdog, - .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog, - .timer_read = i_APCI1500_ReadInterruptMask, - .timer_bits = i_APCI1500_ReadCounterTimerWatchdog, + .do_config = apci1500_do_config, + .do_write = apci1500_do_write, + .do_bits = apci1500_do_bits, + .timer_config = apci1500_timer_config, + .timer_write = apci1500_timer_write, + .timer_read = apci1500_timer_read, + .timer_bits = apci1500_timer_bits, }, }; @@ -56,7 +57,7 @@ static int apci1500_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1500_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci1500_pci_table) = { +static const struct pci_device_id apci1500_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80fc) }, { 0 } }; @@ -71,5 +72,5 @@ static struct pci_driver apci1500_pci_driver = { module_comedi_pci_driver(apci1500_driver, apci1500_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1500, 16 channel DI / 16 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index b626738bb73..e9c5291c77c 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -22,6 +22,7 @@ * more details. */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -89,16 +90,10 @@ static int apci1516_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inw(dev->iobase + APCI1516_DO_REG); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + APCI1516_DO_REG); - } data[1] = s->state; @@ -136,10 +131,9 @@ static int apci1516_auto_attach(struct comedi_device *dev, dev->board_ptr = this_board; dev->board_name = this_board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -212,7 +206,7 @@ static int apci1516_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1516_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci1516_pci_table) = { +static const struct pci_device_id apci1516_pci_table[] = { { PCI_VDEVICE(ADDIDATA, 0x1000), BOARD_APCI1016 }, { PCI_VDEVICE(ADDIDATA, 0x1001), BOARD_APCI1516 }, { PCI_VDEVICE(ADDIDATA, 0x1002), BOARD_APCI2016 }, diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 22bace62210..13d9962b47e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -1,51 +1,170 @@ +#include <linux/module.h> #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_apci1564.c" -#include "addi-data/addi_common.c" - -static const struct addi_board apci1564_boardtypes[] = { - { - .pc_DriverName = "apci1564", - .i_IorangeBase1 = APCI1564_ADDRESS_RANGE, - .i_PCIEeprom = ADDIDATA_EEPROM, - .pc_EepromChip = ADDIDATA_93C76, - .i_NbrDiChannel = 32, - .i_NbrDoChannel = 32, - .i_DoMaxdata = 0xffffffff, - .i_Timer = 1, - .interrupt = v_APCI1564_Interrupt, - .reset = i_APCI1564_Reset, - .di_config = i_APCI1564_ConfigDigitalInput, - .di_bits = apci1564_di_insn_bits, - .do_config = i_APCI1564_ConfigDigitalOutput, - .do_bits = apci1564_do_insn_bits, - .do_read = i_APCI1564_ReadInterruptStatus, - .timer_config = i_APCI1564_ConfigTimerCounterWatchdog, - .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog, - .timer_read = i_APCI1564_ReadTimerCounterWatchdog, - }, -}; + +static irqreturn_t v_ADDI_Interrupt(int irq, void *d) +{ + apci1564_interrupt(irq, d); + return IRQ_RETVAL(1); +} + +static int apci1564_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_private *devpriv = dev->private; + + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DI_REG); + + return insn->n; +} + +static int apci1564_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_private *devpriv = dev->private; + + s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DO_REG); + + if (comedi_dio_update_state(s, data)) + outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int apci1564_reset(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + + ui_Type = 0; + + /* Disable the input interrupts and reset status register */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + + /* Reset the output channels and disable interrupts */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + + /* Reset the watchdog registers */ + addi_watchdog_reset(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG); + + /* Reset the timer registers */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG); + + /* Reset the counter registers */ + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); + + return 0; +} static int apci1564_auto_attach(struct comedi_device *dev, - unsigned long context) + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct addi_private *devpriv; + struct comedi_subdevice *s; + int ret; + + dev->board_name = dev->driver->driver_name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 1); + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + + apci1564_reset(dev); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* Allocate and Initialise DI Subdevice Structures */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 32; + s->maxdata = 1; + s->len_chanlist = 32; + s->range_table = &range_digital; + s->insn_config = apci1564_di_config; + s->insn_bits = apci1564_di_insn_bits; + + /* Allocate and Initialise DO Subdevice Structures */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 32; + s->maxdata = 0xffffffff; + s->len_chanlist = 32; + s->range_table = &range_digital; + s->insn_config = apci1564_do_config; + s->insn_bits = apci1564_do_insn_bits; + s->insn_read = apci1564_do_read; + + /* Allocate and Initialise Timer Subdevice Structures */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_write = apci1564_timer_write; + s->insn_read = apci1564_timer_read; + s->insn_config = apci1564_timer_config; + + return 0; +} + +static void apci1564_detach(struct comedi_device *dev) { - dev->board_ptr = &apci1564_boardtypes[0]; + struct addi_private *devpriv = dev->private; - return addi_auto_attach(dev, context); + if (devpriv) { + if (dev->iobase) + apci1564_reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); + } + comedi_pci_disable(dev); } static struct comedi_driver apci1564_driver = { .driver_name = "addi_apci_1564", .module = THIS_MODULE, .auto_attach = apci1564_auto_attach, - .detach = i_ADDI_Detach, + .detach = apci1564_detach, }; static int apci1564_pci_probe(struct pci_dev *dev, @@ -54,7 +173,7 @@ static int apci1564_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci1564_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci1564_pci_table) = { +static const struct pci_device_id apci1564_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1006) }, { 0 } }; @@ -69,5 +188,5 @@ static struct pci_driver apci1564_pci_driver = { module_comedi_pci_driver(apci1564_driver, apci1564_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1564, 32 channel DI / 32 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index 1f7bed9a3f7..28df4b50b87 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -22,6 +22,7 @@ * more details. */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -59,36 +60,22 @@ static int apci16xx_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); - unsigned int bits; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; - /* - * 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; + if (chan < 8) + mask = 0x000000ff; + else if (chan < 16) + mask = 0x0000ff00; + else if (chan < 24) + mask = 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; - } + mask = 0xff000000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(s->index)); @@ -100,17 +87,8 @@ static int apci16xx_dio_insn_bits(struct comedi_device *dev, 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); - + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + APCI16XX_OUT_REG(s->index)); - } data[1] = inl(dev->iobase + APCI16XX_IN_REG(s->index)); @@ -190,7 +168,7 @@ static int apci16xx_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci16xx_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci16xx_pci_table) = { +static const struct pci_device_id apci16xx_pci_table[] = { { PCI_VDEVICE(ADDIDATA, 0x1009), BOARD_APCI1648 }, { PCI_VDEVICE(ADDIDATA, 0x100a), BOARD_APCI1696 }, { 0 } diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c deleted file mode 100644 index c9e6471eb06..00000000000 --- a/drivers/staging/comedi/drivers/addi_apci_1710.c +++ /dev/null @@ -1,99 +0,0 @@ -#include <linux/pci.h> - -#include <asm/i387.h> - -#include "../comedidev.h" -#include "comedi_fc.h" -#include "amcc_s5933.h" - -#include "addi-data/addi_common.h" - -static void fpu_begin(void) -{ - kernel_fpu_begin(); -} - -static void fpu_end(void) -{ - kernel_fpu_end(); -} - -#include "addi-data/addi_eeprom.c" -#include "addi-data/hwdrv_APCI1710.c" - -static irqreturn_t v_ADDI_Interrupt(int irq, void *d) -{ - v_APCI1710_Interrupt(irq, d); - return IRQ_RETVAL(1); -} - -static int apci1710_auto_attach(struct comedi_device *dev, - unsigned long context_unused) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct addi_private *devpriv; - struct comedi_subdevice *s; - int ret; - - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - ret = comedi_pci_enable(dev); - if (ret) - return ret; - devpriv->s_BoardInfos.ui_Address = pci_resource_start(pcidev, 2); - - if (pcidev->irq > 0) { - ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, - dev->board_name, dev); - if (ret == 0) - dev->irq = pcidev->irq; - } - - i_ADDI_AttachPCI1710(dev); - - i_APCI1710_Reset(dev); - return 0; -} - -static void apci1710_detach(struct comedi_device *dev) -{ - if (dev->iobase) - i_APCI1710_Reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); -} - -static struct comedi_driver apci1710_driver = { - .driver_name = "addi_apci_1710", - .module = THIS_MODULE, - .auto_attach = apci1710_auto_attach, - .detach = apci1710_detach, -}; - -static int apci1710_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return comedi_pci_auto_config(dev, &apci1710_driver, id->driver_data); -} - -static DEFINE_PCI_DEVICE_TABLE(apci1710_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_AMCC, APCI1710_BOARD_DEVICE_ID) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, apci1710_pci_table); - -static struct pci_driver apci1710_pci_driver = { - .name = "addi_apci_1710", - .id_table = apci1710_pci_table, - .probe = apci1710_pci_probe, - .remove = comedi_pci_auto_unconfig, -}; -module_comedi_pci_driver(apci1710_driver, apci1710_pci_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index 89ead8eb3c7..be0a8a7bd3b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -22,8 +22,10 @@ * more details. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/slab.h> #include "../comedidev.h" #include "addi_watchdog.h" @@ -55,16 +57,10 @@ static int apci2032_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inl(dev->iobase + APCI2032_DO_REG); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + APCI2032_DO_REG); - } data[1] = s->state; @@ -201,6 +197,7 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; struct apci2032_int_private *subpriv; unsigned int val; bool do_event = false; @@ -226,21 +223,20 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) */ if (subpriv->active && (val & subpriv->enabled_isns) != 0) { - unsigned short bits; - unsigned int n, len; - unsigned int *chanlist; + unsigned short bits = 0; + int i; /* 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)) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (val & (1 << chan)) + bits |= (1 << i); + } + + if (comedi_buf_put(s, bits)) { s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (s->async->cmd.stop_src == TRIG_COUNT && + if (cmd->stop_src == TRIG_COUNT && subpriv->stop_count > 0) { subpriv->stop_count--; if (subpriv->stop_count == 0) { @@ -363,7 +359,7 @@ static int apci2032_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci2032_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci2032_pci_table) = { +static const struct pci_device_id apci2032_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1004) }, { 0 } }; @@ -378,5 +374,5 @@ static struct pci_driver apci2032_pci_driver = { module_comedi_pci_driver(apci2032_driver, apci2032_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-2032, 32 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index ca1bd92ecb1..e1a916546d1 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -22,6 +22,7 @@ * more details. */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -49,16 +50,10 @@ static int apci2200_do_insn_bits(struct comedi_device *dev, 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); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + APCI2200_DO_REG); - } data[1] = s->state; @@ -139,7 +134,7 @@ static int apci2200_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci2200_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci2200_pci_table) = { +static const struct pci_device_id apci2200_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1005) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 61452848510..0cfb12fa1cb 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -1,3 +1,4 @@ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -25,7 +26,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, [BOARD_APCI3001] = { .pc_DriverName = "apci3001", @@ -36,7 +37,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, }; @@ -65,10 +66,9 @@ static int apci3120_auto_attach(struct comedi_device *dev, dev->board_ptr = this_board; dev->board_name = this_board->pc_DriverName; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -136,11 +136,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = this_board->i_AiChannelList; s->range_table = &range_apci3120_ai; - s->insn_config = i_APCI3120_InsnConfigAnalogInput; - s->insn_read = i_APCI3120_InsnReadAnalogInput; - s->do_cmdtest = i_APCI3120_CommandTestAnalogInput; - s->do_cmd = i_APCI3120_CommandAnalogInput; - s->cancel = i_APCI3120_StopCyclicAcquisition; + s->insn_config = apci3120_ai_insn_config; + s->insn_read = apci3120_ai_insn_read; + s->do_cmdtest = apci3120_ai_cmdtest; + s->do_cmd = apci3120_ai_cmd; + s->cancel = apci3120_cancel; /* Allocate and Initialise AO Subdevice Structures */ s = &dev->subdevices[1]; @@ -151,7 +151,7 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = this_board->i_AoMaxdata; s->len_chanlist = this_board->i_NbrAoChannel; s->range_table = &range_apci3120_ao; - s->insn_write = i_APCI3120_InsnWriteAnalogOutput; + s->insn_write = apci3120_ao_insn_write; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -164,7 +164,6 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = this_board->i_NbrDiChannel; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_bits = apci3120_di_insn_bits; /* Allocate and Initialise DO Subdevice Structures */ @@ -176,7 +175,6 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = this_board->i_DoMaxdata; s->len_chanlist = this_board->i_NbrDoChannel; s->range_table = &range_digital; - s->io_bits = 0xf; /* all bits output */ s->insn_bits = apci3120_do_insn_bits; /* Allocate and Initialise Timer Subdevice Structures */ @@ -188,11 +186,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3120_InsnWriteTimer; - s->insn_read = i_APCI3120_InsnReadTimer; - s->insn_config = i_APCI3120_InsnConfigTimer; + s->insn_write = apci3120_write_insn_timer; + s->insn_read = apci3120_read_insn_timer; + s->insn_config = apci3120_config_insn_timer; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } @@ -202,7 +200,7 @@ static void apci3120_detach(struct comedi_device *dev) if (devpriv) { if (dev->iobase) - i_APCI3120_Reset(dev); + apci3120_reset(dev); if (dev->irq) free_irq(dev->irq, dev); if (devpriv->ul_DmaBufferVirtual[0]) { @@ -232,7 +230,7 @@ static int apci3120_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3120_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci3120_pci_table) = { +static const struct pci_device_id apci3120_pci_table[] = { { PCI_VDEVICE(AMCC, 0x818d), BOARD_APCI3120 }, { PCI_VDEVICE(AMCC, 0x828d), BOARD_APCI3001 }, { 0 } @@ -248,5 +246,5 @@ static struct pci_driver apci3120_pci_driver = { module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-3120, Analog input board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c index 17b540d3c6a..f0f891a482a 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ b/drivers/staging/comedi/drivers/addi_apci_3200.c @@ -1,3 +1,4 @@ +#include <linux/module.h> #include <linux/pci.h> #include <asm/i387.h> @@ -42,15 +43,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, @@ -67,15 +68,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, @@ -108,7 +109,7 @@ static int apci3200_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3200_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci3200_pci_table) = { +static const struct pci_device_id apci3200_pci_table[] = { { PCI_VDEVICE(ADDIDATA, 0x3000), BOARD_APCI3200 }, { PCI_VDEVICE(ADDIDATA, 0x3007), BOARD_APCI3300 }, { 0 } diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index f9b63689a12..49bf1fb840f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -22,6 +22,7 @@ * more details. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/sched.h> @@ -160,16 +161,10 @@ static int apci3501_do_insn_bits(struct comedi_device *dev, 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); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + APCI3501_DO_REG); - } data[1] = s->state; @@ -332,10 +327,9 @@ static int apci3501_auto_attach(struct comedi_device *dev, int ao_n_chan; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -396,9 +390,9 @@ static int apci3501_auto_attach(struct comedi_device *dev, s->maxdata = 0; s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog; - s->insn_read = i_APCI3501_ReadTimerCounterWatchdog; - s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog; + s->insn_write = apci3501_write_insn_timer; + s->insn_read = apci3501_read_insn_timer; + s->insn_config = apci3501_config_insn_timer; /* Initialize the eeprom subdevice */ s = &dev->subdevices[4]; @@ -434,7 +428,7 @@ static int apci3501_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3501_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci3501_pci_table) = { +static const struct pci_device_id apci3501_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3001) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index 5b37cbf9228..0532b6cc40e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -22,6 +22,7 @@ * more details. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -372,7 +373,7 @@ static irqreturn_t apci3xxx_irq_handler(int irq, void *d) writel(status, devpriv->mmio + 16); val = readl(devpriv->mmio + 28); - comedi_buf_put(s->async, val); + comedi_buf_put(s, val); s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); @@ -433,13 +434,26 @@ static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec) return 0; } +static int apci3xxx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 20); + if (status & 0x1) + return 0; + return -EBUSY; +} + static int apci3xxx_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct apci3xxx_private *devpriv = dev->private; - unsigned int val; int ret; int i; @@ -452,10 +466,9 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev, writel(0x80000, devpriv->mmio + 8); /* Wait the EOS */ - do { - val = readl(devpriv->mmio + 20); - val &= 0x1; - } while (!val); + ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0); + if (ret) + return ret; /* Read the analog value */ data[i] = readl(devpriv->mmio + 28); @@ -520,7 +533,7 @@ static int apci3xxx_ai_cmdtest(struct comedi_device *dev, { const struct apci3xxx_boardinfo *board = comedi_board(dev); int err = 0; - unsigned int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -560,31 +573,9 @@ static int apci3xxx_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - /* - * FIXME: The hardware supports multiple scan modes but the original - * addi-data driver only supported reading a single channel with - * interrupts. Need a proper datasheet to fix this. - * - * The following scan modes are supported by the hardware: - * 1) Single software scan - * 2) Single hardware triggered scan - * 3) Continuous software scan - * 4) Continuous software scan with timer delay - * 5) Continuous hardware triggered scan - * 6) Continuous hardware triggered scan with timer delay - * - * For now, limit the chanlist to a single channel. - */ - if (cmd->chanlist_len > 1) { - cmd->chanlist_len = 1; - err |= -EINVAL; - } - - tmp = cmd->convert_arg; - err |= apci3xxx_ai_ns_to_timer(dev, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err |= -EINVAL; + arg = cmd->convert_arg; + err |= apci3xxx_ai_ns_to_timer(dev, &arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); if (err) return 4; @@ -621,6 +612,20 @@ static int apci3xxx_ai_cancel(struct comedi_device *dev, return 0; } +static int apci3xxx_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 96); + if (status & 0x100) + return 0; + return -EBUSY; +} + static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -629,7 +634,7 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct apci3xxx_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int status; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -640,9 +645,9 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, writel((data[i] << 8) | chan, devpriv->mmio + 100); /* Wait the end of transfer */ - do { - status = readl(devpriv->mmio + 96); - } while ((status & 0x100) != 0x100); + ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0); + if (ret) + return ret; } return insn->n; @@ -663,16 +668,10 @@ static int apci3xxx_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inl(dev->iobase + 48) & 0xf; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + 48); - } data[1] = s->state; @@ -685,38 +684,30 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask = 1 << chan; - unsigned int bits; + unsigned int mask = 0; + int ret; /* * Port 0 (channels 0-7) are always inputs * Port 1 (channels 8-15) are always outputs * Port 2 (channels 16-23) are programmable i/o - * - * Changing any channel in port 2 changes the entire port. */ - if (mask & 0xff0000) - bits = 0xff0000; - else - bits = 0; - - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - default: - return -EINVAL; + if (data[0] != INSN_CONFIG_DIO_QUERY) { + /* ignore all other instructions for ports 0 and 1 */ + if (chan < 16) + return -EINVAL; + else + /* changing any channel in port 2 */ + /* changes the entire port */ + mask = 0xff0000; } + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + /* update port 2 configuration */ - if (bits) - outl((s->io_bits >> 24) & 0xff, dev->iobase + 224); + outl((s->io_bits >> 24) & 0xff, dev->iobase + 224); return insn->n; } @@ -726,16 +717,11 @@ static int apci3xxx_dio_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; + unsigned int mask; unsigned int val; - /* only update output channels */ - mask &= s->io_bits; + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - if (mask & 0xff) outl(s->state & 0xff, dev->iobase + 80); if (mask & 0xff0000) @@ -801,10 +787,9 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -836,12 +821,30 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, s->subdev_flags = SDF_READABLE | board->ai_subdev_flags; s->n_chan = board->ai_n_chan; s->maxdata = board->ai_maxdata; - s->len_chanlist = s->n_chan; s->range_table = &apci3xxx_ai_range; s->insn_read = apci3xxx_ai_insn_read; if (dev->irq) { + /* + * FIXME: The hardware supports multiple scan modes + * but the original addi-data driver only supported + * reading a single channel with interrupts. Need a + * proper datasheet to fix this. + * + * The following scan modes are supported by the + * hardware: + * 1) Single software scan + * 2) Single hardware triggered scan + * 3) Continuous software scan + * 4) Continuous software scan with timer delay + * 5) Continuous hardware triggered scan + * 6) Continuous hardware triggered scan with timer + * delay + * + * For now, limit the chanlist to a single channel. + */ dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; s->do_cmdtest = apci3xxx_ai_cmdtest; s->do_cmd = apci3xxx_ai_cmd; s->cancel = apci3xxx_ai_cancel; @@ -936,7 +939,7 @@ static int apci3xxx_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(apci3xxx_pci_table) = { +static const struct pci_device_id apci3xxx_pci_table[] = { { PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 }, { PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 }, { PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 }, diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c index 7b21acc9392..23031feaa09 100644 --- a/drivers/staging/comedi/drivers/addi_watchdog.c +++ b/drivers/staging/comedi/drivers/addi_watchdog.c @@ -18,6 +18,7 @@ * GNU General Public License for more details. */ +#include <linux/module.h> #include "../comedidev.h" #include "addi_watchdog.h" diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index b5e4e53f737..921f6942dfc 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -1,43 +1,35 @@ /* - comedi/drivers/adl_pci6208.c - - Hardware driver for ADLink 6208 series cards: - card | voltage output | current output - -------------+-------------------+--------------- - PCI-6208V | 8 channels | - - PCI-6216V | 16 channels | - - PCI-6208A | 8 channels | 8 channels - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * adl_pci6208.c + * Comedi driver for ADLink 6208 series cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* -Driver: adl_pci6208 -Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards -Devices: (ADLink) PCI-6208 [adl_pci6208] - (ADLink) PCI-6216 [adl_pci6216] -Author: nsyeow <nsyeow@pd.jaring.my> -Updated: Fri, 30 Jan 2004 14:44:27 +0800 -Status: untested - -Configuration Options: not applicable, uses PCI auto config - -References: - - ni_660x.c - - adl_pci9111.c copied the entire pci setup section - - adl_pci9118.c -*/ + * Driver: adl_pci6208 + * Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards + * Devices: (ADLink) PCI-6208 [adl_pci6208] + * (ADLink) PCI-6216 [adl_pci6216] + * Author: nsyeow <nsyeow@pd.jaring.my> + * Updated: Fri, 30 Jan 2004 14:44:27 +0800 + * Status: untested + * + * Configuration Options: not applicable, uses PCI auto config + */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/pci.h> #include "../comedidev.h" @@ -81,37 +73,54 @@ struct pci6208_private { unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS]; }; -static int pci6208_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pci6208_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI6208_AO_STATUS); + if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) + return 0; + return -EBUSY; +} + +static int pci6208_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pci6208_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - unsigned long invert = 1 << (16 - 1); - unsigned long value = 0; - unsigned short status; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int ret; int i; for (i = 0; i < insn->n; i++) { - value = data[i] ^ invert; + val = data[i]; - do { - status = inw(dev->iobase + PCI6208_AO_STATUS); - } while (status & PCI6208_AO_STATUS_DATA_SEND); + /* D/A transfer rate is 2.2us */ + ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0); + if (ret) + return ret; - outw(value, dev->iobase + PCI6208_AO_CONTROL(chan)); + /* the hardware expects two's complement values */ + outw(comedi_offset_munge(s, val), + dev->iobase + PCI6208_AO_CONTROL(chan)); } - devpriv->ao_readback[chan] = value; + devpriv->ao_readback[chan] = val; return insn->n; } -static int pci6208_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pci6208_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pci6208_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) @@ -140,15 +149,8 @@ static int pci6208_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI6208_DIO); - } data[1] = s->state; @@ -172,10 +174,9 @@ static int pci6208_auto_attach(struct comedi_device *dev, dev->board_ptr = boardinfo; dev->board_name = boardinfo->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -193,8 +194,8 @@ static int pci6208_auto_attach(struct comedi_device *dev, s->n_chan = boardinfo->ao_chans; s->maxdata = 0xffff; s->range_table = &range_bipolar10; - s->insn_write = pci6208_ao_winsn; - s->insn_read = pci6208_ao_rinsn; + s->insn_write = pci6208_ao_insn_write; + s->insn_read = pci6208_ao_insn_read; s = &dev->subdevices[1]; /* digital input subdevice */ @@ -221,10 +222,6 @@ static int pci6208_auto_attach(struct comedi_device *dev, val = inw(dev->iobase + PCI6208_DIO); val = (val & PCI6208_DIO_DO_MASK) >> PCI6208_DIO_DO_SHIFT; s->state = val; - s->io_bits = 0x0f; - - dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx\n", - dev->driver->driver_name, dev->board_name, dev->iobase); return 0; } @@ -243,7 +240,7 @@ static int adl_pci6208_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = { +static const struct pci_device_id adl_pci6208_pci_table[] = { { PCI_VDEVICE(ADLINK, 0x6208), BOARD_PCI6208 }, { PCI_VDEVICE(ADLINK, 0x6216), BOARD_PCI6216 }, { 0 } @@ -259,5 +256,5 @@ static struct pci_driver adl_pci6208_pci_driver = { module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for ADLink 6208 series cards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index 0d9243a5f49..5e3cc77a8a0 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -44,6 +44,7 @@ driver. Configuration Options: not applicable, uses comedi PCI auto config */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -111,21 +112,10 @@ static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev, unsigned int *data) { unsigned long reg = (unsigned long)s->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + reg); - } - /* - * NOTE: The output register is not readable. - * This returned state will not be correct until all the - * outputs have been updated. - */ data[1] = s->state; return insn->n; @@ -249,9 +239,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev, } } - dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n", - dev->board_name, board->di_nchan, board->do_nchan); - return 0; } @@ -269,7 +256,7 @@ static int adl_pci7x3x_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = { +static const struct pci_device_id adl_pci7x3x_pci_table[] = { { PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 }, { PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 }, { PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 }, diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index 0b591b0b550..300df55a280 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -27,6 +27,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -144,7 +145,7 @@ static int adl_pci8164_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = { +static const struct pci_device_id adl_pci8164_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x8164) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index af51c746004..584fd57ecb7 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -64,6 +64,7 @@ TODO: */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -83,9 +84,6 @@ TODO: #define PCI9111_RANGE_SETTING_DELAY 10 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2 -#define PCI9111_AI_INSTANT_READ_TIMEOUT 100 - -#define PCI9111_8254_CLOCK_PERIOD_NS 500 /* * IO address map and bit defines @@ -126,8 +124,7 @@ TODO: PLX9052_INTCSR_LI2STAT) static const struct comedi_lrange pci9111_ai_range = { - 5, - { + 5, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.5), @@ -140,10 +137,8 @@ struct pci9111_private_data { unsigned long lcr_io_base; int stop_counter; - int stop_is_none; unsigned int scan_delay; - unsigned int chanlist_len; unsigned int chunk_counter; unsigned int chunk_num_samples; @@ -152,7 +147,7 @@ struct pci9111_private_data { unsigned int div1; unsigned int div2; - short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; + unsigned short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; }; static void plx9050_interrupt_control(unsigned long io_base, @@ -317,149 +312,137 @@ static int pci9111_ai_cancel(struct comedi_device *dev, return 0; } +static int pci9111_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (chan != i) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels,counting upwards from 0\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same reference\n"); + return -EINVAL; + } + } + + return 0; +} + static int pci9111_ai_do_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { struct pci9111_private_data *dev_private = dev->private; - int tmp; - int error = 0; - int range, reference; - int i; + int err = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ - error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - error |= cfc_check_trigger_src(&cmd->scan_begin_src, + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); - error |= cfc_check_trigger_src(&cmd->convert_src, + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); - error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - error |= cfc_check_trigger_src(&cmd->stop_src, + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - if (error) + if (err) return 1; /* Step 2a : make sure trigger sources are unique */ - error |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - error |= cfc_check_trigger_is_unique(cmd->convert_src); - error |= cfc_check_trigger_is_unique(cmd->stop_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); /* Step 2b : and mutually compatible */ - if ((cmd->convert_src == TRIG_TIMER) && - !((cmd->scan_begin_src == TRIG_TIMER) || - (cmd->scan_begin_src == TRIG_FOLLOW))) - error |= -EINVAL; - if ((cmd->convert_src == TRIG_EXT) && - !((cmd->scan_begin_src == TRIG_EXT) || - (cmd->scan_begin_src == TRIG_FOLLOW))) - error |= -EINVAL; + if (cmd->scan_begin_src != TRIG_FOLLOW) { + if (cmd->scan_begin_src != cmd->convert_src) + err |= -EINVAL; + } - if (error) + if (err) return 2; /* Step 3: check if arguments are trivially valid */ - error |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (cmd->convert_src == TRIG_TIMER) - error |= cfc_check_trigger_arg_min(&cmd->convert_arg, + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); else /* TRIG_EXT */ - error |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); if (cmd->scan_begin_src == TRIG_TIMER) - error |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); else /* TRIG_FOLLOW || TRIG_EXT */ - error |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - error |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, - cmd->chanlist_len); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) - error |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); else /* TRIG_NONE */ - error |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - if (error) + if (err) return 3; - /* Step 4 : fix up any arguments */ + /* Step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, - &dev_private->div1, - &dev_private->div2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - error++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &dev_private->div1, + &dev_private->div2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } - /* There's only one timer on this card, so the scan_begin timer must */ - /* be a multiple of chanlist_len*convert_arg */ + /* + * There's only one timer on this card, so the scan_begin timer + * must be a multiple of chanlist_len*convert_arg + */ if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->chanlist_len * cmd->convert_arg; - unsigned int scan_begin_min; - unsigned int scan_begin_arg; - unsigned int scan_factor; - - scan_begin_min = cmd->chanlist_len * cmd->convert_arg; - - if (cmd->scan_begin_arg != scan_begin_min) { - if (scan_begin_min < cmd->scan_begin_arg) { - scan_factor = - cmd->scan_begin_arg / scan_begin_min; - scan_begin_arg = scan_factor * scan_begin_min; - if (cmd->scan_begin_arg != scan_begin_arg) { - cmd->scan_begin_arg = scan_begin_arg; - error++; - } - } else { - cmd->scan_begin_arg = scan_begin_min; - error++; - } - } + if (arg < cmd->scan_begin_arg) + arg *= (cmd->scan_begin_arg / arg); + + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } - if (error) + if (err) return 4; - /* Step 5 : check channel list */ - - if (cmd->chanlist) { - - range = CR_RANGE(cmd->chanlist[0]); - reference = CR_AREF(cmd->chanlist[0]); - - if (cmd->chanlist_len > 1) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - comedi_error(dev, - "entries in chanlist must be consecutive " - "channels,counting upwards from 0\n"); - error++; - } - if (CR_RANGE(cmd->chanlist[i]) != range) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - error++; - } - if (CR_AREF(cmd->chanlist[i]) != reference) { - comedi_error(dev, - "entries in chanlist must all have the same reference\n"); - error++; - } - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci9111_ai_check_chanlist(dev, s, cmd); - if (error) + if (err) return 5; return 0; @@ -470,23 +453,18 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci9111_private_data *dev_private = dev->private; - struct comedi_cmd *async_cmd = &s->async->cmd; + struct comedi_cmd *cmd = &s->async->cmd; - if (!dev->irq) { - comedi_error(dev, - "no irq assigned for PCI9111, cannot do hardware conversion"); - return -1; - } /* Set channel scan limit */ /* PCI9111 allows only scanning from channel 0 to channel n */ /* TODO: handle the case of an external multiplexer */ - if (async_cmd->chanlist_len > 1) { - outb(async_cmd->chanlist_len - 1, + if (cmd->chanlist_len > 1) { + outb(cmd->chanlist_len - 1, dev->iobase + PCI9111_AI_CHANNEL_REG); pci9111_autoscan_set(dev, true); } else { - outb(CR_CHAN(async_cmd->chanlist[0]), + outb(CR_CHAN(cmd->chanlist[0]), dev->iobase + PCI9111_AI_CHANNEL_REG); pci9111_autoscan_set(dev, false); } @@ -494,33 +472,18 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, /* Set gain */ /* This is the same gain on every channel */ - outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, + outb(CR_RANGE(cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, dev->iobase + PCI9111_AI_RANGE_STAT_REG); /* Set counter */ - - switch (async_cmd->stop_src) { - case TRIG_COUNT: - dev_private->stop_counter = - async_cmd->stop_arg * async_cmd->chanlist_len; - dev_private->stop_is_none = 0; - break; - - case TRIG_NONE: + if (cmd->stop_src == TRIG_COUNT) + dev_private->stop_counter = cmd->stop_arg * cmd->chanlist_len; + else /* TRIG_NONE */ dev_private->stop_counter = 0; - dev_private->stop_is_none = 1; - break; - - default: - comedi_error(dev, "Invalid stop trigger"); - return -1; - } /* Set timer pacer */ - dev_private->scan_delay = 0; - switch (async_cmd->convert_src) { - case TRIG_TIMER: + if (cmd->convert_src == TRIG_TIMER) { pci9111_trigger_source_set(dev, software); pci9111_timer_set(dev); pci9111_fifo_reset(dev); @@ -530,17 +493,11 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, plx9050_interrupt_control(dev_private->lcr_io_base, true, true, false, true, true); - if (async_cmd->scan_begin_src == TRIG_TIMER) { - dev_private->scan_delay = - (async_cmd->scan_begin_arg / - (async_cmd->convert_arg * - async_cmd->chanlist_len)) - 1; + if (cmd->scan_begin_src == TRIG_TIMER) { + dev_private->scan_delay = (cmd->scan_begin_arg / + (cmd->convert_arg * cmd->chanlist_len)) - 1; } - - break; - - case TRIG_EXT: - + } else { /* TRIG_EXT */ pci9111_trigger_source_set(dev, external); pci9111_fifo_reset(dev); pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, @@ -548,18 +505,12 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, plx9050_interrupt_control(dev_private->lcr_io_base, true, true, false, true, true); - break; - - default: - comedi_error(dev, "Invalid convert trigger"); - return -1; } dev_private->stop_counter *= (1 + dev_private->scan_delay); - dev_private->chanlist_len = async_cmd->chanlist_len; dev_private->chunk_counter = 0; - dev_private->chunk_num_samples = - dev_private->chanlist_len * (1 + dev_private->scan_delay); + dev_private->chunk_num_samples = cmd->chanlist_len * + (1 + dev_private->scan_delay); return 0; } @@ -569,7 +520,7 @@ static void pci9111_ai_munge(struct comedi_device *dev, unsigned int num_bytes, unsigned int start_chan_index) { - short *array = data; + unsigned short *array = data; unsigned int maxdata = s->maxdata; unsigned int invert = (maxdata + 1) >> 1; unsigned int shift = (maxdata == 0xffff) ? 0 : 4; @@ -580,12 +531,71 @@ static void pci9111_ai_munge(struct comedi_device *dev, array[i] = ((array[i] >> shift) & maxdata) ^ invert; } +static void pci9111_handle_fifo_half_full(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci9111_private_data *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int total = 0; + unsigned int samples; + + if (cmd->stop_src == TRIG_COUNT && + PCI9111_FIFO_HALF_SIZE > devpriv->stop_counter) + samples = devpriv->stop_counter; + else + samples = PCI9111_FIFO_HALF_SIZE; + + insw(dev->iobase + PCI9111_AI_FIFO_REG, + devpriv->ai_bounce_buffer, samples); + + if (devpriv->scan_delay < 1) { + total = cfc_write_array_to_buffer(s, + devpriv->ai_bounce_buffer, + samples * sizeof(short)); + } else { + unsigned int pos = 0; + unsigned int to_read; + + while (pos < samples) { + if (devpriv->chunk_counter < cmd->chanlist_len) { + to_read = cmd->chanlist_len - + devpriv->chunk_counter; + + if (to_read > samples - pos) + to_read = samples - pos; + + total += cfc_write_array_to_buffer(s, + devpriv->ai_bounce_buffer + pos, + to_read * sizeof(short)); + } else { + to_read = devpriv->chunk_num_samples - + devpriv->chunk_counter; + + if (to_read > samples - pos) + to_read = samples - pos; + + total += to_read * sizeof(short); + } + + pos += to_read; + devpriv->chunk_counter += to_read; + + if (devpriv->chunk_counter >= + devpriv->chunk_num_samples) + devpriv->chunk_counter = 0; + } + } + + devpriv->stop_counter -= total / sizeof(short); +} + static irqreturn_t pci9111_interrupt(int irq, void *p_device) { struct comedi_device *dev = p_device; struct pci9111_private_data *dev_private = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async; + struct comedi_cmd *cmd; unsigned int status; unsigned long irq_flags; unsigned char intcsr; @@ -597,6 +607,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) } async = s->async; + cmd = &async->cmd; spin_lock_irqsave(&dev->spinlock, irq_flags); @@ -621,100 +632,42 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); outb(0, dev->iobase + PCI9111_INT_CLR_REG); - pci9111_ai_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } /* '0' means FIFO is half-full */ - if (!(status & PCI9111_AI_STAT_FF_HF)) { - unsigned int num_samples; - unsigned int bytes_written = 0; - - num_samples = - PCI9111_FIFO_HALF_SIZE > - dev_private->stop_counter - && !dev_private-> - stop_is_none ? dev_private->stop_counter : - PCI9111_FIFO_HALF_SIZE; - insw(dev->iobase + PCI9111_AI_FIFO_REG, - dev_private->ai_bounce_buffer, num_samples); - - if (dev_private->scan_delay < 1) { - bytes_written = - cfc_write_array_to_buffer(s, - dev_private-> - ai_bounce_buffer, - num_samples * - sizeof(short)); - } else { - int position = 0; - int to_read; - - while (position < num_samples) { - if (dev_private->chunk_counter < - dev_private->chanlist_len) { - to_read = - dev_private->chanlist_len - - dev_private->chunk_counter; - - if (to_read > - num_samples - position) - to_read = - num_samples - - position; - - bytes_written += - cfc_write_array_to_buffer - (s, - dev_private->ai_bounce_buffer - + position, - to_read * sizeof(short)); - } else { - to_read = - dev_private->chunk_num_samples - - - dev_private->chunk_counter; - if (to_read > - num_samples - position) - to_read = - num_samples - - position; - - bytes_written += - sizeof(short) * to_read; - } - - position += to_read; - dev_private->chunk_counter += to_read; - - if (dev_private->chunk_counter >= - dev_private->chunk_num_samples) - dev_private->chunk_counter = 0; - } - } - - dev_private->stop_counter -= - bytes_written / sizeof(short); - } + if (!(status & PCI9111_AI_STAT_FF_HF)) + pci9111_handle_fifo_half_full(dev, s); } - if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) { + if (cmd->stop_src == TRIG_COUNT && dev_private->stop_counter == 0) async->events |= COMEDI_CB_EOA; - pci9111_ai_cancel(dev, s); - } outb(0, dev->iobase + PCI9111_INT_CLR_REG); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } +static int pci9111_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + if (status & PCI9111_AI_STAT_FF_EF) + return 0; + return -EBUSY; +} + static int pci9111_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -725,7 +678,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, unsigned int invert = (maxdata + 1) >> 1; unsigned int shift = (maxdata == 0xffff) ? 0 : 4; unsigned int status; - int timeout; + int ret; int i; outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG); @@ -742,22 +695,12 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, /* Generate a software trigger */ outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG); - timeout = PCI9111_AI_INSTANT_READ_TIMEOUT; - - while (timeout--) { - status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); - /* '1' means FIFO is not empty */ - if (status & PCI9111_AI_STAT_FF_EF) - goto conversion_done; + ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0); + if (ret) { + pci9111_fifo_reset(dev); + return ret; } - comedi_error(dev, "A/D read timeout"); - data[i] = 0; - pci9111_fifo_reset(dev); - return -ETIME; - -conversion_done: - data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG); data[i] = ((data[i] >> shift) & maxdata) ^ invert; } @@ -812,15 +755,8 @@ static int pci9111_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI9111_DIO_REG); - } data[1] = s->state; @@ -855,10 +791,9 @@ static int pci9111_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - dev_private = kzalloc(sizeof(*dev_private), GFP_KERNEL); + dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); if (!dev_private) return -ENOMEM; - dev->private = dev_private; ret = comedi_pci_enable(dev); if (ret) @@ -868,12 +803,11 @@ static int pci9111_auto_attach(struct comedi_device *dev, pci9111_reset(dev); - if (pcidev->irq > 0) { - ret = request_irq(dev->irq, pci9111_interrupt, + if (pcidev->irq) { + ret = request_irq(pcidev->irq, pci9111_interrupt, IRQF_SHARED, dev->board_name, dev); - if (ret) - return ret; - dev->irq = pcidev->irq; + if (ret == 0) + dev->irq = pcidev->irq; } ret = comedi_alloc_subdevices(dev, 4); @@ -881,18 +815,21 @@ static int pci9111_auto_attach(struct comedi_device *dev, return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_COMMON; s->n_chan = 16; s->maxdata = 0xffff; - s->len_chanlist = 16; s->range_table = &pci9111_ai_range; - s->cancel = pci9111_ai_cancel; s->insn_read = pci9111_ai_insn_read; - s->do_cmdtest = pci9111_ai_do_cmd_test; - s->do_cmd = pci9111_ai_do_cmd; - s->munge = pci9111_ai_munge; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = pci9111_ai_do_cmd_test; + s->do_cmd = pci9111_ai_do_cmd; + s->cancel = pci9111_ai_cancel; + s->munge = pci9111_ai_munge; + } s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; @@ -920,8 +857,6 @@ static int pci9111_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = pci9111_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } @@ -948,7 +883,7 @@ static int pci9111_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { +static const struct pci_device_id pci9111_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ { 0 } diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index cb4ef2dcbf0..59a65cbc6db 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -77,6 +77,7 @@ Configuration options: * manual attachment. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/gfp.h> @@ -95,7 +96,7 @@ Configuration options: * correct channel number on every 12 bit sample */ -#define IORANGE_9118 64 /* I hope */ +#define IORANGE_9118 64 /* I hope */ #define PCI9118_CHANLEN 255 /* * len of chanlist, some source say 256, * but reality looks like 255 :-( @@ -193,28 +194,30 @@ Configuration options: #define EXTTRG_AI 0 /* ext trg is used by AI */ -static const struct comedi_lrange range_pci9118dg_hr = { 8, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } +static const struct comedi_lrange range_pci9118dg_hr = { + 8, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_pci9118hg = { 8, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } +static const struct comedi_lrange range_pci9118hg = { + 8, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; #define PCI9118_BIPOLAR_RANGES 4 /* @@ -317,14 +320,9 @@ struct pci9118_private { unsigned char AdControlReg; /* A/D control register */ unsigned char IntControlReg; /* Interrupt control register */ unsigned char AdFunctionReg; /* A/D function register */ - char valid; /* driver is ok */ char ai_neverending; /* we do unlimited AI */ - unsigned int i8254_osc_base; /* frequence of onboard oscilator */ unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_buf_ptr; /* data buffer ptr in samples */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int ai_n_scanlen; /* len of actual scanlist */ unsigned int ai_n_realscanlen; /* * what we must transfer for one * outgoing scan include front/back adds @@ -338,9 +336,6 @@ struct pci9118_private { * how many channels we must add * before scan to satisfy DMA? */ - unsigned int *ai_chanlist; /* actual chanlist */ - unsigned int ai_timer1; - unsigned int ai_timer2; unsigned int ai_flags; char ai12_startstop; /* * measure can start/stop @@ -350,13 +345,10 @@ struct pci9118_private { * divisors for start of measure * on external start */ - unsigned int ai_data_len; - short *ai_data; - short ao_data[2]; /* data output buffer */ - unsigned int ai_scans; /* number of scans to do */ + unsigned short ao_data[2]; /* data output buffer */ char dma_doublebuf; /* we can use double buffering */ unsigned int dma_actbuf; /* which buffer is used now */ - short *dmabuf_virt[2]; /* + unsigned short *dmabuf_virt[2]; /* * pointers to begin of * DMA buffer */ @@ -370,31 +362,12 @@ struct pci9118_private { */ unsigned int dmabuf_used_size[2]; /* which size was truly used */ unsigned int dmabuf_panic_size[2]; - unsigned int dmabuf_samples[2]; /* size in samples */ int dmabuf_pages[2]; /* number of pages in buffer */ - unsigned char cnt0_users; /* - * bit field of 8254 CNT0 users - * (0-unused, 1-AO, 2-DI, 3-DO) - */ unsigned char exttrg_users; /* * bit field of external trigger * users(0-AI, 1-AO, 2-DI, 3-DO) */ - unsigned int cnt0_divisor; /* actual CNT0 divisor */ - void (*int_ai_func) (struct comedi_device *, struct comedi_subdevice *, - unsigned short, - unsigned int, - unsigned short); /* - * ptr to actual interrupt - * AI function - */ - unsigned char ai16bits; /* =1 16 bit card */ unsigned char usedma; /* =1 use DMA transfer and not INT */ - unsigned char useeoshandle; /* - * =1 change WAKE_EOS DMA transfer - * to fit on every second - */ - unsigned char usessh; /* =1 turn on S&H support */ int softsshdelay; /* * >0 use software S&H, * numer is requested delay in ns @@ -409,7 +382,6 @@ struct pci9118_private { */ unsigned int ai_maskerr; /* which warning was printed */ unsigned int ai_maskharderr; /* on which error bits stops */ - unsigned int ai_inttrig_start; /* TRIG_INT for start */ }; static int check_channel_list(struct comedi_device *dev, @@ -466,7 +438,7 @@ static int check_channel_list(struct comedi_device *dev, static int setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, int rot, int frontadd, - int backadd, int usedma, char useeos) + int backadd, int usedma) { struct pci9118_private *devpriv = dev->private; unsigned int i, differencial = 0, bipolar = 0; @@ -550,18 +522,6 @@ static int setup_channel_list(struct comedi_device *dev, #ifdef PCI9118_PARANOIDCHECK devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; /* for 32bit operations */ - if (useeos) { - for (i = 1; i < n_chan; i++) { /* store range list to card */ - devpriv->chanlist[(n_chan + i) ^ usedma] = - (CR_CHAN(chanlist[i]) & 0xf) << rot; - } - devpriv->chanlist[(2 * n_chan) ^ usedma] = - devpriv->chanlist[0 ^ usedma]; - /* for 32bit operations */ - useeos = 2; - } else { - useeos = 1; - } #endif outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */ /* udelay(100); important delay, or first sample will be crippled */ @@ -569,12 +529,26 @@ static int setup_channel_list(struct comedi_device *dev, return 1; /* we can serve this with scan logic */ } +static int pci9118_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inl(dev->iobase + PCI9118_ADSTAT); + if (status & AdStatus_ADrdy) + return 0; + return -EBUSY; +} + static int pci9118_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci9118_private *devpriv = dev->private; - int n, timeout; + int ret; + int n; devpriv->AdControlReg = AdControl_Int & 0xff; devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; @@ -587,7 +561,7 @@ static int pci9118_insn_read_ai(struct comedi_device *dev, * trigger stop */ - if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0, 0)) + if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0)) return -EINVAL; outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ @@ -595,20 +569,14 @@ static int pci9118_insn_read_ai(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */ udelay(2); - timeout = 100; - while (timeout--) { - if (inl(dev->iobase + PCI9118_ADSTAT) & AdStatus_ADrdy) - goto conv_finish; - udelay(1); - } - comedi_error(dev, "A/D insn timeout"); - data[n] = 0; - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - return -ETIME; + ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0); + if (ret) { + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ + return ret; + } -conv_finish: - if (devpriv->ai16bits) { + if (s->maxdata == 0xffff) { data[n] = (inl(dev->iobase + PCI9118_AD_DATA) & 0xffff) ^ 0x8000; @@ -670,13 +638,12 @@ static int pci9118_insn_bits_di(struct comedi_device *dev, static int pci9118_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outl(s->state & 0x0f, dev->iobase + PCI9118_DO); - } + data[1] = s->state; return insn->n; @@ -700,14 +667,15 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev) static unsigned int defragment_dma_buffer(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int i = 0, j = 0; unsigned int start_pos = devpriv->ai_add_front, - stop_pos = devpriv->ai_add_front + devpriv->ai_n_chan; - unsigned int raw_scanlen = devpriv->ai_add_front + devpriv->ai_n_chan + + stop_pos = devpriv->ai_add_front + cmd->chanlist_len; + unsigned int raw_scanlen = devpriv->ai_add_front + cmd->chanlist_len + devpriv->ai_add_back; for (i = 0; i < num_samples; i++) { @@ -724,17 +692,18 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev, static int move_block_from_dma(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int num_bytes; num_samples = defragment_dma_buffer(dev, s, dma_buffer, num_samples); devpriv->ai_act_scan += - (s->async->cur_chan + num_samples) / devpriv->ai_n_scanlen; + (s->async->cur_chan + num_samples) / cmd->scan_end_arg; s->async->cur_chan += num_samples; - s->async->cur_chan %= devpriv->ai_n_scanlen; + s->async->cur_chan %= cmd->scan_end_arg; num_bytes = cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); @@ -782,46 +751,51 @@ static void pci9118_calc_divisors(char mode, struct comedi_device *dev, unsigned int *tim1, unsigned int *tim2, unsigned int flags, int chans, unsigned int *div1, unsigned int *div2, - char usessh, unsigned int chnsshfront) + unsigned int chnsshfront) { const struct boardtype *this_board = comedi_board(dev); - struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; switch (mode) { case 1: case 4: if (*tim2 < this_board->ai_ns_min) *tim2 = this_board->ai_ns_min; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2, + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, + div1, div2, tim2, flags & TRIG_ROUND_NEAREST); break; case 2: if (*tim2 < this_board->ai_ns_min) *tim2 = this_board->ai_ns_min; - *div1 = *tim2 / devpriv->i8254_osc_base; + *div1 = *tim2 / I8254_OSC_BASE_4MHZ; /* convert timer (burst) */ if (*div1 < this_board->ai_pacer_min) *div1 = this_board->ai_pacer_min; - *div2 = *tim1 / devpriv->i8254_osc_base; /* scan timer */ + *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */ *div2 = *div2 / *div1; /* major timer is c1*c2 */ if (*div2 < chans) *div2 = chans; - *tim2 = *div1 * devpriv->i8254_osc_base; - /* real convert timer */ + *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */ - if (usessh && (chnsshfront == 0)) /* use BSSH signal */ + if (cmd->convert_src == TRIG_NOW && !chnsshfront) { + /* use BSSH signal */ if (*div2 < (chans + 2)) *div2 = chans + 2; + } - *tim1 = *div1 * *div2 * devpriv->i8254_osc_base; + *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ; break; } } -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static void pci9118_start_pacer(struct comedi_device *dev, int mode) { + struct pci9118_private *devpriv = dev->private; + unsigned int divisor1 = devpriv->ai_divisor1; + unsigned int divisor2 = devpriv->ai_divisor2; + outl(0x74, dev->iobase + PCI9118_CNTCTRL); outl(0xb4, dev->iobase + PCI9118_CNTCTRL); /* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */ @@ -845,7 +819,7 @@ static int pci9118_ai_cancel(struct comedi_device *dev, (~EN_A2P_TRANSFERS), devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */ pci9118_exttrg_del(dev, EXTTRG_AI); - start_pacer(dev, 0, 0, 0); /* stop 8254 counters */ + pci9118_start_pacer(dev, 0); /* stop 8254 counters */ devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); /* @@ -872,7 +846,6 @@ static int pci9118_ai_cancel(struct comedi_device *dev, devpriv->ai_act_dmapos = 0; s->async->cur_chan = 0; s->async->inttrig = NULL; - devpriv->ai_buf_ptr = 0; devpriv->ai_neverending = 0; devpriv->dma_actbuf = 0; @@ -909,8 +882,7 @@ static char pci9118_decode_error_status(struct comedi_device *dev, } if (m & devpriv->ai_maskharderr) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return 1; } @@ -924,12 +896,12 @@ static void pci9118_ai_munge(struct comedi_device *dev, { struct pci9118_private *devpriv = dev->private; unsigned int i, num_samples = num_bytes / sizeof(short); - short *array = data; + unsigned short *array = data; for (i = 0; i < num_samples; i++) { if (devpriv->usedma) array[i] = be16_to_cpu(array[i]); - if (devpriv->ai16bits) + if (s->maxdata == 0xffff) array[i] ^= 0x8000; else array[i] = (array[i] >> 4) & 0x0fff; @@ -944,9 +916,8 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, unsigned short int_daq) { struct pci9118_private *devpriv = dev->private; - register short sampl; - - s->async->events = 0; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned short sampl; if (int_adstat & devpriv->ai_maskerr) if (pci9118_decode_error_status(dev, s, int_adstat)) @@ -955,7 +926,7 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, sampl = inw(dev->iobase + PCI9118_AD_DATA); #ifdef PCI9118_PARANOIDCHECK - if (devpriv->ai16bits == 0) { + if (s->maxdata != 0xffff) { if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) { /* data dropout! */ dev_info(dev->class_dev, @@ -963,28 +934,25 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, sampl & 0x000f, devpriv->chanlist[s->async->cur_chan]); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } } #endif cfc_write_to_buffer(s, sampl); s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_scanlen) { + if (s->async->cur_chan >= cmd->scan_end_arg) { /* one scan done */ - s->async->cur_chan %= devpriv->ai_n_scanlen; + s->async->cur_chan %= cmd->scan_end_arg; devpriv->ai_act_scan++; - if (!(devpriv->ai_neverending)) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pci9118_ai_cancel(dev, s); + if (!devpriv->ai_neverending) { + /* all data sampled? */ + if (devpriv->ai_act_scan >= cmd->stop_arg) s->async->events |= COMEDI_CB_EOA; - } + } } - if (s->async->events) - comedi_event(dev, s); + cfc_handle_events(dev, s); } static void interrupt_pci9118_ai_dma(struct comedi_device *dev, @@ -994,21 +962,20 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, unsigned short int_daq) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int next_dma_buf, samplesinbuf, sampls, m; if (int_amcc & MASTER_ABORT_INT) { comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!"); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (int_amcc & TARGET_ABORT_INT) { comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!"); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (int_adstat & devpriv->ai_maskerr) @@ -1035,23 +1002,20 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, } if (samplesinbuf) { - m = devpriv->ai_data_len >> 1; /* - * how many samples is to - * end of buffer - */ + /* how many samples is to end of buffer */ + m = s->async->prealloc_bufsz >> 1; sampls = m; move_block_from_dma(dev, s, devpriv->dmabuf_virt[devpriv->dma_actbuf], samplesinbuf); - m = m - sampls; /* m= how many samples was transferred */ + m = m - sampls; /* m=how many samples was transferred */ } - if (!devpriv->ai_neverending) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pci9118_ai_cancel(dev, s); + if (!devpriv->ai_neverending) { + /* all data sampled? */ + if (devpriv->ai_act_scan >= cmd->stop_arg) s->async->events |= COMEDI_CB_EOA; - } + } if (devpriv->dma_doublebuf) { /* switch dma buffers */ devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; @@ -1064,81 +1028,74 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, interrupt_pci9118_ai_mode4_switch(dev); } - comedi_event(dev, s); + cfc_handle_events(dev, s); } -static irqreturn_t interrupt_pci9118(int irq, void *d) +static irqreturn_t pci9118_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; struct pci9118_private *devpriv = dev->private; - unsigned int int_daq = 0, int_amcc, int_adstat; + unsigned int intsrc; /* IRQ reasons from card */ + unsigned int intcsr; /* INT register from AMCC chip */ + unsigned int adstat; /* STATUS register */ if (!dev->attached) - return IRQ_NONE; /* not fully initialized */ - - int_daq = inl(dev->iobase + PCI9118_INTSRC) & 0xf; - /* get IRQ reasons from card */ - int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* get INT register from AMCC chip */ - - if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) - return IRQ_NONE; /* interrupt from other source */ - - outl(int_amcc | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* shutdown IRQ reasons in AMCC */ - - int_adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; - /* get STATUS register */ - - if (devpriv->ai_do) { - if (devpriv->ai12_startstop) - if ((int_adstat & AdStatus_DTH) && - (int_daq & Int_DTrg)) { - /* start stop of measure */ - if (devpriv->ai12_startstop & START_AI_EXT) { - devpriv->ai12_startstop &= - ~START_AI_EXT; - if (!(devpriv->ai12_startstop & - STOP_AI_EXT)) - pci9118_exttrg_del - (dev, EXTTRG_AI); - /* deactivate EXT trigger */ - start_pacer(dev, devpriv->ai_do, - devpriv->ai_divisor1, - devpriv->ai_divisor2); - /* start pacer */ - outl(devpriv->AdControlReg, - dev->iobase + PCI9118_ADCNTRL); - } else { - if (devpriv->ai12_startstop & - STOP_AI_EXT) { - devpriv->ai12_startstop &= - ~STOP_AI_EXT; - pci9118_exttrg_del - (dev, EXTTRG_AI); - /* deactivate EXT trigger */ - devpriv->ai_neverending = 0; - /* - * well, on next interrupt from - * DMA/EOC measure will stop - */ - } - } - } + return IRQ_NONE; + + intsrc = inl(dev->iobase + PCI9118_INTSRC) & 0xf; + intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); + + if (!intsrc && !(intcsr & ANY_S593X_INT)) + return IRQ_NONE; + + outl(intcsr | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); + + adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; - (devpriv->int_ai_func) (dev, &dev->subdevices[0], int_adstat, - int_amcc, int_daq); + if (!devpriv->ai_do) + return IRQ_HANDLED; + if (devpriv->ai12_startstop) { + if ((adstat & AdStatus_DTH) && (intsrc & Int_DTrg)) { + /* start/stop of measure */ + if (devpriv->ai12_startstop & START_AI_EXT) { + /* deactivate EXT trigger */ + devpriv->ai12_startstop &= ~START_AI_EXT; + if (!(devpriv->ai12_startstop & STOP_AI_EXT)) + pci9118_exttrg_del(dev, EXTTRG_AI); + + /* start pacer */ + pci9118_start_pacer(dev, devpriv->ai_do); + outl(devpriv->AdControlReg, + dev->iobase + PCI9118_ADCNTRL); + } else if (devpriv->ai12_startstop & STOP_AI_EXT) { + /* deactivate EXT trigger */ + devpriv->ai12_startstop &= ~STOP_AI_EXT; + pci9118_exttrg_del(dev, EXTTRG_AI); + + /* on next interrupt measure will stop */ + devpriv->ai_neverending = 0; + } + } } + + if (devpriv->usedma) + interrupt_pci9118_ai_dma(dev, s, adstat, intcsr, intsrc); + else + interrupt_pci9118_ai_onesample(dev, s, adstat, intcsr, intsrc); + return IRQ_HANDLED; } static int pci9118_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (trignum != devpriv->ai_inttrig_start) + if (trig_num != cmd->start_arg) return -EINVAL; devpriv->ai12_startstop &= ~START_AI_INT; @@ -1147,8 +1104,7 @@ static int pci9118_ai_inttrig(struct comedi_device *dev, outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); if (devpriv->ai_do != 3) { - start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, - devpriv->ai_divisor2); + pci9118_start_pacer(dev, devpriv->ai_do); devpriv->AdControlReg |= AdControl_SoftG; } outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); @@ -1164,7 +1120,7 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, struct pci9118_private *devpriv = dev->private; int err = 0; unsigned int flags; - int tmp; + unsigned int arg; unsigned int divisor1 = 0, divisor2 = 0; /* Step 1 : check if triggers are trivially valid */ @@ -1220,8 +1176,15 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src & (TRIG_NOW | TRIG_EXT)) + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_EXT: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_INT: + /* start_arg is the internal trigger (any value) */ + break; + } if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT)) err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); @@ -1258,8 +1221,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, - this_board->n_aichanlist); err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg, cmd->chanlist_len); @@ -1276,45 +1237,30 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->scan_begin_arg < this_board->ai_ns_min) - cmd->scan_begin_arg = this_board->ai_ns_min; - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, + &divisor1, &divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER - && cmd->convert_src == TRIG_NOW) { + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, + &divisor1, &divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER && + cmd->convert_src == TRIG_NOW) { if (cmd->convert_arg == 0) { - if (cmd->scan_begin_arg < - this_board->ai_ns_min * - (cmd->scan_end_arg + 2)) { - cmd->scan_begin_arg = - this_board->ai_ns_min * - (cmd->scan_end_arg + 2); - err++; - } + arg = this_board->ai_ns_min * + (cmd->scan_end_arg + 2); } else { - if (cmd->scan_begin_arg < - cmd->convert_arg * cmd->chanlist_len) { - cmd->scan_begin_arg = - cmd->convert_arg * - cmd->chanlist_len; - err++; - } + arg = cmd->convert_arg * cmd->chanlist_len; } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -1329,23 +1275,23 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, return 0; } -static int Compute_and_setup_dma(struct comedi_device *dev) +static int Compute_and_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int dmalen0, dmalen1, i; dmalen0 = devpriv->dmabuf_size[0]; dmalen1 = devpriv->dmabuf_size[1]; /* isn't output buff smaller that our DMA buff? */ - if (dmalen0 > (devpriv->ai_data_len)) { - dmalen0 = devpriv->ai_data_len & ~3L; /* - * align to 32bit down - */ + if (dmalen0 > s->async->prealloc_bufsz) { + /* align to 32bit down */ + dmalen0 = s->async->prealloc_bufsz & ~3L; } - if (dmalen1 > (devpriv->ai_data_len)) { - dmalen1 = devpriv->ai_data_len & ~3L; /* - * align to 32bit down - */ + if (dmalen1 > s->async->prealloc_bufsz) { + /* align to 32bit down */ + dmalen1 = s->async->prealloc_bufsz & ~3L; } /* we want wake up every scan? */ @@ -1359,8 +1305,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev) } else { /* short first DMA buffer to one scan */ dmalen0 = devpriv->ai_n_realscanlen << 1; - if (devpriv->useeoshandle) - dmalen0 += 2; if (dmalen0 < 4) { dev_info(dev->class_dev, "ERR: DMA0 buf len bug? (%d<4)\n", @@ -1379,8 +1323,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev) } else { /* short second DMA buffer to one scan */ dmalen1 = devpriv->ai_n_realscanlen << 1; - if (devpriv->useeoshandle) - dmalen1 -= 2; if (dmalen1 < 4) { dev_info(dev->class_dev, "ERR: DMA1 buf len bug? (%d<4)\n", @@ -1415,10 +1357,10 @@ static int Compute_and_setup_dma(struct comedi_device *dev) /* fits whole measure into one DMA buffer? */ if (dmalen0 > ((devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans)) { + cmd->stop_arg)) { dmalen0 = (devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans; + cmd->stop_arg; dmalen0 &= ~3L; } else { /* * fits whole measure into @@ -1426,10 +1368,10 @@ static int Compute_and_setup_dma(struct comedi_device *dev) */ if (dmalen1 > ((devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans - dmalen0)) + cmd->stop_arg - dmalen0)) dmalen1 = (devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans - dmalen0; + cmd->stop_arg - dmalen0; dmalen1 &= ~3L; } } @@ -1441,18 +1383,18 @@ static int Compute_and_setup_dma(struct comedi_device *dev) devpriv->dmabuf_use_size[1] = dmalen1; #if 0 - if (devpriv->ai_n_scanlen < this_board->half_fifo_size) { + if (cmd->scan_end_arg < this_board->half_fifo_size) { devpriv->dmabuf_panic_size[0] = - (this_board->half_fifo_size / devpriv->ai_n_scanlen + - 1) * devpriv->ai_n_scanlen * sizeof(short); + (this_board->half_fifo_size / cmd->scan_end_arg + + 1) * cmd->scan_end_arg * sizeof(short); devpriv->dmabuf_panic_size[1] = - (this_board->half_fifo_size / devpriv->ai_n_scanlen + - 1) * devpriv->ai_n_scanlen * sizeof(short); + (this_board->half_fifo_size / cmd->scan_end_arg + + 1) * cmd->scan_end_arg * sizeof(short); } else { devpriv->dmabuf_panic_size[0] = - (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[0]; + (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[0]; devpriv->dmabuf_panic_size[1] = - (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[1]; + (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[1]; } #endif @@ -1499,9 +1441,6 @@ static int pci9118_ai_docmd_sampl(struct comedi_device *dev, return -EIO; } - devpriv->int_ai_func = interrupt_pci9118_ai_onesample; - /* transfer function */ - if (devpriv->ai12_startstop) pci9118_exttrg_add(dev, EXTTRG_AI); /* activate EXT trigger */ @@ -1519,8 +1458,7 @@ static int pci9118_ai_docmd_sampl(struct comedi_device *dev, outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); if (devpriv->ai_do != 3) { - start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, - devpriv->ai_divisor2); + pci9118_start_pacer(dev, devpriv->ai_do); devpriv->AdControlReg |= AdControl_SoftG; } outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); @@ -1533,8 +1471,9 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - Compute_and_setup_dma(dev); + Compute_and_setup_dma(dev, s); switch (devpriv->ai_do) { case 1: @@ -1547,7 +1486,7 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg | AdFunction_BM | AdFunction_BS; - if (devpriv->usessh && (!devpriv->softsshdelay)) + if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay) devpriv->AdFunctionReg |= AdFunction_BSSH; outl(devpriv->ai_n_realscanlen, dev->iobase + PCI9118_BURST); break; @@ -1579,9 +1518,6 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, /* activate EXT trigger */ } - devpriv->int_ai_func = interrupt_pci9118_ai_dma; - /* transfer function */ - outl(0x02000000 | AINT_WRITE_COMPL, devpriv->iobase_a + AMCC_OP_REG_INTCSR); @@ -1589,8 +1525,7 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); if (devpriv->ai_do != 3) { - start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, - devpriv->ai_divisor2); + pci9118_start_pacer(dev, devpriv->ai_do); devpriv->AdControlReg |= AdControl_SoftG; } outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); @@ -1609,13 +1544,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai12_startstop = 0; devpriv->ai_flags = cmd->flags; - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_n_scanlen = cmd->scan_end_arg; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_data = s->async->prealloc_buf; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; devpriv->ai_add_front = 0; devpriv->ai_add_back = 0; devpriv->ai_maskerr = 0x10e; @@ -1629,31 +1557,12 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } if (cmd->start_src == TRIG_INT) { devpriv->ai12_startstop |= START_AI_INT; - devpriv->ai_inttrig_start = cmd->start_arg; s->async->inttrig = pci9118_ai_inttrig; } -#if 0 - if (cmd->stop_src == TRIG_INT) { - devpriv->ai_neverending = 1; - devpriv->ai12_startstop |= STOP_AI_INT; - } -#endif if (cmd->stop_src == TRIG_NONE) devpriv->ai_neverending = 1; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; + if (cmd->stop_src == TRIG_COUNT) devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - } - - /* use sample&hold signal? */ - if (cmd->convert_src == TRIG_NOW) - devpriv->usessh = 1; - /* yes */ - else - devpriv->usessh = 0; - /* no */ /* * use additional sample at end of every scan @@ -1661,11 +1570,10 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) */ devpriv->ai_add_front = 0; devpriv->ai_add_back = 0; - devpriv->useeoshandle = 0; if (devpriv->master) { devpriv->usedma = 1; if ((cmd->flags & TRIG_WAKE_EOS) && - (devpriv->ai_n_scanlen == 1)) { + (cmd->scan_end_arg == 1)) { if (cmd->convert_src == TRIG_NOW) devpriv->ai_add_back = 1; if (cmd->convert_src == TRIG_TIMER) { @@ -1677,13 +1585,9 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } } if ((cmd->flags & TRIG_WAKE_EOS) && - (devpriv->ai_n_scanlen & 1) && - (devpriv->ai_n_scanlen > 1)) { + (cmd->scan_end_arg & 1) && + (cmd->scan_end_arg > 1)) { if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* - * vpriv->useeoshandle=1; // change DMA transfer - * block to fit EOS on every second call - */ devpriv->usedma = 0; /* * XXX maybe can be corrected to use 16 bit DMA @@ -1703,7 +1607,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * we need software S&H signal? * It adds two samples before every scan as minimum */ - if (devpriv->usessh && devpriv->softsshdelay) { + if (cmd->convert_src == TRIG_NOW && devpriv->softsshdelay) { devpriv->ai_add_front = 2; if ((devpriv->usedma == 1) && (devpriv->ai_add_back == 1)) { /* move it to front */ @@ -1720,7 +1624,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_add_front = addchans + 1; if (devpriv->usedma == 1) if ((devpriv->ai_add_front + - devpriv->ai_n_chan + + cmd->chanlist_len + devpriv->ai_add_back) & 1) devpriv->ai_add_front++; /* round up to 32 bit */ @@ -1729,21 +1633,20 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* well, we now know what must be all added */ devpriv->ai_n_realscanlen = /* * what we must take from card in real - * to have ai_n_scanlen on output? + * to have cmd->scan_end_arg on output? */ - (devpriv->ai_add_front + devpriv->ai_n_chan + - devpriv->ai_add_back) * (devpriv->ai_n_scanlen / - devpriv->ai_n_chan); + (devpriv->ai_add_front + cmd->chanlist_len + + devpriv->ai_add_back) * (cmd->scan_end_arg / + cmd->chanlist_len); /* check and setup channel list */ - if (!check_channel_list(dev, s, devpriv->ai_n_chan, - devpriv->ai_chanlist, devpriv->ai_add_front, + if (!check_channel_list(dev, s, cmd->chanlist_len, + cmd->chanlist, devpriv->ai_add_front, devpriv->ai_add_back)) return -EINVAL; - if (!setup_channel_list(dev, s, devpriv->ai_n_chan, - devpriv->ai_chanlist, 0, devpriv->ai_add_front, - devpriv->ai_add_back, devpriv->usedma, - devpriv->useeoshandle)) + if (!setup_channel_list(dev, s, cmd->chanlist_len, + cmd->chanlist, 0, devpriv->ai_add_front, + devpriv->ai_add_back, devpriv->usedma)) return -EINVAL; /* compute timers settings */ @@ -1765,9 +1668,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_flags, devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, - &devpriv->ai_divisor2, devpriv->usessh, + &devpriv->ai_divisor2, devpriv->ai_add_front); - devpriv->ai_timer2 = cmd->convert_arg; } if ((cmd->scan_begin_src == TRIG_TIMER) && @@ -1787,10 +1689,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_flags, devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, - &devpriv->ai_divisor2, devpriv->usessh, + &devpriv->ai_divisor2, devpriv->ai_add_front); - devpriv->ai_timer1 = cmd->scan_begin_arg; - devpriv->ai_timer2 = cmd->convert_arg; } if ((cmd->scan_begin_src == TRIG_FOLLOW) @@ -1798,7 +1698,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_do = 3; } - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pci9118_start_pacer(dev, -1); /* stop pacer */ devpriv->AdControlReg = 0; /* * bipolar, S.E., use 8254, stop 8354, @@ -1824,7 +1724,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_act_scan = 0; devpriv->ai_act_dmapos = 0; s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; if (devpriv->usedma) ret = pci9118_ai_docmd_dma(dev, s); @@ -1845,7 +1744,7 @@ static int pci9118_reset(struct comedi_device *dev) /* disable interrupts source */ outl(0x30, dev->iobase + PCI9118_CNTCTRL); /* outl(0xb4, dev->iobase + PCI9118_CNTCTRL); */ - start_pacer(dev, 0, 0, 0); /* stop 8254 counters */ + pci9118_start_pacer(dev, 0); /* stop 8254 counters */ devpriv->AdControlReg = 0; outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); /* @@ -1888,7 +1787,6 @@ static int pci9118_reset(struct comedi_device *dev) * disable INT and DMA */ - devpriv->cnt0_users = 0; devpriv->exttrg_users = 0; return 0; @@ -1935,28 +1833,6 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, return NULL; } -static void pci9118_report_attach(struct comedi_device *dev, unsigned int irq) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct pci9118_private *devpriv = dev->private; - char irqbuf[30]; - char muxbuf[30]; - - if (irq) - snprintf(irqbuf, sizeof(irqbuf), "irq %u%s", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - snprintf(irqbuf, sizeof(irqbuf), "irq DISABLED"); - if (devpriv->usemux) - snprintf(muxbuf, sizeof(muxbuf), "ext mux %u chans", - devpriv->usemux); - else - snprintf(muxbuf, sizeof(muxbuf), "no ext mux"); - dev_info(dev->class_dev, "%s (pci %s, %s, %sbus master, %s) attached\n", - dev->board_name, pci_name(pcidev), irqbuf, - (devpriv->master ? "" : "no "), muxbuf); -} - static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, int master, int ext_mux, int softsshdelay, int hw_err_mask) @@ -1966,7 +1842,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct comedi_subdevice *s; int ret, pages, i; - unsigned int irq; u16 u16w; dev->board_name = this_board->name; @@ -1986,16 +1861,14 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, for (i = 0; i < 2; i++) { for (pages = 4; pages >= 0; pages--) { devpriv->dmabuf_virt[i] = - (short *)__get_free_pages(GFP_KERNEL, - pages); + (unsigned short *) + __get_free_pages(GFP_KERNEL, pages); if (devpriv->dmabuf_virt[i]) break; } if (devpriv->dmabuf_virt[i]) { devpriv->dmabuf_pages[i] = pages; devpriv->dmabuf_size[i] = PAGE_SIZE * pages; - devpriv->dmabuf_samples[i] = - devpriv->dmabuf_size[i] >> 1; devpriv->dmabuf_hw[i] = virt_to_bus((void *) devpriv->dmabuf_virt[i]); @@ -2037,12 +1910,18 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, pci_write_config_word(pcidev, PCI_COMMAND, u16w | 64); /* Enable parity check for parity error */ + if (!disable_irq && pcidev->irq) { + ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; if (devpriv->usemux) @@ -2051,11 +1930,17 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, s->n_chan = this_board->n_aichan; s->maxdata = this_board->ai_maxdata; - s->len_chanlist = this_board->n_aichanlist; s->range_table = this_board->rangelist_ai; - s->cancel = pci9118_ai_cancel; s->insn_read = pci9118_insn_read_ai; - s->munge = pci9118_ai_munge; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = this_board->n_aichanlist; + s->do_cmdtest = pci9118_ai_cmdtest; + s->do_cmd = pci9118_ai_cmd; + s->cancel = pci9118_ai_cancel; + s->munge = pci9118_ai_munge; + } s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; @@ -2074,7 +1959,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, s->maxdata = 1; s->len_chanlist = 4; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_bits = pci9118_insn_bits_di; s = &dev->subdevices[3]; @@ -2084,46 +1968,13 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, s->maxdata = 1; s->len_chanlist = 4; s->range_table = &range_digital; - s->io_bits = 0xf; /* all bits output */ s->insn_bits = pci9118_insn_bits_do; - devpriv->valid = 1; - devpriv->i8254_osc_base = 250; /* 250ns=4MHz */ devpriv->ai_maskharderr = 0x10a; /* default measure crash condition */ if (hw_err_mask) /* disable some requested */ devpriv->ai_maskharderr &= ~hw_err_mask; - switch (this_board->ai_maxdata) { - case 0xffff: - devpriv->ai16bits = 1; - break; - default: - devpriv->ai16bits = 0; - break; - } - - if (disable_irq) - irq = 0; - else - irq = pcidev->irq; - if (irq > 0) { - if (request_irq(irq, interrupt_pci9118, IRQF_SHARED, - dev->board_name, dev)) { - dev_warn(dev->class_dev, - "unable to allocate IRQ %u, DISABLING IT\n", - irq); - } else { - dev->irq = irq; - /* Enable AI commands */ - s = &dev->subdevices[0]; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = pci9118_ai_cmdtest; - s->do_cmd = pci9118_ai_cmd; - } - } - - pci9118_report_attach(dev, irq); return 0; } @@ -2140,10 +1991,9 @@ static int pci9118_attach(struct comedi_device *dev, softsshdelay = it->options[4]; hw_err_mask = it->options[5]; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; pcidev = pci9118_find_pci(dev, it); if (!pcidev) @@ -2160,10 +2010,9 @@ static int pci9118_auto_attach(struct comedi_device *dev, struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct pci9118_private *devpriv; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; dev->board_ptr = pci9118_find_boardinfo(pcidev); if (dev->board_ptr == NULL) { @@ -2188,7 +2037,7 @@ static void pci9118_detach(struct comedi_device *dev) struct pci9118_private *devpriv = dev->private; if (devpriv) { - if (devpriv->valid) + if (dev->iobase) pci9118_reset(dev); if (dev->irq) free_irq(dev->irq, dev); @@ -2222,7 +2071,7 @@ static int adl_pci9118_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = { +static const struct pci_device_id adl_pci9118_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index d187a7bf0a5..b4ea37704ea 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -73,6 +73,9 @@ If you do not specify any options, they will default to */ +#include <linux/module.h> +#include <linux/delay.h> + #include "../comedidev.h" /* address scheme (page 2.17 of the manual) */ @@ -91,24 +94,23 @@ If you do not specify any options, they will default to /* mask of the bit at STINR to check end of conversion */ #define ADQ12B_EOC 0x20 -#define TIMEOUT 20 - /* available ranges through the PGA gains */ -static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, { - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - BIP_RANGE(0.5) - } +static const struct comedi_lrange range_adq12b_ai_bipolar = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5) + } }; -static const struct comedi_lrange range_adq12b_ai_unipolar = { 4, { - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE - (0.5) - } +static const struct comedi_lrange range_adq12b_ai_unipolar = { + 4, { + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5) + } }; struct adq12b_private { @@ -116,22 +118,30 @@ struct adq12b_private { int differential; /* option 3 of comedi_config */ int last_channel; int last_range; - unsigned int digital_state; }; -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int adq12b_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + ADQ12B_STINR); + if (status & ADQ12B_EOC) + return 0; + return -EBUSY; +} static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct adq12b_private *devpriv = dev->private; - int n, i; + int n; int range, channel; unsigned char hi, lo, status; + int ret; /* change channel and range only if it is different from the previous */ range = CR_RANGE(insn->chanspec); @@ -148,20 +158,14 @@ static int adq12b_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* wait for end of conversion */ - i = 0; - do { - /* udelay(1); */ - status = inb(dev->iobase + ADQ12B_STINR); - status = status & ADQ12B_EOC; - } while (status == 0 && ++i < TIMEOUT); - /* } while (++i < 10); */ + ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0); + if (ret) + return ret; /* read data */ hi = inb(dev->iobase + ADQ12B_ADHIG); lo = inb(dev->iobase + ADQ12B_ADLOW); - /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", - channel, range, status, hi, lo); */ data[n] = (hi << 8) | lo; } @@ -183,23 +187,25 @@ static int adq12b_di_insn_bits(struct comedi_device *dev, static int adq12b_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct adq12b_private *devpriv = dev->private; - int channel; - - for (channel = 0; channel < 8; channel++) - if (((data[0] >> channel) & 0x01) != 0) - outb((((data[1] >> channel) & 0x01) << 3) | channel, - dev->iobase + ADQ12B_OUTBR); - - /* store information to retrieve when asked for reading */ - if (data[0]) { - devpriv->digital_state &= ~data[0]; - devpriv->digital_state |= (data[0] & data[1]); + unsigned int mask; + unsigned int chan; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + for (chan = 0; chan < 8; chan++) { + if ((mask >> chan) & 0x01) { + val = (s->state >> chan) & 0x01; + outb((val << 3) | chan, + dev->iobase + ADQ12B_OUTBR); + } + } } - data[1] = devpriv->digital_state; + data[1] = s->state; return insn->n; } @@ -214,14 +220,12 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->unipolar = it->options[1]; devpriv->differential = it->options[2]; - devpriv->digital_state = 0; /* * initialize channel and range to -1 so we make sure we * always write at least once to the CTREG in the instruction diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index f847bbc175e..602b7a1e40e 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/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -50,10 +51,6 @@ Configuration options: #include "8253.h" #include "amcc_s5933.h" -#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control - * correct channel number on every 12 bit - * sample */ - /* hardware types of the cards */ #define TYPE_PCI171X 0 #define TYPE_PCI1713 2 @@ -72,6 +69,9 @@ Configuration options: #define PCI171x_DAREF 14 /* W: D/A reference control */ #define PCI171x_DI 16 /* R: digi inputs */ #define PCI171x_DO 16 /* R: digi inputs */ + +#define PCI171X_TIMER_BASE 0x18 + #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */ #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */ #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */ @@ -114,65 +114,70 @@ Configuration options: /* D/A synchronized control (PCI1720_SYNCONT) */ #define Syncont_SC0 1 /* set synchronous output mode */ -static const struct comedi_lrange range_pci1710_3 = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(10), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } +static const struct comedi_lrange range_pci1710_3 = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(10), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 }; -static const struct comedi_lrange range_pci1710hg = { 12, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } +static const struct comedi_lrange range_pci1710hg = { + 12, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13 }; -static const struct comedi_lrange range_pci17x1 = { 5, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625) - } +static const struct comedi_lrange range_pci17x1 = { + 5, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 }; -static const struct comedi_lrange range_pci1720 = { 4, { - UNI_RANGE(5), - UNI_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(10) - } +static const struct comedi_lrange range_pci1720 = { + 4, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10) + } }; -static const struct comedi_lrange range_pci171x_da = { 2, { - UNI_RANGE(5), - UNI_RANGE(10), - } +static const struct comedi_lrange range_pci171x_da = { + 2, { + UNI_RANGE(5), + UNI_RANGE(10) + } }; enum pci1710_boardid { @@ -292,31 +297,19 @@ static const struct boardtype boardtypes[] = { }; struct pci1710_private { - char neverending_ai; /* we do unlimited AI */ unsigned int CntrlReg; /* Control register */ - unsigned int i8254_osc_base; /* frequence of onboard oscilator */ - unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chan; /* actual position in actual scan */ - unsigned int ai_buf_ptr; /* data buffer ptr in samples */ - unsigned char ai_eos; /* 1=EOS wake up */ unsigned char ai_et; unsigned int ai_et_CntrlReg; unsigned int ai_et_MuxVal; - unsigned int ai_et_div1, ai_et_div2; + unsigned int next_divisor1; + unsigned int next_divisor2; + unsigned int divisor1; + unsigned int divisor2; unsigned int act_chanlist[32]; /* list of scanned channel */ - unsigned char act_chanlist_len; /* len of scanlist */ - unsigned char act_chanlist_pos; /* actual position in MUX list */ + unsigned char saved_seglen; /* len of the non-repeating chanlist */ unsigned char da_ranges; /* copy of D/A outpit range register */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; - short ao_data[4]; /* data output buffer */ + unsigned short ao_data[4]; /* data output buffer */ unsigned int cnt0_write_wait; /* after a write, wait for update of the * internal state */ }; @@ -329,62 +322,90 @@ static const unsigned int muxonechan[] = { 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f }; -/* -============================================================================== - Check if channel list from user is built correctly - If it's ok, then program scan/gain logic. - This works for all cards. -*/ -static int check_channel_list(struct comedi_device *dev, +static int pci171x_ai_dropout(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) + unsigned int chan, + unsigned int val) +{ + const struct boardtype *board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + + if (board->cardtype != TYPE_PCI1713) { + if ((val & 0xf000) != devpriv->act_chanlist[chan]) { + dev_err(dev->class_dev, + "A/D data droput: received from channel %d, expected %d\n", + (val >> 12) & 0xf, + (devpriv->act_chanlist[chan] >> 12) & 0xf); + return -ENODATA; + } + } + return 0; +} + +static int pci171x_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { + struct pci1710_private *devpriv = dev->private; + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int last_aref = CR_AREF(cmd->chanlist[0]); + unsigned int next_chan = (chan0 + 1) % s->n_chan; unsigned int chansegment[32]; - unsigned int i, nowmustbechan, seglen, segpos; + unsigned int seglen; + int i; - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - comedi_error(dev, "range/channel list is empty!"); + if (cmd->chanlist_len == 1) { + devpriv->saved_seglen = cmd->chanlist_len; return 0; } - if (n_chan == 1) - return 1; /* seglen=1 */ + /* first channel is always ok */ + chansegment[0] = cmd->chanlist[0]; - chansegment[0] = chanlist[0]; /* first channel is every time ok */ - for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { - if (chanlist[0] == chanlist[i]) + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (cmd->chanlist[0] == cmd->chanlist[i]) break; /* we detected a loop, stop */ - if ((CR_CHAN(chanlist[i]) & 1) && - (CR_AREF(chanlist[i]) == AREF_DIFF)) { - comedi_error(dev, "Odd channel cannot be differential input!\n"); - return 0; + + if (aref == AREF_DIFF && (chan & 1)) { + dev_err(dev->class_dev, + "Odd channel cannot be differential input!\n"); + return -EINVAL; } - nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; - if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) - nowmustbechan = (nowmustbechan + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { - printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", - i, CR_CHAN(chanlist[i]), nowmustbechan, - CR_CHAN(chanlist[0])); - return 0; + + if (last_aref == AREF_DIFF) + next_chan = (next_chan + 1) % s->n_chan; + if (chan != next_chan) { + dev_err(dev->class_dev, + "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, chan, next_chan, chan0); + return -EINVAL; } - chansegment[i] = chanlist[i]; /* next correct channel in list */ - } - for (i = 0, segpos = 0; i < n_chan; i++) { - if (chanlist[i] != chansegment[i % seglen]) { - printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", - i, CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); - return 0; + /* next correct channel in list */ + chansegment[i] = cmd->chanlist[i]; + last_aref = aref; + } + seglen = i; + + for (i = 0; i < cmd->chanlist_len; i++) { + if (cmd->chanlist[i] != chansegment[i % seglen]) { + dev_err(dev->class_dev, + "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(cmd->chanlist[i % seglen]), + CR_RANGE(cmd->chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); + return -EINVAL; } } - return seglen; + devpriv->saved_seglen = seglen; + + return 0; } static void setup_channel_list(struct comedi_device *dev, @@ -396,9 +417,6 @@ static void setup_channel_list(struct comedi_device *dev, struct pci1710_private *devpriv = dev->private; unsigned int i, range, chanprog; - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - for (i = 0; i < seglen; i++) { /* store range list to card */ chanprog = muxonechan[CR_CHAN(chanlist[i])]; outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ @@ -406,17 +424,13 @@ static void setup_channel_list(struct comedi_device *dev, if (CR_AREF(chanlist[i]) == AREF_DIFF) range |= 0x0020; outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ -#ifdef PCI171x_PARANOIDCHECK devpriv->act_chanlist[i] = (CR_CHAN(chanlist[i]) << 12) & 0xf000; -#endif } -#ifdef PCI171x_PARANOIDCHECK for ( ; i < n_chan; i++) { /* store remainder of channel list */ devpriv->act_chanlist[i] = (CR_CHAN(chanlist[i]) << 12) & 0xf000; } -#endif devpriv->ai_et_MuxVal = CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); @@ -424,19 +438,27 @@ static void setup_channel_list(struct comedi_device *dev, outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); } -/* -============================================================================== -*/ +static int pci171x_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI171x_STATUS); + if ((status & Status_FE) == 0) + return 0; + return -EBUSY; +} + static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; - int n, timeout; -#ifdef PCI171x_PARANOIDCHECK - const struct boardtype *this_board = comedi_board(dev); - unsigned int idata; -#endif + unsigned int chan = CR_CHAN(insn->chanspec); + int ret = 0; + int i; devpriv->CntrlReg &= Control_CNT0; devpriv->CntrlReg |= Control_SW; /* set software trigger */ @@ -446,39 +468,27 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, setup_channel_list(dev, s, &insn->chanspec, 1, 1); - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { + unsigned int val; + outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ - /* udelay(1); */ - timeout = 100; - while (timeout--) { - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE)) - goto conv_finish; - } - comedi_error(dev, "A/D insn timeout"); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - data[n] = 0; - return -ETIME; - -conv_finish: -#ifdef PCI171x_PARANOIDCHECK - idata = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((idata & 0xf000) != devpriv->act_chanlist[0]) { - comedi_error(dev, "A/D insn data droput!"); - return -ETIME; - } - data[n] = idata & 0x0fff; -#else - data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff; -#endif + ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); + if (ret) + break; + + val = inw(dev->iobase + PCI171x_AD_DATA); + ret = pci171x_ai_dropout(dev, s, chan, val); + if (ret) + break; + + data[i] = val & s->maxdata; } outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - return n; + return ret ? ret : insn->n; } /* @@ -489,6 +499,7 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, chan, range, ofs; chan = CR_CHAN(insn->chanspec); @@ -504,11 +515,14 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); ofs = PCI171x_DA1; } + val = devpriv->ao_data[chan]; - for (n = 0; n < insn->n; n++) - outw(data[n], dev->iobase + ofs); + for (n = 0; n < insn->n; n++) { + val = data[n]; + outw(val, dev->iobase + ofs); + } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; @@ -543,37 +557,31 @@ static int pci171x_insn_bits_di(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pci171x_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI171x_DO); - } + data[1] = s->state; return insn->n; } -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static void pci171x_start_pacer(struct comedi_device *dev, + bool load_counters) { - outw(0xb4, dev->iobase + PCI171x_CNTCTRL); - outw(0x74, dev->iobase + PCI171x_CNTCTRL); - - if (mode == 1) { - outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2); - outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2); - outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1); - outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1); + struct pci1710_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE; + + i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); + + if (load_counters) { + i8254_write(timer_base, 1, 2, devpriv->divisor2); + i8254_write(timer_base, 1, 1, devpriv->divisor1); } } @@ -678,6 +686,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, rangereg, chan; chan = CR_CHAN(insn->chanspec); @@ -687,13 +696,15 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, outb(rangereg, dev->iobase + PCI1720_RANGE); devpriv->da_ranges = rangereg; } + val = devpriv->ao_data[chan]; for (n = 0; n < insn->n; n++) { - outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1)); + val = data[n]; + outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; } @@ -713,101 +724,73 @@ static int pci171x_ai_cancel(struct comedi_device *dev, devpriv->CntrlReg |= Control_SW; outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ - start_pacer(dev, -1, 0, 0); + pci171x_start_pacer(dev, false); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); break; } - devpriv->ai_do = 0; devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; - devpriv->neverending_ai = 0; return 0; } -/* -============================================================================== -*/ -static void interrupt_pci1710_every_sample(void *d) +static void pci1710_handle_every_sample(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pci1710_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - int m; -#ifdef PCI171x_PARANOIDCHECK - const struct boardtype *this_board = comedi_board(dev); - short sampl; -#endif + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int status; + unsigned int val; + int ret; - m = inw(dev->iobase + PCI171x_STATUS); - if (m & Status_FE) { - printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m); - pci171x_ai_cancel(dev, s); + status = inw(dev->iobase + PCI171x_STATUS); + if (status & Status_FE) { + dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } - if (m & Status_FF) { - printk - ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", - dev->minor, m); - pci171x_ai_cancel(dev, s); + if (status & Status_FF) { + dev_dbg(dev->class_dev, + "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { -#ifdef PCI171x_PARANOIDCHECK - sampl = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((sampl & 0xf000) != - devpriv->act_chanlist[s->async->cur_chan]) { - printk - ("comedi: A/D data dropout: received data from channel %d, expected %d!\n", - (sampl & 0xf000) >> 12, - (devpriv-> - act_chanlist[s-> - async->cur_chan] & 0xf000) >> - 12); - pci171x_ai_cancel(dev, s); - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return; - } - comedi_buf_put(s->async, sampl & 0x0fff); -#else - comedi_buf_put(s->async, - inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); -#endif - ++s->async->cur_chan; + val = inw(dev->iobase + PCI171x_AD_DATA); + ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); + if (ret) { + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + break; + } - if (s->async->cur_chan >= devpriv->ai_n_chan) + comedi_buf_put(s, val & s->maxdata); + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) s->async->cur_chan = 0; if (s->async->cur_chan == 0) { /* one scan done */ devpriv->ai_act_scan++; - if ((!devpriv->neverending_ai) && - (devpriv->ai_act_scan >= devpriv->ai_scans)) { + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { /* all data sampled */ - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; + break; } } } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -817,78 +800,57 @@ static int move_block_from_fifo(struct comedi_device *dev, struct comedi_subdevice *s, int n, int turn) { struct pci1710_private *devpriv = dev->private; - int i, j; -#ifdef PCI171x_PARANOIDCHECK - const struct boardtype *this_board = comedi_board(dev); - int sampl; -#endif + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int val; + int ret; + int i; - j = s->async->cur_chan; for (i = 0; i < n; i++) { -#ifdef PCI171x_PARANOIDCHECK - sampl = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((sampl & 0xf000) != devpriv->act_chanlist[j]) { - printk - ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n", - dev->minor, (sampl & 0xf000) >> 12, - (devpriv->act_chanlist[j] & 0xf000) >> 12, - i, j, devpriv->ai_act_scan, n, turn, - sampl); - pci171x_ai_cancel(dev, s); - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return 1; - } - comedi_buf_put(s->async, sampl & 0x0fff); -#else - comedi_buf_put(s->async, - inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); -#endif - j++; - if (j >= devpriv->ai_n_chan) { - j = 0; + val = inw(dev->iobase + PCI171x_AD_DATA); + + ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); + if (ret) { + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return ret; + } + + comedi_buf_put(s, val & s->maxdata); + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; devpriv->ai_act_scan++; } } - s->async->cur_chan = j; return 0; } -/* -============================================================================== -*/ -static void interrupt_pci1710_half_fifo(void *d) +static void pci1710_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; const struct boardtype *this_board = comedi_board(dev); struct pci1710_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_cmd *cmd = &s->async->cmd; int m, samplesinbuf; m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { - printk("comedi%d: A/D FIFO not half full! (%4x)\n", - dev->minor, m); - pci171x_ai_cancel(dev, s); + dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (m & Status_FF) { - printk - ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", - dev->minor, m); - pci171x_ai_cancel(dev, s); + dev_dbg(dev->class_dev, + "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } samplesinbuf = this_board->fifo_half_size; - if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) { - m = devpriv->ai_data_len / sizeof(short); + if (samplesinbuf * sizeof(short) >= s->async->prealloc_bufsz) { + m = s->async->prealloc_bufsz / sizeof(short); if (move_block_from_fifo(dev, s, m, 0)) return; samplesinbuf -= m; @@ -899,17 +861,16 @@ static void interrupt_pci1710_half_fifo(void *d) return; } - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data - sampled */ - pci171x_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + cfc_handle_events(dev, s); + return; + } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -919,9 +880,15 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) { struct comedi_device *dev = d; struct pci1710_private *devpriv = dev->private; + struct comedi_subdevice *s; + struct comedi_cmd *cmd; if (!dev->attached) /* is device attached? */ return IRQ_NONE; /* no, exit */ + + s = dev->read_subdev; + cmd = &s->async->cmd; + /* is this interrupt from our board? */ if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) return IRQ_NONE; /* no, exit */ @@ -936,94 +903,59 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) outb(0, dev->iobase + PCI171x_CLRINT); outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - /* start pacer */ - start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2); + pci171x_start_pacer(dev, true); return IRQ_HANDLED; } - if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */ - interrupt_pci1710_every_sample(d); - } else { - interrupt_pci1710_half_fifo(d); - } + + if (cmd->flags & TRIG_WAKE_EOS) + pci1710_handle_every_sample(dev, s); + else + pci1710_handle_fifo(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ -static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) +static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct boardtype *this_board = comedi_board(dev); struct pci1710_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0; - unsigned int seglen; + struct comedi_cmd *cmd = &s->async->cmd; - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pci171x_start_pacer(dev, false); - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); + setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len, + devpriv->saved_seglen); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - devpriv->ai_do = mode; - devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; - devpriv->neverending_ai = 0; devpriv->CntrlReg &= Control_CNT0; - /* don't we want wake up every scan? devpriv->ai_eos=1; */ - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { - devpriv->ai_eos = 1; - } else { + if ((cmd->flags & TRIG_WAKE_EOS) == 0) devpriv->CntrlReg |= Control_ONEFH; - devpriv->ai_eos = 0; - } - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; - /* well, user want neverending */ - else - devpriv->neverending_ai = 0; + devpriv->divisor1 = devpriv->next_divisor1; + devpriv->divisor2 = devpriv->next_divisor2; - switch (mode) { - case 1: - case 2: - if (devpriv->ai_timer1 < this_board->ai_ns_min) - devpriv->ai_timer1 = this_board->ai_ns_min; + if (cmd->convert_src == TRIG_TIMER) { devpriv->CntrlReg |= Control_PACER | Control_IRQEN; - if (mode == 2) { + if (cmd->start_src == TRIG_EXT) { devpriv->ai_et_CntrlReg = devpriv->CntrlReg; devpriv->CntrlReg &= ~(Control_PACER | Control_ONEFH | Control_GATE); devpriv->CntrlReg |= Control_EXT; devpriv->ai_et = 1; - } else { + } else { /* TRIG_NOW */ devpriv->ai_et = 0; } - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &devpriv->ai_timer1, - devpriv->ai_flags & TRIG_ROUND_MASK); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - if (mode != 2) { - /* start pacer */ - start_pacer(dev, mode, divisor1, divisor2); - } else { - devpriv->ai_et_div1 = divisor1; - devpriv->ai_et_div2 = divisor2; - } - break; - case 3: + + if (cmd->start_src == TRIG_NOW) + pci171x_start_pacer(dev, true); + } else { /* TRIG_EXT */ devpriv->CntrlReg |= Control_EXT | Control_IRQEN; outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - break; } return 0; @@ -1039,8 +971,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, const struct boardtype *this_board = comedi_board(dev); struct pci1710_private *devpriv = dev->private; int err = 0; - int tmp; - unsigned int divisor1 = 0, divisor2 = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -1088,65 +1019,25 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->next_divisor1, + &devpriv->next_divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* step 5: complain about special chanlist considerations */ - - if (cmd->chanlist) { - if (!check_channel_list(dev, s, cmd->chanlist, - cmd->chanlist_len)) - return 5; /* incorrect channels list */ - } - - return 0; -} - -/* -============================================================================== -*/ -static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct pci1710_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; + /* Step 5: check channel list */ - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; + err |= pci171x_ai_check_chanlist(dev, s, cmd); - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans = cmd->stop_arg; - else - devpriv->ai_scans = 0; - - - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */ - devpriv->ai_timer1 = cmd->convert_arg; - return pci171x_ai_docmd_and_mode(cmd->start_src == - TRIG_EXT ? 2 : 1, dev, - s); - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pci171x_ai_docmd_and_mode(3, dev, s); - } - } + if (err) + return 5; - return -1; + return 0; } /* @@ -1162,7 +1053,7 @@ static int pci171x_reset(struct comedi_device *dev) outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ - start_pacer(dev, -1, 0, 0); /* stop 8254 */ + pci171x_start_pacer(dev, false); devpriv->da_ranges = 0; if (this_board->n_aochan) { outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */ @@ -1233,10 +1124,9 @@ static int pci1710_auto_attach(struct comedi_device *dev, dev->board_ptr = this_board; dev->board_name = this_board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -1272,23 +1162,22 @@ static int pci1710_auto_attach(struct comedi_device *dev, if (this_board->n_aichan) { s = &dev->subdevices[subdev]; - dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; if (this_board->n_aichand) s->subdev_flags |= SDF_DIFF; s->n_chan = this_board->n_aichan; s->maxdata = this_board->ai_maxdata; - s->len_chanlist = this_board->n_aichan; s->range_table = this_board->rangelist_ai; - s->cancel = pci171x_ai_cancel; s->insn_read = pci171x_insn_read_ai; if (dev->irq) { + dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; s->do_cmdtest = pci171x_ai_cmdtest; s->do_cmd = pci171x_ai_cmd; + s->cancel = pci171x_ai_cancel; } - devpriv->i8254_osc_base = 100; /* 100ns=10MHz */ subdev++; } @@ -1320,7 +1209,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = this_board->n_dichan; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_bits = pci171x_insn_bits_di; subdev++; } @@ -1333,9 +1221,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = this_board->n_dochan; s->range_table = &range_digital; - /* all bits output */ - s->io_bits = (1 << this_board->n_dochan) - 1; - s->state = 0; s->insn_bits = pci171x_insn_bits_do; subdev++; } @@ -1354,9 +1239,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, subdev++; } - dev_info(dev->class_dev, "%s attached, irq %sabled\n", - dev->board_name, dev->irq ? "en" : "dis"); - return 0; } @@ -1383,7 +1265,7 @@ static int adv_pci1710_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = { +static const struct pci_device_id adv_pci1710_pci_table[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050), diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 8430a27ec1b..07b107d1ab3 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -43,6 +43,7 @@ TODO: 3. Implement calibration. */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -104,7 +105,7 @@ TODO: struct pci1723_private { unsigned char da_range[8]; /* D/A output range for each channel */ - short ao_data[8]; /* data output buffer */ + unsigned short ao_data[8]; /* data output buffer */ }; /* @@ -179,53 +180,41 @@ static int pci1723_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int mask; - unsigned int bits; - unsigned short dio_mode; + unsigned short mode; + int ret; - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x00FF) - bits = 0x00FF; + if (chan < 8) + mask = 0x00ff; else - bits = 0xFF00; + mask = 0xff00; - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; /* update hardware DIO mode */ - dio_mode = 0x0000; /* low byte output, high byte output */ - if ((s->io_bits & 0x00FF) == 0) - dio_mode |= 0x0001; /* low byte input */ - if ((s->io_bits & 0xFF00) == 0) - dio_mode |= 0x0002; /* high byte input */ - outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET); - return 1; + mode = 0x0000; /* assume output */ + if (!(s->io_bits & 0x00ff)) + mode |= 0x0001; /* low byte input */ + if (!(s->io_bits & 0xff00)) + mode |= 0x0002; /* high byte input */ + outw(mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET); + + return insn->n; } -/* - digital i/o bits read/write -*/ static int pci1723_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI1723_WRITE_DIGITAL_OUTPUT_CMD); - } + data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); + return insn->n; } @@ -237,10 +226,9 @@ static int pci1723_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -292,8 +280,6 @@ static int pci1723_auto_attach(struct comedi_device *dev, pci1723_reset(dev); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } @@ -318,7 +304,7 @@ static int adv_pci1723_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = { +static const struct pci_device_id adv_pci1723_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c index da7462e01fa..af670acb03d 100644 --- a/drivers/staging/comedi/drivers/adv_pci1724.c +++ b/drivers/staging/comedi/drivers/adv_pci1724.c @@ -52,6 +52,8 @@ supported PCI devices are configured as comedi devices automatically. */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/pci.h> #include "../comedidev.h" @@ -114,8 +116,8 @@ enum board_id_contents { BOARD_ID_MASK = 0xf }; -static const struct comedi_lrange ao_ranges_1724 = { 4, - { +static const struct comedi_lrange ao_ranges_1724 = { + 4, { BIP_RANGE(10), RANGE_mA(0, 20), RANGE_mA(4, 20), @@ -123,10 +125,6 @@ static const struct comedi_lrange ao_ranges_1724 = { 4, } }; -static const struct comedi_lrange *const ao_range_list_1724[NUM_AO_CHANNELS] = { - [0 ... NUM_AO_CHANNELS - 1] = &ao_ranges_1724, -}; - /* this structure is for data unique to this hardware driver. */ struct adv_pci1724_private { int ao_value[NUM_AO_CHANNELS]; @@ -306,7 +304,7 @@ static int setup_subdevices(struct comedi_device *dev) s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; s->n_chan = NUM_AO_CHANNELS; s->maxdata = 0x3fff; - s->range_table_list = ao_range_list_1724; + s->range_table = &ao_ranges_1724; s->insn_read = ao_readback_insn; s->insn_write = ao_winsn; @@ -340,10 +338,9 @@ static int adv_pci1724_auto_attach(struct comedi_device *dev, int retval; unsigned int board_id; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* init software copies of output values to indicate we don't know * what the output value is since it has never been written. */ @@ -384,7 +381,7 @@ static int adv_pci1724_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(adv_pci1724_pci_table) = { +static const struct pci_device_id adv_pci1724_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1724) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index 8e6ec75bd29..2d966a87f2e 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -29,6 +29,7 @@ Configuration options: */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> @@ -447,45 +448,39 @@ static int pci_dio_insn_bits_di_w(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pci_dio_insn_bits_do_b(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { for (i = 0; i < d->regs; i++) outb((s->state >> (8 * i)) & 0xff, dev->iobase + d->addr + i); } + data[1] = s->state; return insn->n; } -/* -============================================================================== -*/ static int pci_dio_insn_bits_do_w(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { for (i = 0; i < d->regs; i++) outw((s->state >> (16 * i)) & 0xffff, dev->iobase + d->addr + 2 * i); } + data[1] = s->state; return insn->n; @@ -640,12 +635,10 @@ static int pci1760_insn_bits_di(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pci1760_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { int ret; unsigned char omb[4] = { @@ -656,14 +649,13 @@ static int pci1760_insn_bits_do(struct comedi_device *dev, }; unsigned char imb[4]; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { omb[0] = s->state; ret = pci1760_mbxrequest(dev, omb, imb); if (!ret) return ret; } + data[1] = s->state; return insn->n; @@ -1107,10 +1099,9 @@ static int pci_dio_auto_attach(struct comedi_device *dev, dev->board_ptr = this_board; dev->board_name = this_board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -1139,10 +1130,12 @@ static int pci_dio_auto_attach(struct comedi_device *dev, for (i = 0; i < MAX_DIO_SUBDEVG; i++) for (j = 0; j < this_board->sdio[i].regs; j++) { s = &dev->subdevices[subdev]; - subdev_8255_init(dev, s, NULL, - dev->iobase + - this_board->sdio[i].addr + - SIZE_8255 * j); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + + this_board->sdio[i].addr + + SIZE_8255 * j); + if (ret) + return ret; subdev++; } @@ -1197,7 +1190,7 @@ static int adv_pci_dio_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype); } -static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = { +static const struct pci_device_id adv_pci_dio_pci_table[] = { { PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 }, { PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 }, { PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 }, diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index 279dfe8951f..324746b1493 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -35,8 +35,8 @@ Notes: */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include "8255.h" /* @@ -101,14 +101,27 @@ struct aio12_8_private { unsigned int ao_readback[4]; }; +static int aio_aio12_8_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + AIO12_8_STATUS_REG); + if (status & AIO12_8_STATUS_ADC_EOC) + return 0; + return -EBUSY; +} + static int aio_aio12_8_ai_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val; unsigned char control; + int ret; int n; /* @@ -122,20 +135,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, inb(dev->iobase + AIO12_8_STATUS_REG); for (n = 0; n < insn->n; n++) { - int timeout = 5; - /* Setup and start conversion */ outb(control, dev->iobase + AIO12_8_ADC_REG); /* Wait for conversion to complete */ - do { - val = inb(dev->iobase + AIO12_8_STATUS_REG); - timeout--; - if (timeout == 0) { - dev_err(dev->class_dev, "ADC timeout\n"); - return -ETIMEDOUT; - } - } while (!(val & AIO12_8_STATUS_ADC_EOC)); + ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0); + if (ret) + return ret; data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; } @@ -181,13 +187,12 @@ static int aio_aio12_8_ao_write(struct comedi_device *dev, } static const struct comedi_lrange range_aio_aio12_8 = { - 4, - { - UNI_RANGE(5), - BIP_RANGE(5), - UNI_RANGE(10), - BIP_RANGE(10), - } + 4, { + UNI_RANGE(5), + BIP_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(10) + } }; static int aio_aio12_8_attach(struct comedi_device *dev, @@ -202,10 +207,9 @@ static int aio_aio12_8_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_alloc_subdevices(dev, 4); if (ret) @@ -249,9 +253,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev, /* 8254 counter/timer subdevice */ s->type = COMEDI_SUBD_UNUSED; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 029834d0ff1..781104aa533 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -30,8 +30,8 @@ Configuration Options: */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #define AIO_IIRO_16_SIZE 0x08 #define AIO_IIRO_16_RELAY_0_7 0x00 @@ -45,9 +45,7 @@ static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + if (comedi_dio_update_state(s, data)) { outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7); outb((s->state >> 8) & 0xff, dev->iobase + AIO_IIRO_16_RELAY_8_15); @@ -100,7 +98,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = aio_iiro_16_dio_insn_bits_read; - return 1; + return 0; } static struct comedi_driver aio_iiro_16_driver = { diff --git a/drivers/staging/comedi/drivers/amcc_s5933.h b/drivers/staging/comedi/drivers/amcc_s5933.h index b810d5f3d97..2ba73644461 100644 --- a/drivers/staging/comedi/drivers/amcc_s5933.h +++ b/drivers/staging/comedi/drivers/amcc_s5933.h @@ -145,12 +145,12 @@ #define AINT_READ_COMPL 0x00008000 #define AINT_WRITE_COMPL 0x00004000 -#define AINT_OMB_ENABLE 0x00001000 -#define AINT_OMB_SELECT 0x00000c00 +#define AINT_OMB_ENABLE 0x00001000 +#define AINT_OMB_SELECT 0x00000c00 #define AINT_OMB_BYTE 0x00000300 -#define AINT_IMB_ENABLE 0x00000010 -#define AINT_IMB_SELECT 0x0000000c +#define AINT_IMB_ENABLE 0x00000010 +#define AINT_IMB_SELECT 0x0000000c #define AINT_IMB_BYTE 0x00000003 /* these are bits from various different registers, needs cleanup XXX */ diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index e2478105ac1..dc1dee79fc1 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -192,8 +192,7 @@ * order they appear in the channel list. */ -#include <linux/slab.h> - +#include <linux/module.h> #include "../comedidev.h" #include "amplc_dio200.h" @@ -272,10 +271,9 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) irq = it->options[1]; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_request_region(dev, it->options[0], thisboard->mainsize); if (ret) diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index 649fc69724f..3edaa4028da 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -19,8 +19,8 @@ GNU General Public License for more details. */ +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include "../comedidev.h" @@ -130,7 +130,6 @@ struct dio200_subdev_intr { unsigned int enabled_isns; unsigned int stopcount; bool active:1; - bool continuous:1; }; static inline const struct dio200_layout * @@ -259,7 +258,7 @@ static int dio200_start_intr(struct comedi_device *dev, struct comedi_cmd *cmd = &s->async->cmd; int retval = 0; - if (!subpriv->continuous && subpriv->stopcount == 0) { + if (cmd->stop_src == TRIG_COUNT && subpriv->stopcount == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; subpriv->active = false; @@ -281,22 +280,18 @@ static int dio200_start_intr(struct comedi_device *dev, return retval; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int dio200_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { - struct dio200_subdev_intr *subpriv; + struct dio200_subdev_intr *subpriv = s->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; - subpriv = s->private; - spin_lock_irqsave(&subpriv->spinlock, flags); s->async->inttrig = NULL; if (subpriv->active) @@ -315,18 +310,18 @@ static void dio200_read_scan_intr(struct comedi_device *dev, unsigned int triggered) { struct dio200_subdev_intr *subpriv = s->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned short val; - unsigned int n, ch, len; + unsigned int n, ch; val = 0; - len = s->async->cmd.chanlist_len; - for (n = 0; n < len; n++) { - ch = CR_CHAN(s->async->cmd.chanlist[n]); + for (n = 0; n < cmd->chanlist_len; n++) { + ch = CR_CHAN(cmd->chanlist[n]); if (triggered & (1U << ch)) val |= (1U << n); } /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, val)) { + if (comedi_buf_put(s, val)) { s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); } else { /* Error! Stop acquisition. */ @@ -336,8 +331,7 @@ static void dio200_read_scan_intr(struct comedi_device *dev, } /* Check for end of acquisition. */ - if (!subpriv->continuous) { - /* stop_src == TRIG_COUNT */ + if (cmd->stop_src == TRIG_COUNT) { if (subpriv->stopcount > 0) { subpriv->stopcount--; if (subpriv->stopcount == 0) { @@ -513,31 +507,19 @@ static int dio200_subdev_intr_cmd(struct comedi_device *dev, int event = 0; spin_lock_irqsave(&subpriv->spinlock, flags); - subpriv->active = 1; + subpriv->active = true; /* Set up end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - subpriv->continuous = false; + if (cmd->stop_src == TRIG_COUNT) subpriv->stopcount = cmd->stop_arg; - break; - default: - /* TRIG_NONE */ - subpriv->continuous = true; + else /* TRIG_NONE */ subpriv->stopcount = 0; - break; - } - /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = dio200_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = dio200_start_intr(dev, s); - break; - } + spin_unlock_irqrestore(&subpriv->spinlock, flags); if (event) @@ -829,7 +811,7 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s, spin_lock_irqsave(&subpriv->spinlock, flags); switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: - if (data[1] > (I8254_MODE5 | I8254_BINARY)) + if (data[1] > (I8254_MODE5 | I8254_BCD)) ret = -EINVAL; else dio200_subdev_8254_set_mode(dev, s, chan, data[1]); @@ -941,31 +923,34 @@ static void dio200_subdev_8255_set_dir(struct comedi_device *dev, dio200_write8(dev, subpriv->ofs + 3, config); } -/* - * Handle 'insn_bits' for an '8255' DIO subdevice. - */ static int dio200_subdev_8255_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct dio200_subdev_8255 *subpriv = s->private; + unsigned int mask; + unsigned int val; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - if (data[0] & 0xff) + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) dio200_write8(dev, subpriv->ofs, s->state & 0xff); - if (data[0] & 0xff00) + if (mask & 0xff00) dio200_write8(dev, subpriv->ofs + 1, (s->state >> 8) & 0xff); - if (data[0] & 0xff0000) + if (mask & 0xff0000) dio200_write8(dev, subpriv->ofs + 2, (s->state >> 16) & 0xff); } - data[1] = dio200_read8(dev, subpriv->ofs); - data[1] |= dio200_read8(dev, subpriv->ofs + 1) << 8; - data[1] |= dio200_read8(dev, subpriv->ofs + 2) << 16; - return 2; + + val = dio200_read8(dev, subpriv->ofs); + val |= dio200_read8(dev, subpriv->ofs + 1) << 8; + val |= dio200_read8(dev, subpriv->ofs + 2) << 16; + + data[1] = val; + + return insn->n; } /* @@ -976,34 +961,26 @@ static int dio200_subdev_8255_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int mask; - unsigned int bits; - - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x0000ff) - bits = 0x0000ff; - else if (mask & 0x00ff00) - bits = 0x00ff00; - else if (mask & 0x0f0000) - bits = 0x0f0000; + int ret; + + if (chan < 8) + mask = 0x0000ff; + else if (chan < 16) + mask = 0x00ff00; + else if (chan < 20) + mask = 0x0f0000; else - bits = 0xf00000; - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + mask = 0xf00000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + dio200_subdev_8255_set_dir(dev, s); - return 1; + + return insn->n; } /* @@ -1030,8 +1007,6 @@ static int dio200_subdev_8255_init(struct comedi_device *dev, s->maxdata = 1; s->insn_bits = dio200_subdev_8255_bits; s->insn_config = dio200_subdev_8255_config; - s->state = 0; - s->io_bits = 0; dio200_subdev_8255_set_dir(dev, s); return 0; } @@ -1215,7 +1190,7 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq, "warning! irq %u unavailable!\n", irq); } } - dev_info(dev->class_dev, "attached\n"); + return 0; } EXPORT_SYMBOL_GPL(amplc_dio200_common_attach); diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c index d7d9f5cc3ab..e0367380b37 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_pci.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c @@ -220,9 +220,9 @@ * order they appear in the channel list. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include "../comedidev.h" @@ -380,10 +380,9 @@ static int dio200_pci_auto_attach(struct comedi_device *dev, dev_info(dev->class_dev, "%s: attach pci %s (%s)\n", dev->driver->driver_name, pci_name(pci_dev), dev->board_name); - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -440,7 +439,7 @@ static struct comedi_driver dio200_pci_comedi_driver = { .detach = dio200_pci_detach, }; -static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = { +static const struct pci_device_id dio200_pci_table[] = { { PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215), pci215_model diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 4e889b82cbf..c9a96ad0055 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -47,6 +47,7 @@ the IRQ jumper. If no interrupt is connected, then subdevice 1 is unused. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -313,7 +314,7 @@ static int pc236_intr_cmdtest(struct comedi_device *dev, 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, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -355,44 +356,18 @@ static int pc236_intr_cancel(struct comedi_device *dev, static irqreturn_t pc236_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = &dev->subdevices[1]; + struct comedi_subdevice *s = dev->read_subdev; int handled; handled = pc236_intr_check(dev); if (dev->attached && handled) { - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); } return IRQ_RETVAL(handled); } -static void pc236_report_attach(struct comedi_device *dev, unsigned int irq) -{ - const struct pc236_board *thisboard = comedi_board(dev); - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - char tmpbuf[60]; - int tmplen; - - if (is_isa_board(thisboard)) - tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), - "(base %#lx) ", dev->iobase); - else if (is_pci_board(thisboard)) - tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), - "(pci %s) ", pci_name(pcidev)); - else - tmplen = 0; - if (irq) - tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen, - "(irq %u%s) ", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen, - "(no irq) "); - dev_info(dev->class_dev, "%s %sattached\n", - dev->board_name, tmpbuf); -} - static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, unsigned int irq, unsigned long req_irq_flags) { @@ -410,10 +385,9 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s = &dev->subdevices[0]; /* digital i/o subdevice (8255) */ ret = subdev_8255_init(dev, s, NULL, iobase); - if (ret < 0) { - dev_err(dev->class_dev, "error! out of memory!\n"); + if (ret) return ret; - } + s = &dev->subdevices[1]; dev->read_subdev = s; s->type = COMEDI_SUBD_UNUSED; @@ -428,13 +402,14 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = pc236_intr_insn; + s->len_chanlist = 1; s->do_cmdtest = pc236_intr_cmdtest; s->do_cmd = pc236_intr_cmd; s->cancel = pc236_intr_cancel; } } - pc236_report_attach(dev, irq); - return 1; + + return 0; } static int pc236_pci_common_attach(struct comedi_device *dev, @@ -467,10 +442,9 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct pc236_private *devpriv; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* Process options according to bus type. */ if (is_isa_board(thisboard)) { @@ -510,10 +484,9 @@ static int pc236_auto_attach(struct comedi_device *dev, dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n", pci_name(pci_dev)); - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; dev->board_ptr = pc236_find_pci_board(pci_dev); if (dev->board_ptr == NULL) { @@ -568,7 +541,7 @@ static struct comedi_driver amplc_pc236_driver = { }; #if DO_PCI -static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = { +static const struct pci_device_id pc236_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) }, {0} }; diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 6546095e7a4..7c10d28d278 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -33,6 +33,7 @@ connected to a reed-relay. Relay contacts are closed when output is 1. The state of the outputs can be read. */ +#include <linux/module.h> #include "../comedidev.h" #define PC263_DRIVER_NAME "amplc_pc263" @@ -56,17 +57,16 @@ static const struct pc263_board pc263_boards[] = { static int pc263_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outb(s->state & 0xFF, dev->iobase); - outb(s->state >> 8, dev->iobase + 1); + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase); + outb((s->state >> 8) & 0xff, dev->iobase + 1); } + + data[1] = s->state; + return insn->n; } @@ -94,8 +94,6 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (base %#lx) attached\n", dev->board_name, - dev->iobase); return 0; } diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index f1e36f08b10..339c47c1eb9 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -98,6 +98,7 @@ Caveats: correctly. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -214,12 +215,6 @@ Caveats: #define CLK_EXT 7 /* external clock */ /* Macro to construct clock input configuration register value. */ #define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7)) -/* Timebases in ns. */ -#define TIMEBASE_10MHZ 100 -#define TIMEBASE_1MHZ 1000 -#define TIMEBASE_100KHZ 10000 -#define TIMEBASE_10KHZ 100000 -#define TIMEBASE_1KHZ 1000000 /* * Counter/timer gate input configuration sources. @@ -272,17 +267,16 @@ Caveats: /* The software selectable internal ranges for PCI224 (option[2] == 0). */ static const struct comedi_lrange range_pci224_internal = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; static const unsigned short hwrange_pci224_internal[8] = { @@ -298,11 +292,10 @@ static const unsigned short hwrange_pci224_internal[8] = { /* The software selectable external ranges for PCI224 (option[2] == 1). */ static const struct comedi_lrange range_pci224_external = { - 2, - { - RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */ - RANGE_ext(0, 1), /* unipolar [0,+Vref] */ - } + 2, { + RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */ + RANGE_ext(0, 1) /* unipolar [0,+Vref] */ + } }; static const unsigned short hwrange_pci224_external[2] = { @@ -313,19 +306,17 @@ static const unsigned short hwrange_pci224_external[2] = { /* The hardware selectable Vref*2 external range for PCI234 * (option[2] == 1, option[3+n] == 0). */ static const struct comedi_lrange range_pci234_ext2 = { - 1, - { - RANGE_ext(-2, 2), - } + 1, { + RANGE_ext(-2, 2) + } }; /* The hardware selectable Vref external range for PCI234 * (option[2] == 1, option[3+n] == 1). */ static const struct comedi_lrange range_pci234_ext = { - 1, - { - RANGE_ext(-1, 1), - } + 1, { + RANGE_ext(-1, 1) + } }; /* This serves for all the PCI234 ranges. */ @@ -378,7 +369,7 @@ struct pci224_private { unsigned long state; spinlock_t ao_spinlock; unsigned int *ao_readback; - short *ao_scan_vals; + unsigned short *ao_scan_vals; unsigned char *ao_scan_order; int intr_cpuid; short intr_running; @@ -386,7 +377,6 @@ struct pci224_private { unsigned int cached_div1; unsigned int cached_div2; unsigned int ao_stop_count; - short ao_stop_continuous; unsigned short ao_enab; /* max 16 channels so 'short' will do */ unsigned char intsce; }; @@ -476,16 +466,6 @@ pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, } /* - * Just a wrapper for the inline function 'i8253_cascade_ns_to_timer'. - */ -static void -pci224_cascade_ns_to_timer(int osc_base, unsigned int *d1, unsigned int *d2, - unsigned int *nanosec, int round_mode) -{ - i8253_cascade_ns_to_timer(osc_base, d1, d2, nanosec, round_mode); -} - -/* * Kills a command running on the AO subdevice. */ static void pci224_ao_stop(struct comedi_device *dev, @@ -540,11 +520,10 @@ static void pci224_ao_start(struct comedi_device *dev, unsigned long flags; set_bit(AO_CMD_STARTED, &devpriv->state); - if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { /* An empty acquisition! */ - pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); } else { /* Enable interrupts. */ spin_lock_irqsave(&devpriv->ao_spinlock, flags); @@ -566,21 +545,15 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, { struct pci224_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int bytes_per_scan = cfc_bytes_per_scan(s); unsigned int num_scans; unsigned int room; unsigned short dacstat; unsigned int i, n; - unsigned int bytes_per_scan; - if (cmd->chanlist_len) { - bytes_per_scan = cmd->chanlist_len * sizeof(short); - } else { - /* Shouldn't get here! */ - bytes_per_scan = sizeof(short); - } /* Determine number of scans available in buffer. */ - num_scans = comedi_buf_read_n_available(s->async) / bytes_per_scan; - if (!devpriv->ao_stop_continuous) { + num_scans = comedi_buf_read_n_available(s) / bytes_per_scan; + if (cmd->stop_src == TRIG_COUNT) { /* Fixed number of scans. */ if (num_scans > devpriv->ao_stop_count) num_scans = devpriv->ao_stop_count; @@ -592,11 +565,10 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, switch (dacstat & PCI224_DACCON_FIFOFL_MASK) { case PCI224_DACCON_FIFOFL_EMPTY: room = PCI224_FIFO_ROOM_EMPTY; - if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { /* FIFO empty at end of counted acquisition. */ - pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } break; @@ -614,14 +586,12 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, /* FIFO is less than half-full. */ if (num_scans == 0) { /* Nothing left to put in the FIFO. */ - pci224_ao_stop(dev, s); - s->async->events |= COMEDI_CB_OVERFLOW; dev_err(dev->class_dev, "AO buffer underrun\n"); + s->async->events |= COMEDI_CB_OVERFLOW; } } /* Determine how many new scans can be put in the FIFO. */ - if (cmd->chanlist_len) - room /= cmd->chanlist_len; + room /= cmd->chanlist_len; /* Determine how many scans to process. */ if (num_scans > room) @@ -636,7 +606,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, dev->iobase + PCI224_DACDATA); } } - if (!devpriv->ao_stop_continuous) { + if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_stop_count -= num_scans; if (devpriv->ao_stop_count == 0) { /* @@ -679,19 +649,17 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, PCI224_DACCON_TRIG_MASK); outw(devpriv->daccon, dev->iobase + PCI224_DACCON); } - if (s->async->events) - comedi_event(dev, s); + cfc_handle_events(dev, s); } -/* - * Internal trigger function to start acquisition on AO subdevice. - */ -static int -pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pci224_ao_inttrig_start(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; s->async->inttrig = NULL; @@ -700,6 +668,37 @@ pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, return 1; } +static int pci224_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int chan_mask = 0; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan_mask & (1 << chan)) { + dev_dbg(dev->class_dev, + "%s: entries in chanlist must contain no duplicate channels\n", + __func__); + return -EINVAL; + } + chan_mask |= (1 << chan); + + if (range != range0) { + dev_dbg(dev->class_dev, + "%s: entries in chanlist must all have the same range index\n", + __func__); + return -EINVAL; + } + } + + return 0; +} + #define MAX_SCAN_PERIOD 0xFFFFFFFFU #define MIN_SCAN_PERIOD 2500 #define CONVERT_PERIOD 625 @@ -713,7 +712,7 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, { struct pci224_private *devpriv = dev->private; int err = 0; - unsigned int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -740,14 +739,14 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, * There's only one external trigger signal (which makes these * tests easier). Only one thing can use it. */ - tmp = 0; + arg = 0; if (cmd->start_src & TRIG_EXT) - tmp++; + arg++; if (cmd->scan_begin_src & TRIG_EXT) - tmp++; + arg++; if (cmd->stop_src & TRIG_EXT) - tmp++; - if (tmp > 1) + arg++; + if (arg > 1) err |= -EINVAL; if (err) @@ -780,10 +779,10 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, MAX_SCAN_PERIOD); - tmp = cmd->chanlist_len * CONVERT_PERIOD; - if (tmp < MIN_SCAN_PERIOD) - tmp = MIN_SCAN_PERIOD; - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, tmp); + arg = cmd->chanlist_len * CONVERT_PERIOD; + if (arg < MIN_SCAN_PERIOD) + arg = MIN_SCAN_PERIOD; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, arg); break; case TRIG_EXT: /* Force to external trigger 0. */ @@ -834,99 +833,21 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 4: fix up any arguments. */ if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1, div2, round; - int round_mode = cmd->flags & TRIG_ROUND_MASK; - - tmp = cmd->scan_begin_arg; - /* Check whether to use a single timer. */ - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - round = TIMEBASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = TIMEBASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) / - TIMEBASE_10MHZ; - if (div2 <= 0x10000) { - /* A single timer will suffice. */ - if (div2 < 2) - div2 = 2; - cmd->scan_begin_arg = div2 * TIMEBASE_10MHZ; - if (cmd->scan_begin_arg < div2 || - cmd->scan_begin_arg < TIMEBASE_10MHZ) { - /* Overflow! */ - cmd->scan_begin_arg = MAX_SCAN_PERIOD; - } - } else { - /* Use two timers. */ - div1 = devpriv->cached_div1; - div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2, - &cmd->scan_begin_arg, - round_mode); - devpriv->cached_div1 = div1; - devpriv->cached_div2 = div2; - } - if (tmp != cmd->scan_begin_arg) - err++; - + arg = cmd->scan_begin_arg; + /* Use two timers. */ + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->cached_div1, + &devpriv->cached_div2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) return 4; - /* Step 5: check channel list. */ - - if (cmd->chanlist && (cmd->chanlist_len > 0)) { - unsigned int range; - enum { range_err = 1, dupchan_err = 2, }; - unsigned errors; - unsigned int n; - unsigned int ch; - - /* - * Check all channels have the same range index. Don't care - * about analogue reference, as we can't configure it. - * - * Check the list has no duplicate channels. - */ - range = CR_RANGE(cmd->chanlist[0]); - errors = 0; - tmp = 0; - for (n = 0; n < cmd->chanlist_len; n++) { - ch = CR_CHAN(cmd->chanlist[n]); - if (tmp & (1U << ch)) - errors |= dupchan_err; - - tmp |= (1U << ch); - if (CR_RANGE(cmd->chanlist[n]) != range) - errors |= range_err; - - } - if (errors) { - if (errors & dupchan_err) { - DPRINTK("comedi%d: " DRIVER_NAME - ": ao_cmdtest: " - "entries in chanlist must contain no " - "duplicate channels\n", dev->minor); - } - if (errors & range_err) { - DPRINTK("comedi%d: " DRIVER_NAME - ": ao_cmdtest: " - "entries in chanlist must all have " - "the same range index\n", dev->minor); - } - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci224_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -934,9 +855,33 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* - * 'do_cmd' function for AO subdevice. - */ +static void pci224_ao_start_pacer(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci224_private *devpriv = dev->private; + unsigned long timer_base = devpriv->iobase1 + PCI224_Z2_CT0; + + /* + * The output of timer Z2-0 will be used as the scan trigger + * source. + */ + /* Make sure Z2-0 is gated on. */ + outb(GAT_CONFIG(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE); + /* Cascading with Z2-2. */ + /* Make sure Z2-2 is gated on. */ + outb(GAT_CONFIG(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE); + /* Z2-2 needs 10 MHz clock. */ + outb(CLK_CONFIG(2, CLK_10MHZ), devpriv->iobase1 + PCI224_ZCLK_SCE); + /* Load Z2-2 mode (2) and counter (div1). */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 2, devpriv->cached_div1); + /* Z2-0 is clocked from Z2-2's output. */ + outb(CLK_CONFIG(0, CLK_OUTNM1), devpriv->iobase1 + PCI224_ZCLK_SCE); + /* Load Z2-0 mode (2) and counter (div2). */ + i8254_set_mode(timer_base, 0, 0, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 0, devpriv->cached_div2); +} + static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci224_private *devpriv = dev->private; @@ -992,105 +937,26 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1, div2, round; - unsigned int ns = cmd->scan_begin_arg; - int round_mode = cmd->flags & TRIG_ROUND_MASK; - - /* Check whether to use a single timer. */ - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - round = TIMEBASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = TIMEBASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) / - TIMEBASE_10MHZ; - if (div2 <= 0x10000) { - /* A single timer will suffice. */ - if (div2 < 2) - div2 = 2; - div2 &= 0xffff; - div1 = 1; /* Flag that single timer to be used. */ - } else { - /* Use two timers. */ - div1 = devpriv->cached_div1; - div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2, - &ns, round_mode); - } - - /* - * The output of timer Z2-0 will be used as the scan trigger - * source. - */ - /* Make sure Z2-0 is gated on. */ - outb(GAT_CONFIG(0, GAT_VCC), - devpriv->iobase1 + PCI224_ZGAT_SCE); - if (div1 == 1) { - /* Not cascading. Z2-0 needs 10 MHz clock. */ - outb(CLK_CONFIG(0, CLK_10MHZ), - devpriv->iobase1 + PCI224_ZCLK_SCE); - } else { - /* Cascading with Z2-2. */ - /* Make sure Z2-2 is gated on. */ - outb(GAT_CONFIG(2, GAT_VCC), - devpriv->iobase1 + PCI224_ZGAT_SCE); - /* Z2-2 needs 10 MHz clock. */ - outb(CLK_CONFIG(2, CLK_10MHZ), - devpriv->iobase1 + PCI224_ZCLK_SCE); - /* Load Z2-2 mode (2) and counter (div1). */ - i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, - 2, div1, 2); - /* Z2-0 is clocked from Z2-2's output. */ - outb(CLK_CONFIG(0, CLK_OUTNM1), - devpriv->iobase1 + PCI224_ZCLK_SCE); - } - /* Load Z2-0 mode (2) and counter (div2). */ - i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, 0, div2, 2); - } + if (cmd->scan_begin_src == TRIG_TIMER) + pci224_ao_start_pacer(dev, s); /* * Sort out end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - /* Fixed number of scans. */ - devpriv->ao_stop_continuous = 0; + if (cmd->stop_src == TRIG_COUNT) devpriv->ao_stop_count = cmd->stop_arg; - break; - default: - /* Continuous scans. */ - devpriv->ao_stop_continuous = 1; + else /* TRIG_EXT | TRIG_NONE */ devpriv->ao_stop_count = 0; - break; - } - /* - * Sort out start of acquisition. - */ - switch (cmd->start_src) { - case TRIG_INT: - spin_lock_irqsave(&devpriv->ao_spinlock, flags); - s->async->inttrig = &pci224_ao_inttrig_start; - spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - break; - case TRIG_EXT: + spin_lock_irqsave(&devpriv->ao_spinlock, flags); + if (cmd->start_src == TRIG_INT) { + s->async->inttrig = pci224_ao_inttrig_start; + } else { /* TRIG_EXT */ /* Enable external interrupt trigger to start acquisition. */ - spin_lock_irqsave(&devpriv->ao_spinlock, flags); devpriv->intsce |= PCI224_INTR_EXT; outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); - spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - break; } + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); return 0; } @@ -1114,8 +980,8 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, { const struct pci224_board *thisboard = comedi_board(dev); struct pci224_private *devpriv = dev->private; - struct comedi_async *async = s->async; - short *array = data; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned short *array = data; unsigned int length = num_bytes / sizeof(*array); unsigned int offset; unsigned int shift; @@ -1124,7 +990,7 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, /* The hardware expects 16-bit numbers. */ shift = 16 - thisboard->ao_bits; /* Channels will be all bipolar or all unipolar. */ - if ((devpriv->hwrange[CR_RANGE(async->cmd.chanlist[0])] & + if ((devpriv->hwrange[CR_RANGE(cmd->chanlist[0])] & PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) { /* Unipolar */ offset = 0; @@ -1145,7 +1011,7 @@ static irqreturn_t pci224_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct pci224_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->write_subdev; struct comedi_cmd *cmd; unsigned char intstat, valid_intstat; unsigned char curenab; @@ -1246,20 +1112,6 @@ static struct pci_dev *pci224_find_pci_dev(struct comedi_device *dev, return NULL; } -static void pci224_report_attach(struct comedi_device *dev, unsigned int irq) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - char tmpbuf[30]; - - if (irq) - snprintf(tmpbuf, sizeof(tmpbuf), "irq %u%s", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - snprintf(tmpbuf, sizeof(tmpbuf), "no irq"); - dev_info(dev->class_dev, "%s (pci %s) (%s) attached\n", - dev->board_name, pci_name(pcidev), tmpbuf); -} - /* * Common part of attach and auto_attach. */ @@ -1408,8 +1260,7 @@ static int pci224_attach_common(struct comedi_device *dev, } } - pci224_report_attach(dev, irq); - return 1; + return 0; } static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -1419,10 +1270,9 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev_info(dev->class_dev, DRIVER_NAME ": attach\n"); - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; pci_dev = pci224_find_pci_dev(dev, it); if (!pci_dev) @@ -1440,10 +1290,9 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_unused) dev_info(dev->class_dev, DRIVER_NAME ": attach pci %s\n", pci_name(pci_dev)); - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; dev->board_ptr = pci224_find_pci_board(pci_dev); if (dev->board_ptr == NULL) { @@ -1503,7 +1352,7 @@ static int amplc_pci224_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = { +static const struct pci_device_id amplc_pci224_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) }, { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) }, { 0 } diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 846d6448fa4..3895bc7cb3e 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -184,6 +184,7 @@ Support for PCI230+/260+, more triggered scan functionality, and workarounds for (or detection of) various hardware problems added by Ian Abbott. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -518,14 +519,6 @@ struct pci230_private { * level threshold (PCI230+/260+). */ unsigned short adcg; /* ADCG register value. */ unsigned char int_en; /* Interrupt enables bits. */ - unsigned char ai_continuous; /* Flag set when cmd->stop_src == - * TRIG_NONE - user chooses to stop - * continuous conversion by - * cancelation. */ - unsigned char ao_continuous; /* Flag set when cmd->stop_src == - * TRIG_NONE - user chooses to stop - * continuous conversion by - * cancelation. */ unsigned char ai_bipolar; /* Set if bipolar input range so we * know to mangle it. */ unsigned char ao_bipolar; /* Set if bipolar output range so we @@ -545,15 +538,16 @@ static const unsigned int pci230_timebase[8] = { }; /* PCI230 analogue input range table */ -static const struct comedi_lrange pci230_ai_range = { 7, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5) - } +static const struct comedi_lrange pci230_ai_range = { + 7, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5) + } }; /* PCI230 analogue gain bits for each input range. */ @@ -563,23 +557,24 @@ static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 }; static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 }; /* PCI230 analogue output range table */ -static const struct comedi_lrange pci230_ao_range = { 2, { - UNI_RANGE(10), - BIP_RANGE(10) - } +static const struct comedi_lrange pci230_ao_range = { + 2, { + UNI_RANGE(10), + BIP_RANGE(10) + } }; /* PCI230 daccon bipolar flag for each analogue output range. */ static const unsigned char pci230_ao_bipolar[2] = { 0, 1 }; -static short pci230_ai_read(struct comedi_device *dev) +static unsigned short pci230_ai_read(struct comedi_device *dev) { const struct pci230_board *thisboard = comedi_board(dev); struct pci230_private *devpriv = dev->private; - short data; + unsigned short data; /* Read sample. */ - data = (short)inw(dev->iobase + PCI230_ADCDATA); + data = inw(dev->iobase + PCI230_ADCDATA); /* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower * four bits reserved for expansion). */ /* PCI230+ is 16 bit AI. */ @@ -594,7 +589,7 @@ static short pci230_ai_read(struct comedi_device *dev) } static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, - short datum) + unsigned short datum) { const struct pci230_board *thisboard = comedi_board(dev); struct pci230_private *devpriv = dev->private; @@ -608,11 +603,12 @@ static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, * four bits reserved for expansion). */ /* PCI230+ is also 12 bit AO. */ datum <<= (16 - thisboard->ao_bits); - return (unsigned short)datum; + return datum; } static inline void pci230_ao_write_nofifo(struct comedi_device *dev, - short datum, unsigned int chan) + unsigned short datum, + unsigned int chan) { struct pci230_private *devpriv = dev->private; @@ -626,8 +622,8 @@ static inline void pci230_ao_write_nofifo(struct comedi_device *dev, PCI230_DACOUT2)); } -static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum, - unsigned int chan) +static inline void pci230_ao_write_fifo(struct comedi_device *dev, + unsigned short datum, unsigned int chan) { struct pci230_private *devpriv = dev->private; @@ -795,19 +791,29 @@ static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct) /* Counter ct, 8254 mode 1, initial count not written. */ } -/* - * COMEDI_SUBD_AI instruction; - */ +static int pci230_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI230_ADCCON); + if ((status & PCI230_ADC_FIFO_EMPTY) == 0) + return 0; + return -EBUSY; +} + static int pci230_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci230_private *devpriv = dev->private; - unsigned int n, i; + unsigned int n; unsigned int chan, range, aref; unsigned int gainshift; - unsigned int status; unsigned short adccon, adcen; + int ret; /* Unpack channel and range. */ chan = CR_CHAN(insn->chanspec); @@ -816,9 +822,9 @@ static int pci230_ai_rinsn(struct comedi_device *dev, if (aref == AREF_DIFF) { /* Differential. */ if (chan >= s->n_chan / 2) { - DPRINTK("comedi%d: amplc_pci230: ai_rinsn: " - "differential channel number out of range " - "0 to %u\n", dev->minor, (s->n_chan / 2) - 1); + dev_dbg(dev->class_dev, + "%s: differential channel number out of range 0 to %u\n", + __func__, (s->n_chan / 2) - 1); return -EINVAL; } } @@ -879,18 +885,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev, i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + PCI230_ADCCON); - if (!(status & PCI230_ADC_FIFO_EMPTY)) - break; - udelay(1); - } - if (i == TIMEOUT) { - dev_err(dev->class_dev, "timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = pci230_ai_read(dev); @@ -947,6 +945,38 @@ static int pci230_ao_rinsn(struct comedi_device *dev, return i; } +static int pci230_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int prev_chan = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan < prev_chan) { + dev_dbg(dev->class_dev, + "%s: channel numbers must increase\n", + __func__); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "%s: channels must have the same range\n", + __func__); + return -EINVAL; + } + + prev_chan = chan; + } + + return 0; +} + static int pci230_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -1059,48 +1089,9 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, if (err) return 4; - /* Step 5: check channel list if it exists. */ - - if (cmd->chanlist && cmd->chanlist_len > 0) { - enum { - seq_err = (1 << 0), - range_err = (1 << 1) - }; - unsigned int errors; - unsigned int n; - unsigned int chan, prev_chan; - unsigned int range, first_range; - - prev_chan = CR_CHAN(cmd->chanlist[0]); - first_range = CR_RANGE(cmd->chanlist[0]); - errors = 0; - for (n = 1; n < cmd->chanlist_len; n++) { - chan = CR_CHAN(cmd->chanlist[n]); - range = CR_RANGE(cmd->chanlist[n]); - /* Channel numbers must strictly increase. */ - if (chan < prev_chan) - errors |= seq_err; - - /* Ranges must be the same. */ - if (range != first_range) - errors |= range_err; - - prev_chan = chan; - } - if (errors != 0) { - err++; - if ((errors & seq_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: " - "channel numbers must increase\n", - dev->minor); - } - if ((errors & range_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: " - "channels must have the same range\n", - dev->minor); - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci230_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1164,16 +1155,16 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci230_private *devpriv = dev->private; - short data; + unsigned short data; int i, ret; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) return; for (i = 0; i < cmd->chanlist_len; i++) { /* Read sample from Comedi's circular buffer. */ - ret = comedi_buf_get(s->async, &data); + ret = comedi_buf_get(s, &data); if (ret == 0) { s->async->events |= COMEDI_CB_OVERFLOW; pci230_ao_stop(dev, s); @@ -1184,7 +1175,7 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i])); } async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (!devpriv->ao_continuous) { + if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_scan_count--; if (devpriv->ao_scan_count == 0) { /* End of acquisition. */ @@ -1206,16 +1197,14 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, unsigned int room; unsigned short dacstat; unsigned int i, n; - unsigned int bytes_per_scan; unsigned int events = 0; int running; /* Get DAC FIFO status. */ dacstat = inw(dev->iobase + PCI230_DACCON); /* Determine number of scans available in buffer. */ - bytes_per_scan = cmd->chanlist_len * sizeof(short); - num_scans = comedi_buf_read_n_available(async) / bytes_per_scan; - if (!devpriv->ao_continuous) { + num_scans = comedi_buf_read_n_available(s) / cfc_bytes_per_scan(s); + if (cmd->stop_src == TRIG_COUNT) { /* Fixed number of scans. */ if (num_scans > devpriv->ao_scan_count) num_scans = devpriv->ao_scan_count; @@ -1257,15 +1246,15 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, /* Process scans. */ for (n = 0; n < num_scans; n++) { for (i = 0; i < cmd->chanlist_len; i++) { - short datum; + unsigned short datum; - comedi_buf_get(async, &datum); + comedi_buf_get(s, &datum); pci230_ao_write_fifo(dev, datum, CR_CHAN(cmd->chanlist[i])); } } events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK; - if (!devpriv->ao_continuous) { + if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_scan_count -= num_scans; if (devpriv->ao_scan_count == 0) { /* All data for the command has been written @@ -1343,7 +1332,7 @@ static void pci230_ao_start(struct comedi_device *dev, unsigned long irqflags; set_bit(AO_CMD_STARTED, &devpriv->state); - if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) { /* An empty acquisition! */ async->events |= COMEDI_CB_EOA; pci230_ao_stop(dev, s); @@ -1428,7 +1417,9 @@ static int pci230_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { - if (trig_num != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_src) return -EINVAL; s->async->inttrig = NULL; @@ -1454,14 +1445,10 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) devpriv->ao_scan_count = cmd->stop_arg; - devpriv->ao_continuous = 0; - } else { - /* TRIG_NONE, user calls cancel. */ + else /* TRIG_NONE, user calls cancel */ devpriv->ao_scan_count = 0; - devpriv->ao_continuous = 1; - } /* Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale */ @@ -1546,6 +1533,109 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd) return !err; } +static int pci230_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct pci230_private *devpriv = dev->private; + unsigned int max_diff_chan = (s->n_chan / 2) - 1; + unsigned int prev_chan = 0; + unsigned int prev_range = 0; + unsigned int prev_aref = 0; + unsigned int prev_polarity = 0; + unsigned int subseq_len = 0; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int polarity = pci230_ai_bipolar[range]; + + if (aref == AREF_DIFF && chan >= max_diff_chan) { + dev_dbg(dev->class_dev, + "%s: differential channel number out of range 0 to %u\n", + __func__, max_diff_chan); + return -EINVAL; + } + + if (i > 0) { + /* + * Channel numbers must strictly increase or + * subsequence must repeat exactly. + */ + if (chan <= prev_chan && subseq_len == 0) + subseq_len = i; + + if (subseq_len > 0 && + cmd->chanlist[i % subseq_len] != chanspec) { + dev_dbg(dev->class_dev, + "%s: channel numbers must increase or sequence must repeat exactly\n", + __func__); + return -EINVAL; + } + + if (aref != prev_aref) { + dev_dbg(dev->class_dev, + "%s: channel sequence analogue references must be all the same (single-ended or differential)\n", + __func__); + return -EINVAL; + } + + if (polarity != prev_polarity) { + dev_dbg(dev->class_dev, + "%s: channel sequence ranges must be all bipolar or all unipolar\n", + __func__); + return -EINVAL; + } + + if (aref != AREF_DIFF && range != prev_range && + ((chan ^ prev_chan) & ~1) == 0) { + dev_dbg(dev->class_dev, + "%s: single-ended channel pairs must have the same range\n", + __func__); + return -EINVAL; + } + } + prev_chan = chan; + prev_range = range; + prev_aref = aref; + prev_polarity = polarity; + } + + if (subseq_len == 0) + subseq_len = cmd->chanlist_len; + + if ((cmd->chanlist_len % subseq_len) != 0) { + dev_dbg(dev->class_dev, + "%s: sequence must repeat exactly\n", __func__); + return -EINVAL; + } + + /* + * Buggy PCI230+ or PCI260+ requires channel 0 to be (first) in the + * sequence if the sequence contains more than one channel. Hardware + * versions 1 and 2 have the bug. There is no hardware version 3. + * + * Actually, there are two firmwares that report themselves as + * hardware version 1 (the boards have different ADC chips with + * slightly different timing requirements, which was supposed to + * be invisible to software). The first one doesn't seem to have + * the bug, but the second one does, and we can't tell them apart! + */ + if (devpriv->hwver > 0 && devpriv->hwver < 4) { + if (subseq_len > 1 && CR_CHAN(cmd->chanlist[0]) != 0) { + dev_info(dev->class_dev, + "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n", + devpriv->hwver); + return -EINVAL; + } + } + + return 0; +} + static int pci230_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -1734,140 +1824,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - /* Step 5: check channel list if it exists. */ - - if (cmd->chanlist && cmd->chanlist_len > 0) { - enum { - seq_err = 1 << 0, - rangepair_err = 1 << 1, - polarity_err = 1 << 2, - aref_err = 1 << 3, - diffchan_err = 1 << 4, - buggy_chan0_err = 1 << 5 - }; - unsigned int errors; - unsigned int chan, prev_chan; - unsigned int range, prev_range; - unsigned int polarity, prev_polarity; - unsigned int aref, prev_aref; - unsigned int subseq_len; - unsigned int n; - - subseq_len = 0; - errors = 0; - prev_chan = prev_aref = prev_range = prev_polarity = 0; - for (n = 0; n < cmd->chanlist_len; n++) { - chan = CR_CHAN(cmd->chanlist[n]); - range = CR_RANGE(cmd->chanlist[n]); - aref = CR_AREF(cmd->chanlist[n]); - polarity = pci230_ai_bipolar[range]; - /* Only the first half of the channels are available if - * differential. (These are remapped in software. In - * hardware, only the even channels are available.) */ - if ((aref == AREF_DIFF) - && (chan >= (s->n_chan / 2))) { - errors |= diffchan_err; - } - if (n > 0) { - /* Channel numbers must strictly increase or - * subsequence must repeat exactly. */ - if ((chan <= prev_chan) - && (subseq_len == 0)) { - subseq_len = n; - } - if ((subseq_len > 0) - && (cmd->chanlist[n] != - cmd->chanlist[n % subseq_len])) { - errors |= seq_err; - } - /* Channels must have same AREF. */ - if (aref != prev_aref) - errors |= aref_err; - - /* Channel ranges must have same polarity. */ - if (polarity != prev_polarity) - errors |= polarity_err; - - /* Single-ended channel pairs must have same - * range. */ - if ((aref != AREF_DIFF) - && (((chan ^ prev_chan) & ~1) == 0) - && (range != prev_range)) { - errors |= rangepair_err; - } - } - prev_chan = chan; - prev_range = range; - prev_aref = aref; - prev_polarity = polarity; - } - if (subseq_len == 0) { - /* Subsequence is whole sequence. */ - subseq_len = n; - } - /* If channel list is a repeating subsequence, need a whole - * number of repeats. */ - if ((n % subseq_len) != 0) - errors |= seq_err; - - if ((devpriv->hwver > 0) && (devpriv->hwver < 4)) { - /* - * Buggy PCI230+ or PCI260+ requires channel 0 to be - * (first) in the sequence if the sequence contains - * more than one channel. Hardware versions 1 and 2 - * have the bug. There is no hardware version 3. - * - * Actually, there are two firmwares that report - * themselves as hardware version 1 (the boards - * have different ADC chips with slightly different - * timing requirements, which was supposed to be - * invisible to software). The first one doesn't - * seem to have the bug, but the second one - * does, and we can't tell them apart! - */ - if ((subseq_len > 1) - && (CR_CHAN(cmd->chanlist[0]) != 0)) { - errors |= buggy_chan0_err; - } - } - if (errors != 0) { - err++; - if ((errors & seq_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "channel numbers must increase or " - "sequence must repeat exactly\n", - dev->minor); - } - if ((errors & rangepair_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "single-ended channel pairs must " - "have the same range\n", dev->minor); - } - if ((errors & polarity_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "channel sequence ranges must be all " - "bipolar or all unipolar\n", - dev->minor); - } - if ((errors & aref_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "channel sequence analogue references " - "must be all the same (single-ended " - "or differential)\n", dev->minor); - } - if ((errors & diffchan_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "differential channel number out of " - "range 0 to %u\n", dev->minor, - (s->n_chan / 2) - 1); - } - if ((errors & buggy_chan0_err) != 0) { - dev_info(dev->class_dev, - "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n", - devpriv->hwver); - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci230_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1889,9 +1848,9 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, /* Wake at end of scan. */ wake = scanlen - devpriv->ai_scan_pos; } else { - if (devpriv->ai_continuous - || (devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL) - || (scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL)) { + if (cmd->stop_src != TRIG_COUNT || + devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || + scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) { wake = PCI230_ADC_FIFOLEVEL_HALFFULL; } else { wake = (devpriv->ai_scan_count * scanlen) @@ -2042,7 +2001,7 @@ static void pci230_ai_start(struct comedi_device *dev, struct comedi_cmd *cmd = &async->cmd; set_bit(AI_CMD_STARTED, &devpriv->state); - if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { /* An empty acquisition! */ async->events |= COMEDI_CB_EOA; pci230_ai_stop(dev, s); @@ -2175,7 +2134,9 @@ static int pci230_ai_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { - if (trig_num != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; s->async->inttrig = NULL; @@ -2188,16 +2149,17 @@ static void pci230_handle_ai(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci230_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int scanlen = cmd->scan_end_arg; unsigned int events = 0; unsigned int status_fifo; unsigned int i; unsigned int todo; unsigned int fifoamount; - struct comedi_async *async = s->async; - unsigned int scanlen = async->cmd.scan_end_arg; /* Determine number of samples to read. */ - if (devpriv->ai_continuous) { + if (cmd->stop_src != TRIG_COUNT) { todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } else if (devpriv->ai_scan_count == 0) { todo = 0; @@ -2245,7 +2207,7 @@ static void pci230_handle_ai(struct comedi_device *dev, } } /* Read sample and store in Comedi's circular buffer. */ - if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) { + if (comedi_buf_put(s, pci230_ai_read(dev)) == 0) { events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; comedi_error(dev, "AI buffer overflow"); break; @@ -2259,7 +2221,7 @@ static void pci230_handle_ai(struct comedi_device *dev, async->events |= COMEDI_CB_EOS; } } - if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { /* End of acquisition. */ events |= COMEDI_CB_EOA; } else { @@ -2310,14 +2272,10 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) devpriv->ai_scan_count = cmd->stop_arg; - devpriv->ai_continuous = 0; - } else { - /* TRIG_NONE, user calls cancel. */ + else /* TRIG_NONE, user calls cancel */ devpriv->ai_scan_count = 0; - devpriv->ai_continuous = 1; - } devpriv->ai_scan_pos = 0; /* Position within scan. */ /* Steps; @@ -2461,12 +2419,10 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } } - if (cmd->start_src == TRIG_INT) { + if (cmd->start_src == TRIG_INT) s->async->inttrig = pci230_ai_inttrig_start; - } else { - /* TRIG_NOW */ + else /* TRIG_NOW */ pci230_ai_start(dev, s); - } return 0; } @@ -2615,10 +2571,9 @@ static int pci230_alloc_private(struct comedi_device *dev) { struct pci230_private *devpriv; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; spin_lock_init(&devpriv->isr_spinlock); spin_lock_init(&devpriv->res_spinlock); @@ -2636,7 +2591,7 @@ static int pci230_attach_common(struct comedi_device *dev, struct comedi_subdevice *s; unsigned long iobase1, iobase2; /* PCI230's I/O spaces 1 and 2 respectively. */ - int irq_hdl, rc; + int rc; comedi_set_hw_dev(dev, &pci_dev->dev); @@ -2708,16 +2663,12 @@ static int pci230_attach_common(struct comedi_device *dev, outw(devpriv->adcg, dev->iobase + PCI230_ADCG); outw(devpriv->adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); - /* Register the interrupt handler. */ - irq_hdl = request_irq(pci_dev->irq, pci230_interrupt, - IRQF_SHARED, "amplc_pci230", dev); - if (irq_hdl < 0) { - dev_warn(dev->class_dev, - "unable to register irq %u, commands will not be available\n", - pci_dev->irq); - } else { - dev->irq = pci_dev->irq; - dev_dbg(dev->class_dev, "registered irq %u\n", pci_dev->irq); + + if (pci_dev->irq) { + rc = request_irq(pci_dev->irq, pci230_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (rc == 0) + dev->irq = pci_dev->irq; } rc = comedi_alloc_subdevices(dev, 3); @@ -2733,14 +2684,14 @@ static int pci230_attach_common(struct comedi_device *dev, s->range_table = &pci230_ai_range; s->insn_read = &pci230_ai_rinsn; s->len_chanlist = 256; /* but there are restrictions. */ - /* Only register commands if the interrupt handler is installed. */ - if (irq_hdl == 0) { + if (dev->irq) { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; s->do_cmd = &pci230_ai_cmd; s->do_cmdtest = &pci230_ai_cmdtest; s->cancel = pci230_ai_cancel; } + s = &dev->subdevices[1]; /* analog output subdevice */ if (thisboard->ao_chans > 0) { @@ -2752,9 +2703,7 @@ static int pci230_attach_common(struct comedi_device *dev, s->insn_write = &pci230_ao_winsn; s->insn_read = &pci230_ao_rinsn; s->len_chanlist = thisboard->ao_chans; - /* Only register commands if the interrupt handler is - * installed. */ - if (irq_hdl == 0) { + if (dev->irq) { dev->write_subdev = s; s->subdev_flags |= SDF_CMD_WRITE; s->do_cmd = &pci230_ao_cmd; @@ -2764,18 +2713,19 @@ static int pci230_attach_common(struct comedi_device *dev, } else { s->type = COMEDI_SUBD_UNUSED; } + s = &dev->subdevices[2]; /* digital i/o subdevice */ if (thisboard->have_dio) { rc = subdev_8255_init(dev, s, NULL, - (devpriv->iobase1 + PCI230_PPI_X_BASE)); - if (rc < 0) + devpriv->iobase1 + PCI230_PPI_X_BASE); + if (rc) return rc; } else { s->type = COMEDI_SUBD_UNUSED; } - dev_info(dev->class_dev, "attached\n"); - return 1; + + return 0; } static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -2855,7 +2805,7 @@ static int amplc_pci230_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = { +static const struct pci_device_id amplc_pci230_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) }, { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) }, { 0 } diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index 4da900cc584..93ed03ee416 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -32,6 +32,7 @@ connected to a reed-relay. Relay contacts are closed when output is 1. The state of the outputs can be read. */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -43,17 +44,16 @@ The state of the outputs can be read. static int pci263_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outb(s->state & 0xFF, dev->iobase); - outb(s->state >> 8, dev->iobase + 1); + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase); + outb((s->state >> 8) & 0xff, dev->iobase + 1); } + + data[1] = s->state; + return insn->n; } @@ -84,8 +84,6 @@ static int pci263_auto_attach(struct comedi_device *dev, /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (pci %s) attached\n", dev->board_name, - pci_name(pci_dev)); return 0; } @@ -96,7 +94,7 @@ static struct comedi_driver amplc_pci263_driver = { .detach = comedi_pci_disable, }; -static DEFINE_PCI_DEVICE_TABLE(pci263_pci_table) = { +static const struct pci_device_id pci263_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) }, {0} }; diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index 929218a3597..e03dd6e7141 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -1,42 +1,39 @@ /* - comedi/drivers/c6xdigio.c - - Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. - (http://robot0.ge.uiuc.edu/~spong/mecha/) - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Dan Block - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * c6xdigio.c + * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. + * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/ + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Dan Block + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: c6xdigio -Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card -Author: Dan Block -Status: unknown -Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio) -Updated: Sun Nov 20 20:18:34 EST 2005 - -This driver will not work with a 2.4 kernel. -http://robot0.ge.uiuc.edu/~spong/mecha/ -*/ +/* + * Driver: c6xdigio + * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card + * Author: Dan Block + * Status: unknown + * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio] + * Updated: Sun Nov 20 20:18:34 EST 2005 + * + * Configuration Options: + * [0] - base address + */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/timex.h> #include <linux/timer.h> @@ -45,351 +42,194 @@ http://robot0.ge.uiuc.edu/~spong/mecha/ #include "../comedidev.h" -static u8 ReadByteFromHwPort(unsigned long addr) -{ - u8 result = inb(addr); - return result; -} - -static void WriteByteToHwPort(unsigned long addr, u8 val) -{ - outb_p(val, addr); -} - -#define C6XDIGIO_SIZE 3 - /* - * port offsets + * Register I/O map */ -#define C6XDIGIO_PARALLEL_DATA 0 -#define C6XDIGIO_PARALLEL_STATUS 1 -#define C6XDIGIO_PARALLEL_CONTROL 2 -struct pwmbitstype { - unsigned sb0:2; - unsigned sb1:2; - unsigned sb2:2; - unsigned sb3:2; - unsigned sb4:2; -}; -union pwmcmdtype { - unsigned cmd; /* assuming here that int is 32bit */ - struct pwmbitstype bits; -}; -struct encbitstype { - unsigned sb0:3; - unsigned sb1:3; - unsigned sb2:3; - unsigned sb3:3; - unsigned sb4:3; - unsigned sb5:3; - unsigned sb6:3; - unsigned sb7:3; -}; -union encvaluetype { - unsigned value; - struct encbitstype bits; -}; +#define C6XDIGIO_DATA_REG 0x00 +#define C6XDIGIO_DATA_CHAN(x) (((x) + 1) << 4) +#define C6XDIGIO_DATA_PWM (1 << 5) +#define C6XDIGIO_DATA_ENCODER (1 << 6) +#define C6XDIGIO_STATUS_REG 0x01 +#define C6XDIGIO_CTRL_REG 0x02 #define C6XDIGIO_TIME_OUT 20 -static void C6X_pwmInit(unsigned long baseAddr) +static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context) { + unsigned int status; int timeout = 0; -/* printk("Inside C6X_pwmInit\n"); */ - - WriteByteToHwPort(baseAddr, 0x70); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x74); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x70); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { + do { + status = inb(dev->iobase + C6XDIGIO_STATUS_REG); + if ((status & 0x80) != context) + return 0; timeout++; - } - - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } + } while (timeout < C6XDIGIO_TIME_OUT); + return -EBUSY; } -static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value) +static int c6xdigio_write_data(struct comedi_device *dev, + unsigned int val, unsigned int status) { - unsigned ppcmd; - union pwmcmdtype pwm; - int timeout = 0; - unsigned tmp; - - /* printk("Inside C6X_pwmOutput\n"); */ - - pwm.cmd = value; - if (pwm.cmd > 498) - pwm.cmd = 498; - if (pwm.cmd < 2) - pwm.cmd = 2; - - if (channel == 0) { - ppcmd = 0x28; - } else { /* if channel == 1 */ - ppcmd = 0x30; - } /* endif */ - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + outb_p(val, dev->iobase + C6XDIGIO_DATA_REG); + return c6xdigio_chk_status(dev, status); +} - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } +static int c6xdigio_get_encoder_bits(struct comedi_device *dev, + unsigned int *bits, + unsigned int cmd, + unsigned int status) +{ + unsigned int val; - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + val = inb(dev->iobase + C6XDIGIO_STATUS_REG); + val >>= 3; + val &= 0x07; - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + *bits = val; - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + return c6xdigio_write_data(dev, cmd, status); +} +static void c6xdigio_pwm_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) +{ + unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan); + unsigned int bits; + + if (val > 498) + val = 498; + if (val < 2) + val = 2; + + bits = (val >> 0) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 2) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 4) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 6) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 8) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + + c6xdigio_write_data(dev, 0x00, 0x80); } -static int C6X_encInput(unsigned long baseAddr, unsigned channel) +static int c6xdigio_encoder_read(struct comedi_device *dev, + unsigned int chan) { - unsigned ppcmd; - union encvaluetype enc; - int timeout = 0; - int tmp; + unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan); + unsigned int val = 0; + unsigned int bits; - /* printk("Inside C6X_encInput\n"); */ + c6xdigio_write_data(dev, cmd, 0x00); - enc.value = 0; - if (channel == 0) - ppcmd = 0x48; - else - ppcmd = 0x50; + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 0); - WriteByteToHwPort(baseAddr, ppcmd); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 3); - enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 6); - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 9); - return enc.value ^ 0x800000; -} + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 12); -static void C6X_encResetAll(unsigned long baseAddr) -{ - unsigned timeout = 0; + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 15); -/* printk("Inside C6X_encResetAll\n"); */ + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 18); - WriteByteToHwPort(baseAddr, 0x68); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x6C); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x68); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } -} + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 21); -static int c6xdigio_pwmo_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - printk(KERN_DEBUG "c6xdigio_pwmo_insn_read %x\n", insn->n); - return insn->n; + c6xdigio_write_data(dev, 0x00, 0x80); + + return val; } -static int c6xdigio_pwmo_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int c6xdigio_pwm_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = (s->state >> (16 * chan)) & 0xffff; int i; - int chan = CR_CHAN(insn->chanspec); - /* printk("c6xdigio_pwmo_insn_write %x\n", insn->n); */ for (i = 0; i < insn->n; i++) { - C6X_pwmOutput(dev->iobase, chan, data[i]); - /* devpriv->ao_readback[chan] = data[i]; */ + val = data[i]; + c6xdigio_pwm_write(dev, chan, val); } - return i; + + /* + * There are only 2 PWM channels and they have a maxdata of 500. + * Instead of allocating private data to save the values in for + * readback this driver just packs the values for the two channels + * in the s->state. + */ + s->state &= (0xffff << (16 * chan)); + s->state |= (val << (16 * chan)); + + return insn->n; } -/* static int c6xdigio_ei_init_insn_read(struct comedi_device *dev, */ -/* struct comedi_subdevice *s, */ -/* struct comedi_insn *insn, */ -/* unsigned int *data) */ -/* { */ -/* printk("c6xdigio_ei_init_insn_read %x\n", insn->n); */ -/* return insn->n; */ -/* } */ - -/* static int c6xdigio_ei_init_insn_write(struct comedi_device *dev, */ -/* struct comedi_subdevice *s, */ -/* struct comedi_insn *insn, */ -/* unsigned int *data) */ -/* { */ -/* int i; */ -/* int chan = CR_CHAN(insn->chanspec); */ - /* *//* C6X_encResetAll( dev->iobase ); */ - /* *//* return insn->n; */ -/* } */ - -static int c6xdigio_ei_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int c6xdigio_pwm_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* printk("c6xdigio_ei__insn_read %x\n", insn->n); */ - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + val = (s->state >> (16 * chan)) & 0xffff; - for (n = 0; n < insn->n; n++) - data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff); + for (i = 0; i < insn->n; i++) + data[i] = val; - return n; + return insn->n; } -static void board_init(struct comedi_device *dev) +static int c6xdigio_encoder_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = c6xdigio_encoder_read(dev, chan); - /* printk("Inside board_init\n"); */ + /* munge two's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); + } - C6X_pwmInit(dev->iobase); - C6X_encResetAll(dev->iobase); + return insn->n; +} +static void c6xdigio_init(struct comedi_device *dev) +{ + /* Initialize the PWM */ + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x74, 0x80); + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); + + /* Reset the encoders */ + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x6c, 0x80); + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); } static const struct pnp_device_id c6xdigio_pnp_tbl[] = { @@ -411,7 +251,7 @@ static int c6xdigio_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], C6XDIGIO_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x03); if (ret) return ret; @@ -424,39 +264,26 @@ static int c6xdigio_attach(struct comedi_device *dev, s = &dev->subdevices[0]; /* pwm output subdevice */ - s->type = COMEDI_SUBD_AO; /* Not sure what to put here */ - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_pwmo; */ - s->insn_read = c6xdigio_pwmo_insn_read; - s->insn_write = c6xdigio_pwmo_insn_write; - s->maxdata = 500; - s->range_table = &range_bipolar10; /* A suitable lie */ + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 500; + s->range_table = &range_unknown; + s->insn_write = c6xdigio_pwm_insn_write; + s->insn_read = c6xdigio_pwm_insn_read; s = &dev->subdevices[1]; /* encoder (counter) subdevice */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_ei; */ - s->insn_read = c6xdigio_ei_insn_read; - s->maxdata = 0xffffff; - s->range_table = &range_unknown; - - /* s = &dev->subdevices[2]; */ - /* pwm output subdevice */ - /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */ - /* s->subdev_flags = SDF_WRITEABLE; */ - /* s->n_chan = 1; */ - /* s->trig[0] = c6xdigio_ei_init; */ - /* s->insn_read = c6xdigio_ei_init_insn_read; */ - /* s->insn_write = c6xdigio_ei_init_insn_write; */ - /* s->maxdata = 0xFFFF; // Really just a don't care */ - /* s->range_table = &range_unknown; // Not sure what to put here */ + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = 2; + s->maxdata = 0xffffff; + s->range_table = &range_unknown; + s->insn_read = c6xdigio_encoder_insn_read; /* I will call this init anyway but more than likely the DSP board */ /* will not be connected when device driver is loaded. */ - board_init(dev); + c6xdigio_init(dev); return 0; } @@ -476,5 +303,5 @@ static struct comedi_driver c6xdigio_driver = { module_comedi_driver(c6xdigio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index ae9a2082b5a..eb1b92d72e8 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -34,8 +34,8 @@ Status: experimental */ +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include <linux/delay.h> #include "../comedidev.h" @@ -95,10 +95,17 @@ static const struct comedi_lrange das16cs_ai_range = { } }; -static irqreturn_t das16cs_interrupt(int irq, void *d) +static int das16cs_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - /* struct comedi_device *dev = d; */ - return IRQ_HANDLED; + unsigned int status; + + status = inw(dev->iobase + DAS16CS_MISC1); + if (status & 0x0080) + return 0; + return -EBUSY; } static int das16cs_ai_rinsn(struct comedi_device *dev, @@ -109,8 +116,8 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); + int ret; int i; - int to; outw(chan, dev->iobase + DAS16CS_DIO_MUX); @@ -138,132 +145,16 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outw(0, dev->iobase + DAS16CS_ADC_DATA); -#define TIMEOUT 1000 - for (to = 0; to < TIMEOUT; to++) { - if (inw(dev->iobase + DAS16CS_MISC1) & 0x0080) - break; - } - if (to == TIMEOUT) { - dev_dbg(dev->class_dev, "cb_das16_cs: ai timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0); + if (ret) + return ret; + data[i] = inw(dev->iobase + DAS16CS_ADC_DATA); } return i; } -static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - return -EINVAL; -} - -static int das16cs_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int tmp; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - -#define MAX_SPEED 10000 /* in nanoseconds */ -#define MIN_SPEED 1000000000 /* in nanoseconds */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); - } - if (cmd->convert_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* see above */ - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); - } - - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - if (cmd->stop_src == TRIG_COUNT) - err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); - else /* TRIG_NONE */ - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(100, &div1, &div2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(100, &div1, &div2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } - - if (err) - return 4; - - return 0; -} - static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -293,6 +184,7 @@ static int das16cs_ao_winsn(struct comedi_device *dev, for (bit = 15; bit >= 0; bit--) { int b = (d >> bit) & 0x1; + b <<= 1; outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1); udelay(1); @@ -325,14 +217,11 @@ static int das16cs_ao_rinsn(struct comedi_device *dev, static int das16cs_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + DAS16CS_DIO); - } data[1] = inw(dev->iobase + DAS16CS_DIO); @@ -341,33 +230,22 @@ static int das16cs_dio_insn_bits(struct comedi_device *dev, static int das16cs_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct das16cs_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int bits; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; if (chan < 4) - bits = 0x0f; + mask = 0x0f; else - bits = 0xf0; + mask = 0xf0; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; devpriv->status2 &= ~0x00c0; devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0; @@ -415,22 +293,16 @@ static int das16cs_auto_attach(struct comedi_device *dev, dev->iobase = link->resource[0]->start; link->priv = dev; - ret = pcmcia_request_irq(link, das16cs_interrupt); - if (ret) - return ret; - dev->irq = link->irq; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; @@ -439,8 +311,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->range_table = &das16cs_ai_range; s->len_chanlist = 16; s->insn_read = das16cs_ai_rinsn; - s->do_cmd = das16cs_ai_cmd; - s->do_cmdtest = das16cs_ai_cmdtest; s = &dev->subdevices[1]; /* analog output subdevice */ @@ -466,10 +336,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->insn_bits = das16cs_dio_insn_bits; s->insn_config = das16cs_dio_insn_config; - dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx, irq=%u\n", - dev->driver->driver_name, dev->board_name, - dev->iobase, dev->irq); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 58bca184bf2..7377da1aff7 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -61,6 +61,7 @@ TODO: analog triggering on 1602 series */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -72,7 +73,6 @@ analog triggering on 1602 series #include "amcc_s5933.h" #include "comedi_fc.h" -#define TIMER_BASE 100 /* 10MHz master clock */ #define AI_BUFFER_SIZE 1024 /* max ai fifo size */ #define AO_BUFFER_SIZE 1024 /* max ao fifo size */ #define NUM_CHANNELS_8800 8 @@ -181,43 +181,40 @@ static inline unsigned int DAC_DATA_REG(unsigned int channel) /* analog input ranges for most boards */ static const struct comedi_lrange cb_pcidas_ranges = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; /* pci-das1001 input ranges */ static const struct comedi_lrange cb_pcidas_alt_ranges = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } + 8, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; /* analog output ranges */ static const struct comedi_lrange cb_pcidas_ao_ranges = { - 4, - { - BIP_RANGE(5), - BIP_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(10), - } + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } }; enum trimpot_model { @@ -357,15 +354,15 @@ struct cb_pcidas_private { unsigned int s5933_intcsr_bits; unsigned int ao_control_bits; /* fifo buffers */ - short ai_buffer[AI_BUFFER_SIZE]; - short ao_buffer[AO_BUFFER_SIZE]; + unsigned short ai_buffer[AI_BUFFER_SIZE]; + unsigned short ao_buffer[AO_BUFFER_SIZE]; /* divisors of master clock for analog output pacing */ unsigned int ao_divisor1; unsigned int ao_divisor2; /* number of analog output samples remaining */ unsigned int ao_count; /* cached values for readback */ - int ao_value[2]; + unsigned short ao_value[2]; unsigned int caldac_value[NUM_CHANNELS_8800]; unsigned int trimpot_value[NUM_CHANNELS_8402]; unsigned int dac08_value; @@ -379,6 +376,20 @@ static inline unsigned int cal_enable_bits(struct comedi_device *dev) return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); } +static int cb_pcidas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned int status; + + status = inw(devpriv->control_status + ADCMUX_CONT); + if (status & EOC) + return 0; + return -EBUSY; +} + static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -388,7 +399,8 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned int bits; - int n, i; + int ret; + int n; /* enable calibration input if appropriate */ if (insn->chanspec & CR_ALT_SOURCE) { @@ -418,13 +430,9 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, outw(0, devpriv->adc_fifo + ADCDATA); /* wait for conversion to end */ - /* return -ETIMEDOUT if there is a timeout */ - for (i = 0; i < 10000; i++) { - if (inw(devpriv->control_status + ADCMUX_CONT) & EOC) - break; - } - if (i == 10000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(devpriv->adc_fifo + ADCDATA); @@ -795,6 +803,33 @@ static int trimpot_read_insn(struct comedi_device *dev, return 1; } +static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + return 0; +} + static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -802,8 +837,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, const struct cb_pcidas_board *thisboard = comedi_board(dev); struct cb_pcidas_private *devpriv = dev->private; int err = 0; - int tmp; - int i, gain, start_chan; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -838,9 +872,12 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, if (err) return 2; - /* step 3: arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; case TRIG_EXT: /* External trigger, only CR_EDGE and CR_INVERT flags allowed */ if ((cmd->start_arg @@ -854,9 +891,6 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, err |= -EINVAL; } break; - default: - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - break; } if (cmd->scan_begin_src == TRIG_TIMER) @@ -878,47 +912,28 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -926,20 +941,16 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, return 0; } -static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns, - int rounding_flags) +static void cb_pcidas_ai_load_counters(struct comedi_device *dev) { struct cb_pcidas_private *devpriv = dev->private; + unsigned long timer_base = devpriv->pacer_counter_dio + ADC8254; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), - &(devpriv->divisor2), ns, - rounding_flags & TRIG_ROUND_MASK); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1, - devpriv->divisor1, 2); - i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 2, - devpriv->divisor2, 2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } static int cb_pcidas_ai_cmd(struct comedi_device *dev, @@ -977,12 +988,8 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, outw(bits, devpriv->control_status + ADCMUX_CONT); /* load counters */ - if (cmd->convert_src == TRIG_TIMER) - cb_pcidas_load_counters(dev, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - else if (cmd->scan_begin_src == TRIG_TIMER) - cb_pcidas_load_counters(dev, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + if (cmd->scan_begin_src == TRIG_TIMER || cmd->convert_src == TRIG_TIMER) + cb_pcidas_ai_load_counters(dev); /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) @@ -1011,9 +1018,9 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, /* set start trigger and burst mode */ bits = 0; - if (cmd->start_src == TRIG_NOW) + if (cmd->start_src == TRIG_NOW) { bits |= SW_TRIGGER; - else if (cmd->start_src == TRIG_EXT) { + } else { /* TRIG_EXT */ bits |= EXT_TRIGGER | TGEN | XTRCL; if (thisboard->is_1602) { if (cmd->start_arg & CR_INVERT) @@ -1021,9 +1028,6 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, if (cmd->start_arg & CR_EDGE) bits |= TGSEL; } - } else { - comedi_error(dev, "bug!"); - return -1; } if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) bits |= BURSTE; @@ -1032,6 +1036,25 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, return 0; } +static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + + if (cmd->chanlist_len > 1) { + unsigned int chan1 = CR_CHAN(cmd->chanlist[1]); + + if (chan0 != 0 || chan1 != 1) { + dev_dbg(dev->class_dev, + "channels must be ordered channel 0, channel 1 in chanlist\n"); + return -EINVAL; + } + } + + return 0; +} + static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -1039,7 +1062,7 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, const struct cb_pcidas_board *thisboard = comedi_board(dev); struct cb_pcidas_private *devpriv = dev->private; int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -1082,28 +1105,20 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->ao_divisor1), - &(devpriv->ao_divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->ao_divisor1, + &devpriv->ao_divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist && cmd->chanlist_len > 1) { - if (CR_CHAN(cmd->chanlist[0]) != 0 || - CR_CHAN(cmd->chanlist[1]) != 1) { - comedi_error(dev, - "channels must be ordered channel 0, channel 1 in chanlist\n"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1143,7 +1158,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; - if (trig_num != 0) + if (trig_num != cmd->start_arg) return -EINVAL; /* load up fifo */ @@ -1178,6 +1193,18 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, return 0; } +static void cb_pcidas_ao_load_counters(struct comedi_device *dev) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned long timer_base = devpriv->pacer_counter_dio + DAC8254; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->ao_divisor1); + i8254_write(timer_base, 0, 2, devpriv->ao_divisor2); +} + static int cb_pcidas_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1207,19 +1234,9 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, outw(0, devpriv->ao_registers + DACFIFOCLR); /* load counters */ - if (cmd->scan_begin_src == TRIG_TIMER) { - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->ao_divisor1), - &(devpriv->ao_divisor2), - &(cmd->scan_begin_arg), - cmd->flags); - - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1, - devpriv->ao_divisor1, 2); - i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2, - devpriv->ao_divisor2, 2); - } + if (cmd->scan_begin_src == TRIG_TIMER) + cb_pcidas_ao_load_counters(dev); + /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg; @@ -1276,8 +1293,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) unsigned int num_points; unsigned long flags; - async->events = 0; - if (status & DAEMI) { /* clear dac empty interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); @@ -1289,7 +1304,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) (cmd->stop_src == TRIG_COUNT && devpriv->ao_count)) { comedi_error(dev, "dac fifo underflow"); - cb_pcidas_ao_cancel(dev, s); async->events |= COMEDI_CB_ERROR; } async->events |= COMEDI_CB_EOA; @@ -1307,7 +1321,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) num_points * sizeof(short)); num_points = num_bytes / sizeof(short); - if (async->cmd.stop_src == TRIG_COUNT) + if (cmd->stop_src == TRIG_COUNT) devpriv->ao_count -= num_points; /* write data to board's fifo */ outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, @@ -1319,7 +1333,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) spin_unlock_irqrestore(&dev->spinlock, flags); } - comedi_event(dev, s); + cfc_handle_events(dev, s); } static irqreturn_t cb_pcidas_interrupt(int irq, void *d) @@ -1329,6 +1343,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) struct cb_pcidas_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async; + struct comedi_cmd *cmd; int status, s5933_status; int half_fifo = thisboard->fifo_size / 2; unsigned int num_samples, i; @@ -1339,7 +1354,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) return IRQ_NONE; async = s->async; - async->events = 0; + cmd = &async->cmd; s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); @@ -1362,7 +1377,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) if (status & ADHFI) { /* read data */ num_samples = half_fifo; - if (async->cmd.stop_src == TRIG_COUNT && + if (cmd->stop_src == TRIG_COUNT && num_samples > devpriv->count) { num_samples = devpriv->count; } @@ -1371,10 +1386,8 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) cfc_write_array_to_buffer(s, devpriv->ai_buffer, num_samples * sizeof(short)); devpriv->count -= num_samples; - if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) async->events |= COMEDI_CB_EOA; - cb_pcidas_cancel(dev, s); - } /* clear half-full interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | INT, @@ -1388,10 +1401,9 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) INT_ADCFIFO)) == 0) break; cfc_write_to_buffer(s, inw(devpriv->adc_fifo)); - if (async->cmd.stop_src == TRIG_COUNT && + if (cmd->stop_src == TRIG_COUNT && --devpriv->count == 0) { /* end of acquisition */ - cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -1418,11 +1430,10 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) outw(devpriv->adc_fifo_bits | LADFUL, devpriv->control_status + INT_ADCFIFO); spin_unlock_irqrestore(&dev->spinlock, flags); - cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -1444,10 +1455,9 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, dev->board_ptr = thisboard; dev->board_name = thisboard->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -1584,9 +1594,6 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } @@ -1619,7 +1626,7 @@ static int cb_pcidas_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = { +static const struct pci_device_id cb_pcidas_pci_table[] = { { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 }, { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 }, { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 }, diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 43c0bf58771..035c3a17600 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -82,6 +82,7 @@ TODO: #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -93,15 +94,6 @@ TODO: #include "plx9080.h" #include "comedi_fc.h" -#undef PCIDAS64_DEBUG /* disable debugging code */ -/* #define PCIDAS64_DEBUG enable debugging code */ - -#ifdef PCIDAS64_DEBUG -#define DEBUG_PRINT(format, args...) pr_debug(format, ## args) -#else -#define DEBUG_PRINT(format, args...) no_printk(format, ## args) -#endif - #define TIMER_BASE 25 /* 40MHz master clock */ /* 100kHz 'prescaled' clock for slow acquisition, * maybe I'll support this someday */ @@ -437,91 +429,85 @@ static inline uint8_t attenuate_bit(unsigned int channel) /* analog input ranges for 64xx boards */ static const struct comedi_lrange ai_ranges_64xx = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; /* analog input ranges for 60xx boards */ static const struct comedi_lrange ai_ranges_60xx = { - 4, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - } + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05) + } }; /* analog input ranges for 6030, etc boards */ static const struct comedi_lrange ai_ranges_6030 = { - 14, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.2), - BIP_RANGE(0.1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE(0.5), - UNI_RANGE(0.2), - UNI_RANGE(0.1), - } + 14, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2), + BIP_RANGE(0.1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; /* analog input ranges for 6052, etc boards */ static const struct comedi_lrange ai_ranges_6052 = { - 15, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.25), - BIP_RANGE(0.1), - BIP_RANGE(0.05), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE(0.5), - UNI_RANGE(0.2), - UNI_RANGE(0.1), - } + 15, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.25), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; /* analog input ranges for 4020 board */ static const struct comedi_lrange ai_ranges_4020 = { - 2, - { - BIP_RANGE(5), - BIP_RANGE(1), - } + 2, { + BIP_RANGE(5), + BIP_RANGE(1) + } }; /* analog output ranges */ static const struct comedi_lrange ao_ranges_64xx = { - 4, - { - BIP_RANGE(5), - BIP_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(10), - } + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } }; static const int ao_range_code_64xx[] = { @@ -536,11 +522,10 @@ static const int ao_range_code_60xx[] = { }; static const struct comedi_lrange ao_ranges_6030 = { - 2, - { - BIP_RANGE(10), - UNI_RANGE(10), - } + 2, { + BIP_RANGE(10), + UNI_RANGE(10) + } }; static const int ao_range_code_6030[] = { @@ -549,11 +534,10 @@ static const int ao_range_code_6030[] = { }; static const struct comedi_lrange ao_ranges_4020 = { - 2, - { - BIP_RANGE(5), - BIP_RANGE(10), - } + 2, { + BIP_RANGE(5), + BIP_RANGE(10) + } }; static const int ao_range_code_4020[] = { @@ -1136,7 +1120,7 @@ struct pcidas64_private { volatile short ai_cmd_running; unsigned int ai_fifo_segment_length; struct ext_clock_info ext_clock; - short ao_bounce_buffer[DAC_FIFO_SIZE]; + unsigned short ao_bounce_buffer[DAC_FIFO_SIZE]; }; static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, @@ -1251,8 +1235,6 @@ static void disable_ai_interrupts(struct comedi_device *dev) writew(devpriv->intr_enable_bits, devpriv->main_iobase + INTR_ENABLE_REG); spin_unlock_irqrestore(&dev->spinlock, flags); - - DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits); } static void enable_ai_interrupts(struct comedi_device *dev, @@ -1276,7 +1258,6 @@ static void enable_ai_interrupts(struct comedi_device *dev, devpriv->intr_enable_bits |= bits; writew(devpriv->intr_enable_bits, devpriv->main_iobase + INTR_ENABLE_REG); - DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits); spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -1291,38 +1272,6 @@ static void init_plx9080(struct comedi_device *dev) devpriv->plx_control_bits = readl(devpriv->plx9080_iobase + PLX_CONTROL_REG); - /* plx9080 dump */ - DEBUG_PRINT(" plx interrupt status 0x%x\n", - readl(plx_iobase + PLX_INTRCS_REG)); - DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG)); - DEBUG_PRINT(" plx control reg 0x%x\n", devpriv->plx_control_bits); - DEBUG_PRINT(" plx mode/arbitration reg 0x%x\n", - readl(plx_iobase + PLX_MARB_REG)); - DEBUG_PRINT(" plx region0 reg 0x%x\n", - readl(plx_iobase + PLX_REGION0_REG)); - DEBUG_PRINT(" plx region1 reg 0x%x\n", - readl(plx_iobase + PLX_REGION1_REG)); - - DEBUG_PRINT(" plx revision 0x%x\n", - readl(plx_iobase + PLX_REVISION_REG)); - DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n", - readl(plx_iobase + PLX_DMA0_MODE_REG)); - DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n", - readl(plx_iobase + PLX_DMA1_MODE_REG)); - DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n", - readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n", - readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n", - readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG)); - DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n", - readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG)); - DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n", - readb(plx_iobase + PLX_DMA0_CS_REG)); - DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n", - readl(plx_iobase + PLX_DMA0_THRESHOLD_REG)); - DEBUG_PRINT(" plx bigend 0x%x\n", readl(plx_iobase + PLX_BIGEND_REG)); - #ifdef __BIG_ENDIAN bits = BIGEND_DMA0 | BIGEND_DMA1; #else @@ -1416,9 +1365,6 @@ static int set_ai_fifo_segment_length(struct comedi_device *dev, devpriv->ai_fifo_segment_length = num_increments * increment_size; - DEBUG_PRINT("set hardware fifo segment length to %i\n", - devpriv->ai_fifo_segment_length); - return devpriv->ai_fifo_segment_length; } @@ -1440,8 +1386,6 @@ static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples) num_samples = retval * fifo->num_segments * fifo->sample_packing_ratio; - DEBUG_PRINT("set hardware fifo size to %i\n", num_samples); - return num_samples; } @@ -1537,8 +1481,6 @@ static int alloc_and_init_dma_members(struct comedi_device *dev) if (devpriv->ai_dma_desc == NULL) return -ENOMEM; - DEBUG_PRINT("ai dma descriptors start at bus addr 0x%llx\n", - (unsigned long long)devpriv->ai_dma_desc_bus_addr); if (ao_cmd_is_supported(thisboard)) { devpriv->ao_dma_desc = pci_alloc_consistent(pcidev, @@ -1547,9 +1489,6 @@ static int alloc_and_init_dma_members(struct comedi_device *dev) &devpriv->ao_dma_desc_bus_addr); if (devpriv->ao_dma_desc == NULL) return -ENOMEM; - - DEBUG_PRINT("ao dma descriptors start at bus addr 0x%llx\n", - (unsigned long long)devpriv->ao_dma_desc_bus_addr); } /* initialize dma descriptors */ for (i = 0; i < ai_dma_ring_count(thisboard); i++) { @@ -1649,8 +1588,6 @@ static void i2c_write_byte(struct comedi_device *dev, uint8_t byte) uint8_t bit; unsigned int num_bits = 8; - DEBUG_PRINT("writing to i2c byte 0x%x\n", byte); - for (bit = 1 << (num_bits - 1); bit; bit >>= 1) { i2c_set_scl(dev, 0); if ((byte & bit)) @@ -1727,17 +1664,37 @@ static void i2c_write(struct comedi_device *dev, unsigned int address, i2c_stop(dev); } +static int cb_pcidas64_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->main_iobase + HW_STATUS_REG); + if (thisboard->layout == LAYOUT_4020) { + status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG); + if (status) + return 0; + } else { + if (pipe_full_bits(status)) + return 0; + } + return -EBUSY; +} + static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct pcidas64_board *thisboard = comedi_board(dev); struct pcidas64_private *devpriv = dev->private; - unsigned int bits = 0, n, i; + unsigned int bits = 0, n; unsigned int channel, range, aref; unsigned long flags; - static const int timeout = 100; + int ret; - DEBUG_PRINT("chanspec 0x%x\n", insn->chanspec); channel = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); aref = CR_AREF(insn->chanspec); @@ -1765,7 +1722,6 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, if (insn->chanspec & CR_ALT_SOURCE) { unsigned int cal_en_bit; - DEBUG_PRINT("reading calibration source\n"); if (thisboard->layout == LAYOUT_60XX) cal_en_bit = CAL_EN_60XX_BIT; else @@ -1799,7 +1755,6 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; if (insn->chanspec & CR_ALT_SOURCE) { - DEBUG_PRINT("reading calibration source\n"); devpriv->i2c_cal_range_bits |= adc_src_4020_bits(devpriv->calibration_source); } else { /* select BNC inputs */ @@ -1836,25 +1791,10 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->main_iobase + ADC_CONVERT_REG); /* wait for data */ - for (i = 0; i < timeout; i++) { - bits = readw(devpriv->main_iobase + HW_STATUS_REG); - DEBUG_PRINT(" pipe bits 0x%x\n", pipe_full_bits(bits)); - if (thisboard->layout == LAYOUT_4020) { - if (readw(devpriv->main_iobase + - ADC_WRITE_PNTR_REG)) - break; - } else { - if (pipe_full_bits(bits)) - break; - } - udelay(1); - } - DEBUG_PRINT(" looped %i times waiting for data\n", i); - if (i == timeout) { - comedi_error(dev, " analog input read insn timed out"); - dev_info(dev->class_dev, "status 0x%x\n", bits); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0); + if (ret) + return ret; + if (thisboard->layout == LAYOUT_4020) data[n] = readl(devpriv->dio_counter_iobase + ADC_FIFO_REG) & 0xffff; @@ -1883,7 +1823,6 @@ static int ai_config_calibration_source(struct comedi_device *dev, return -EINVAL; } - DEBUG_PRINT("setting calibration source to %i\n", source); devpriv->calibration_source = source; return 2; @@ -2056,14 +1995,52 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) return; } +static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + const struct pcidas64_board *board = comedi_board(dev); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "all elements in chanlist must use the same analog reference\n"); + return -EINVAL; + } + } + + if (board->layout == LAYOUT_4020) { + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "chanlist must use consecutive channels\n"); + return -EINVAL; + } + } + if (cmd->chanlist_len == 3) { + dev_dbg(dev->class_dev, + "chanlist cannot be 3 channels long, use 1, 2, or 4 channels\n"); + return -EINVAL; + } + } + + return 0; +} + static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcidas64_board *thisboard = comedi_board(dev); int err = 0; unsigned int tmp_arg, tmp_arg2; - int i; - int aref; unsigned int triggers; /* Step 1 : check if triggers are trivially valid */ @@ -2101,15 +2078,24 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) err |= -EINVAL; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err |= -EINVAL; if (err) return 2; /* Step 3: check if arguments are trivially valid */ + switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* + * start_arg is the CR_CHAN | CR_INVERT of the + * external trigger. + */ + break; + } + if (cmd->convert_src == TRIG_TIMER) { if (thisboard->layout == LAYOUT_4020) { err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); @@ -2159,36 +2145,9 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - /* make sure user is doesn't change analog reference mid chanlist */ - if (cmd->chanlist) { - aref = CR_AREF(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (aref != CR_AREF(cmd->chanlist[i])) { - comedi_error(dev, - "all elements in chanlist must use the same analog reference"); - err++; - break; - } - } - /* check 4020 chanlist */ - if (thisboard->layout == LAYOUT_4020) { - unsigned int first_channel = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - first_channel + i) { - comedi_error(dev, - "chanlist must use consecutive channels"); - err++; - break; - } - } - if (cmd->chanlist_len == 3) { - comedi_error(dev, - "chanlist cannot be 3 channels long, use 1, 2, or 4 channels"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas64_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -2367,7 +2326,6 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd) /* load lower 16 bits of convert interval */ writew(convert_counter & 0xffff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); - DEBUG_PRINT("convert counter 0x%x\n", convert_counter); /* load upper 8 bits of convert interval */ writew((convert_counter >> 16) & 0xff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); @@ -2377,7 +2335,6 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd) /* load upper 8 bits of scan delay */ writew((scan_counter >> 16) & 0xff, devpriv->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG); - DEBUG_PRINT("scan counter 0x%x\n", scan_counter); } static int use_internal_queue_6xxx(const struct comedi_cmd *cmd) @@ -2468,9 +2425,6 @@ static int setup_channel_queue(struct comedi_device *dev, writew(bits, devpriv->main_iobase + ADC_QUEUE_FIFO_REG); - DEBUG_PRINT( - "wrote 0x%x to external channel queue\n", - bits); } /* doing a queue clear is not specified in board docs, * but required for reliable operation */ @@ -2592,7 +2546,6 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } writew(devpriv->adc_control1_bits, devpriv->main_iobase + ADC_CONTROL1_REG); - DEBUG_PRINT("control1 bits 0x%x\n", devpriv->adc_control1_bits); spin_unlock_irqrestore(&dev->spinlock, flags); /* clear adc buffer */ @@ -2644,17 +2597,14 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (use_hw_sample_counter(cmd)) bits |= ADC_SAMPLE_COUNTER_EN_BIT; writew(bits, devpriv->main_iobase + ADC_CONTROL0_REG); - DEBUG_PRINT("control0 bits 0x%x\n", bits); devpriv->ai_cmd_running = 1; spin_unlock_irqrestore(&dev->spinlock, flags); /* start acquisition */ - if (cmd->start_src == TRIG_NOW) { + if (cmd->start_src == TRIG_NOW) writew(0, devpriv->main_iobase + ADC_START_REG); - DEBUG_PRINT("soft trig\n"); - } return 0; } @@ -2689,10 +2639,6 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev) read_segment = adc_upper_read_ptr_code(prepost_bits); write_segment = adc_upper_write_ptr_code(prepost_bits); - DEBUG_PRINT(" rd seg %i, wrt seg %i, rd idx %i, wrt idx %i\n", - read_segment, write_segment, read_index, - write_index); - if (read_segment != write_segment) num_samples = devpriv->ai_fifo_segment_length - read_index; @@ -2714,8 +2660,6 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev) break; } - DEBUG_PRINT(" read %i samples from fifo\n", num_samples); - for (i = 0; i < num_samples; i++) { cfc_write_to_buffer(s, readw(devpriv->main_iobase + @@ -2779,6 +2723,7 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) const struct pcidas64_board *thisboard = comedi_board(dev); struct pcidas64_private *devpriv = dev->private; struct comedi_async *async = dev->read_subdev->async; + struct comedi_cmd *cmd = &async->cmd; uint32_t next_transfer_addr; int j; int num_samples = 0; @@ -2800,7 +2745,7 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) DMA_BUFFER_SIZE) && j < ai_dma_ring_count(thisboard); j++) { /* transfer data from dma buffer to comedi buffer */ num_samples = dma_transfer_size(dev); - if (async->cmd.stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) { if (num_samples > devpriv->ai_count) num_samples = devpriv->ai_count; devpriv->ai_count -= num_samples; @@ -2811,11 +2756,6 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) num_samples * sizeof(uint16_t)); devpriv->ai_dma_index = (devpriv->ai_dma_index + 1) % ai_dma_ring_count(thisboard); - - DEBUG_PRINT("next buffer addr 0x%lx\n", - (unsigned long)devpriv-> - ai_buffer_bus_addr[devpriv->ai_dma_index]); - DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr); } /* XXX check for dma ring buffer overrun * (use end-of-chain bit to mark last unused buffer) */ @@ -2844,24 +2784,17 @@ static void handle_ai_interrupt(struct comedi_device *dev, if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - DEBUG_PRINT("dma1 status 0x%x\n", dma1_status); if (dma1_status & PLX_DMA_EN_BIT) drain_dma_buffers(dev, 1); - - DEBUG_PRINT(" cleared dma ch1 interrupt\n"); } spin_unlock_irqrestore(&dev->spinlock, flags); - if (status & ADC_DONE_BIT) - DEBUG_PRINT("adc done interrupt\n"); - /* drain fifo with pio */ if ((status & ADC_DONE_BIT) || ((cmd->flags & TRIG_WAKE_EOS) && (status & ADC_INTR_PENDING_BIT) && (thisboard->layout != LAYOUT_4020))) { - DEBUG_PRINT("pio fifo drain\n"); spin_lock_irqsave(&dev->spinlock, flags); if (devpriv->ai_cmd_running) { spin_unlock_irqrestore(&dev->spinlock, flags); @@ -2946,7 +2879,6 @@ static void restart_ao_dma(struct comedi_device *dev) dma_desc_bits = readl(devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); dma_desc_bits &= ~PLX_END_OF_CHAIN_BIT; - DEBUG_PRINT("restarting ao dma, descriptor reg 0x%x\n", dma_desc_bits); load_first_dma_descriptor(dev, 0, dma_desc_bits); dma_start_sync(dev, 0); @@ -2962,11 +2894,7 @@ static unsigned int load_ao_dma_buffer(struct comedi_device *dev, buffer_index = devpriv->ao_dma_index; prev_buffer_index = prev_ao_dma_index(dev); - DEBUG_PRINT("attempting to load ao buffer %i (0x%llx)\n", buffer_index, - (unsigned long long)devpriv->ao_buffer_bus_addr[ - buffer_index]); - - num_bytes = comedi_buf_read_n_available(dev->write_subdev->async); + num_bytes = comedi_buf_read_n_available(dev->write_subdev); if (num_bytes > DMA_BUFFER_SIZE) num_bytes = DMA_BUFFER_SIZE; if (cmd->stop_src == TRIG_COUNT && num_bytes > devpriv->ao_count) @@ -2976,8 +2904,6 @@ static unsigned int load_ao_dma_buffer(struct comedi_device *dev, if (num_bytes == 0) return 0; - DEBUG_PRINT("loading %i bytes\n", num_bytes); - num_bytes = cfc_read_array_from_buffer(dev->write_subdev, devpriv-> ao_buffer[buffer_index], @@ -3051,14 +2977,12 @@ static void handle_ao_interrupt(struct comedi_device *dev, writeb(PLX_CLEAR_DMA_INTR_BIT, devpriv->plx9080_iobase + PLX_DMA0_CS_REG); spin_unlock_irqrestore(&dev->spinlock, flags); - DEBUG_PRINT("dma0 status 0x%x\n", dma0_status); if (dma0_status & PLX_DMA_EN_BIT) { load_ao_dma(dev, cmd); /* try to recover from dma end-of-chain event */ if (ao_dma_needs_restart(dev, dma0_status)) restart_ao_dma(dev); } - DEBUG_PRINT(" cleared dma ch0 interrupt\n"); } else { spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -3067,12 +2991,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, async->events |= COMEDI_CB_EOA; if (ao_stopped_by_error(dev, cmd)) async->events |= COMEDI_CB_ERROR; - DEBUG_PRINT("plx dma0 desc reg 0x%x\n", - readl(devpriv->plx9080_iobase + - PLX_DMA0_DESCRIPTOR_REG)); - DEBUG_PRINT("plx dma0 address reg 0x%x\n", - readl(devpriv->plx9080_iobase + - PLX_DMA0_PCI_ADDRESS_REG)); } cfc_handle_events(dev, s); } @@ -3088,15 +3006,12 @@ static irqreturn_t handle_interrupt(int irq, void *d) plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG); status = readw(devpriv->main_iobase + HW_STATUS_REG); - DEBUG_PRINT("hw status 0x%x, plx status 0x%x\n", status, plx_status); - /* an interrupt before all the postconfig stuff gets done could * cause a NULL dereference if we continue through the * interrupt handler */ - if (!dev->attached) { - DEBUG_PRINT("premature interrupt, ignoring\n"); + if (!dev->attached) return IRQ_HANDLED; - } + handle_ai_interrupt(dev, status, plx_status); handle_ao_interrupt(dev, status, plx_status); @@ -3104,11 +3019,8 @@ static irqreturn_t handle_interrupt(int irq, void *d) if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG); writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits); } - DEBUG_PRINT("exiting handler\n"); - return IRQ_HANDLED; } @@ -3129,7 +3041,6 @@ static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) abort_dma(dev, 1); - DEBUG_PRINT("ai canceled\n"); return 0; } @@ -3294,15 +3205,17 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) return 0; } -static inline int external_ai_queue_in_use(struct comedi_device *dev) +static inline int external_ai_queue_in_use(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { const struct pcidas64_board *thisboard = comedi_board(dev); - if (dev->read_subdev->busy) + if (s->busy) return 0; if (thisboard->layout == LAYOUT_4020) return 0; - else if (use_internal_queue_6xxx(&dev->read_subdev->async->cmd)) + else if (use_internal_queue_6xxx(cmd)) return 0; return 1; } @@ -3314,7 +3227,7 @@ static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd = &s->async->cmd; int retval; - if (trig_num != 0) + if (trig_num != cmd->start_arg) return -EINVAL; retval = prep_ao_dma(dev, cmd); @@ -3336,7 +3249,7 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct pcidas64_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - if (external_ai_queue_in_use(dev)) { + if (external_ai_queue_in_use(dev, s, cmd)) { warn_external_queue(dev); return -EBUSY; } @@ -3357,13 +3270,32 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "chanlist must use consecutive channels\n"); + return -EINVAL; + } + } + + return 0; +} + static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcidas64_board *thisboard = comedi_board(dev); int err = 0; unsigned int tmp_arg; - int i; /* Step 1 : check if triggers are trivially valid */ @@ -3395,6 +3327,8 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 3: check if arguments are trivially valid */ + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + if (cmd->scan_begin_src == TRIG_TIMER) { err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, thisboard->ao_scan_speed); @@ -3425,17 +3359,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - if (cmd->chanlist) { - unsigned int first_channel = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != first_channel + i) { - comedi_error(dev, - "chanlist must use consecutive channels"); - err++; - break; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas64_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -3457,7 +3383,6 @@ static int dio_callback(int dir, int port, int data, unsigned long arg) void __iomem *iobase = (void __iomem *)arg; if (dir) { writeb(data, iobase + port); - DEBUG_PRINT("wrote 0x%x to port %i\n", data, port); return 0; } else { return readb(iobase + port); @@ -3489,18 +3414,15 @@ static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int do_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcidas64_private *devpriv = dev->private; - data[0] &= 0xf; - /* zero bits we are going to change */ - s->state &= ~data[0]; - /* set new bits */ - s->state |= data[0] & data[1]; - - writeb(s->state, devpriv->dio_counter_iobase + DO_REG); + if (comedi_dio_update_state(s, data)) + writeb(s->state, devpriv->dio_counter_iobase + DO_REG); data[1] = s->state; @@ -3509,41 +3431,30 @@ static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, static int dio_60xx_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct pcidas64_private *devpriv = dev->private; - unsigned int mask; - - mask = 1 << CR_CHAN(insn->chanspec); + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - return 2; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; writeb(s->io_bits, devpriv->dio_counter_iobase + DIO_DIRECTION_60XX_REG); - return 1; + return insn->n; } -static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dio_60xx_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcidas64_private *devpriv = dev->private; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { writeb(s->state, devpriv->dio_counter_iobase + DIO_DATA_60XX_REG); } @@ -3949,16 +3860,19 @@ static int setup_subdevices(struct comedi_device *dev) if (thisboard->has_8255) { if (thisboard->layout == LAYOUT_4020) { dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG; - subdev_8255_init(dev, s, dio_callback_4020, - (unsigned long)dio_8255_iobase); + ret = subdev_8255_init(dev, s, dio_callback_4020, + (unsigned long)dio_8255_iobase); } else { dio_8255_iobase = devpriv->dio_counter_iobase + DIO_8255_OFFSET; - subdev_8255_init(dev, s, dio_callback, - (unsigned long)dio_8255_iobase); + ret = subdev_8255_init(dev, s, dio_callback, + (unsigned long)dio_8255_iobase); } - } else + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* 8 channel dio for 60xx */ s = &dev->subdevices[5]; @@ -4034,10 +3948,9 @@ static int auto_attach(struct comedi_device *dev, return -ENODEV; dev->board_ptr = thisboard; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; retval = comedi_pci_enable(dev); if (retval) @@ -4060,11 +3973,6 @@ static int auto_attach(struct comedi_device *dev, return -ENOMEM; } - DEBUG_PRINT(" plx9080 remapped to 0x%p\n", devpriv->plx9080_iobase); - DEBUG_PRINT(" main remapped to 0x%p\n", devpriv->main_iobase); - DEBUG_PRINT(" diocounter remapped to 0x%p\n", - devpriv->dio_counter_iobase); - /* figure out what local addresses are */ local_range = readl(devpriv->plx9080_iobase + PLX_LAS0RNG_REG) & LRNG_MEM_MASK; @@ -4079,9 +3987,6 @@ static int auto_attach(struct comedi_device *dev, devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase & ~local_range) | local_decode; - DEBUG_PRINT(" local 0 io addr 0x%x\n", devpriv->local0_iobase); - DEBUG_PRINT(" local 1 io addr 0x%x\n", devpriv->local1_iobase); - retval = alloc_and_init_dma_members(dev); if (retval < 0) return retval; @@ -4175,7 +4080,7 @@ static int cb_pcidas64_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = { +static const struct pci_device_id cb_pcidas64_pci_table[] = { { PCI_VDEVICE(CB, 0x001d), BOARD_PCIDAS6402_16 }, { PCI_VDEVICE(CB, 0x001e), BOARD_PCIDAS6402_12 }, { PCI_VDEVICE(CB, 0x0035), BOARD_PCIDAS64_M1_16 }, diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 2d3e920e598..901dc5d1bb7 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -37,6 +37,7 @@ * Only simple analog output writing is supported. */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -348,10 +349,9 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, dev->board_ptr = thisboard; dev->board_name = thisboard->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -388,8 +388,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, for (i = 0; i < thisboard->ao_chans; i++) cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } @@ -407,7 +405,7 @@ static int cb_pcidda_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = { +static const struct pci_device_id cb_pcidda_pci_table[] = { { PCI_VDEVICE(CB, 0x0020), BOARD_DDA02_12 }, { PCI_VDEVICE(CB, 0x0021), BOARD_DDA04_12 }, { PCI_VDEVICE(CB, 0x0022), BOARD_DDA08_12 }, diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index 8b5c198862a..50e522e6e69 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -31,12 +31,13 @@ Configuration Options: Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org). Only supports DIO, AO and simple AI in it's present form. -No interrupts, multi channel or FIFO AI, although the card looks like it could support this. +No interrupts, multi channel or FIFO AI, +although the card looks like it could support this. See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. */ +#include <linux/module.h> #include <linux/pci.h> -#include <linux/delay.h> #include <linux/interrupt.h> #include "../comedidev.h" @@ -44,9 +45,6 @@ See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. #include "plx9052.h" #include "8255.h" -/* #define CBPCIMDAS_DEBUG */ -#undef CBPCIMDAS_DEBUG - /* Registers for the PCIM-DAS1602/16 */ /* sizes of io regions (bytes) */ @@ -88,21 +86,31 @@ struct cb_pcimdas_private { unsigned int ao_readback[2]; }; -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int cb_pcimdas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct cb_pcimdas_private *devpriv = dev->private; + unsigned int status; + + status = inb(devpriv->BADR3 + 2); + if ((status & 0x80) == 0) + return 0; + return -EBUSY; +} + static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct cb_pcimdas_private *devpriv = dev->private; - int n, i; + int n; unsigned int d; - unsigned int busy; int chan = CR_CHAN(insn->chanspec); unsigned short chanlims; int maxchans; + int ret; /* only support sw initiated reads from a single channel */ @@ -121,8 +129,12 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, d = d & 0xfd; outb(d, devpriv->BADR3 + 5); } - outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */ - outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */ + + /* set bursting off, conversions on */ + outb(0x01, devpriv->BADR3 + 6); + + /* set range to 10V. UP/BP is controlled by a switch on the board */ + outb(0x00, devpriv->BADR3 + 7); /* * write channel limits to multiplexer, set Low (bits 0-3) and @@ -136,19 +148,11 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outw(0, dev->iobase + 0); -#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */ - /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */ - /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - busy = inb(devpriv->BADR3 + 2) & 0x80; - if (!busy) - break; - } - if (i == TIMEOUT) { - printk("timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0); + if (ret) + return ret; + /* read data */ data[n] = inw(dev->iobase + 0); } @@ -210,10 +214,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, unsigned long iobase_8255; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -223,15 +226,6 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, devpriv->BADR3 = pci_resource_start(pcidev, 3); iobase_8255 = pci_resource_start(pcidev, 4); -/* Dont support IRQ yet */ -/* get irq */ -/* if(request_irq(pcidev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */ -/* { */ -/* printk(" unable to allocate irq %u\n", pcidev->irq); */ -/* return -EINVAL; */ -/* } */ -/* dev->irq = pcidev->irq; */ - ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; @@ -261,9 +255,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, s = &dev->subdevices[2]; /* digital i/o subdevice */ - subdev_8255_init(dev, s, NULL, iobase_8255); - - dev_info(dev->class_dev, "%s attached\n", dev->board_name); + ret = subdev_8255_init(dev, s, NULL, iobase_8255); + if (ret) + return ret; return 0; } @@ -289,7 +283,7 @@ static int cb_pcimdas_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = { +static const struct pci_device_id cb_pcimdas_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 406cba8cba8..4a2b200de01 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -74,6 +74,7 @@ Configuration Options: not applicable, uses PCI auto config -Calin Culianu <calin@ajvar.org> */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -156,10 +157,9 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -187,9 +187,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, if (ret) return ret; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - - return 1; + return 0; } static struct comedi_driver cb_pcimdda_driver = { @@ -206,7 +204,7 @@ static int cb_pcimdda_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = { +static const struct pci_device_id cb_pcimdda_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_ID_PCIM_DDA06_16) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 1a51866be6f..8450c99af8b 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -1,130 +1,131 @@ /* - comedi/drivers/comedi_bond.c - A Comedi driver to 'bond' or merge multiple drivers and devices as one. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - Copyright (C) 2005 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: comedi_bond -Description: A driver to 'bond' (merge) multiple subdevices from multiple - devices together as one. -Devices: -Author: ds -Updated: Mon, 10 Oct 00:18:25 -0500 -Status: works - -This driver allows you to 'bond' (merge) multiple comedi subdevices -(coming from possibly difference boards and/or drivers) together. For -example, if you had a board with 2 different DIO subdevices, and -another with 1 DIO subdevice, you could 'bond' them with this driver -so that they look like one big fat DIO subdevice. This makes writing -applications slightly easier as you don't have to worry about managing -different subdevices in the application -- you just worry about -indexing one linear array of channel id's. - -Right now only DIO subdevices are supported as that's the personal itch -I am scratching with this driver. If you want to add support for AI and AO -subdevs, go right on ahead and do so! - -Commands aren't supported -- although it would be cool if they were. - -Configuration Options: - List of comedi-minors to bond. All subdevices of the same type - within each minor will be concatenated together in the order given here. -*/ + * comedi_bond.c + * A Comedi driver to 'bond' or merge multiple drivers and devices as one. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2005 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +/* + * Driver: comedi_bond + * Description: A driver to 'bond' (merge) multiple subdevices from multiple + * devices together as one. + * Devices: + * Author: ds + * Updated: Mon, 10 Oct 00:18:25 -0500 + * Status: works + * + * This driver allows you to 'bond' (merge) multiple comedi subdevices + * (coming from possibly difference boards and/or drivers) together. For + * example, if you had a board with 2 different DIO subdevices, and + * another with 1 DIO subdevice, you could 'bond' them with this driver + * so that they look like one big fat DIO subdevice. This makes writing + * applications slightly easier as you don't have to worry about managing + * different subdevices in the application -- you just worry about + * indexing one linear array of channel id's. + * + * Right now only DIO subdevices are supported as that's the personal itch + * I am scratching with this driver. If you want to add support for AI and AO + * subdevs, go right on ahead and do so! + * + * Commands aren't supported -- although it would be cool if they were. + * + * Configuration Options: + * List of comedi-minors to bond. All subdevices of the same type + * within each minor will be concatenated together in the order given here. + */ + +#include <linux/module.h> #include <linux/string.h> #include <linux/slab.h> #include "../comedi.h" #include "../comedilib.h" #include "../comedidev.h" -/* The maxiumum number of channels per subdevice. */ -#define MAX_CHANS 256 - -struct BondedDevice { +struct bonded_device { struct comedi_device *dev; unsigned minor; unsigned subdev; - unsigned subdev_type; unsigned nchans; - unsigned chanid_offset; /* The offset into our unified linear - channel-id's of chanid 0 on this - subdevice. */ }; -/* this structure is for data unique to this hardware driver. If - several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device struct. */ struct comedi_bond_private { # define MAX_BOARD_NAME 256 char name[MAX_BOARD_NAME]; - struct BondedDevice **devs; + struct bonded_device **devs; unsigned ndevs; - struct BondedDevice *chanIdDevMap[MAX_CHANS]; unsigned nchans; }; -/* DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ static int bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct comedi_bond_private *devpriv = dev->private; -#define LSAMPL_BITS (sizeof(unsigned int)*8) - unsigned nchans = LSAMPL_BITS, num_done = 0, i; - - if (devpriv->nchans < nchans) - nchans = devpriv->nchans; - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) { - struct BondedDevice *bdev = devpriv->devs[i]; - /* Grab the channel mask and data of only the bits corresponding - to this subdevice.. need to shift them to zero position of - course. */ - /* Bits corresponding to this subdev. */ - unsigned int subdevMask = ((1 << bdev->nchans) - 1); - unsigned int writeMask, dataBits; - - /* Argh, we have >= LSAMPL_BITS chans.. take all bits */ - if (bdev->nchans >= LSAMPL_BITS) - subdevMask = (unsigned int)(-1); - - writeMask = (data[0] >> num_done) & subdevMask; - dataBits = (data[1] >> num_done) & subdevMask; - - /* Read/Write the new digital lines */ - if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask, - &dataBits) != 2) - return -EINVAL; - - /* Make room for the new bits in data[1], the return value */ - data[1] &= ~(subdevMask << num_done); - /* Put the bits in the return value */ - data[1] |= (dataBits & subdevMask) << num_done; - /* Save the new bits to the saved state.. */ - s->state = data[1]; - - num_done += bdev->nchans; - } + unsigned int n_left, n_done, base_chan; + unsigned int write_mask, data_bits; + struct bonded_device **devs; + + write_mask = data[0]; + data_bits = data[1]; + base_chan = CR_CHAN(insn->chanspec); + /* do a maximum of 32 channels, starting from base_chan. */ + n_left = devpriv->nchans - base_chan; + if (n_left > 32) + n_left = 32; + + n_done = 0; + devs = devpriv->devs; + do { + struct bonded_device *bdev = *devs++; + + if (base_chan < bdev->nchans) { + /* base channel falls within bonded device */ + unsigned int b_chans, b_mask, b_write_mask, b_data_bits; + int ret; + + /* + * Get num channels to do for bonded device and set + * up mask and data bits for bonded device. + */ + b_chans = bdev->nchans - base_chan; + if (b_chans > n_left) + b_chans = n_left; + b_mask = (1U << b_chans) - 1; + b_write_mask = (write_mask >> n_done) & b_mask; + b_data_bits = (data_bits >> n_done) & b_mask; + /* Read/Write the new digital lines. */ + ret = comedi_dio_bitfield2(bdev->dev, bdev->subdev, + b_write_mask, &b_data_bits, + base_chan); + if (ret < 0) + return ret; + /* Place read bits into data[1]. */ + data[1] &= ~(b_mask << n_done); + data[1] |= (b_data_bits & b_mask) << n_done; + /* + * Set up for following bonded device (if still have + * channels to read/write). + */ + base_chan = 0; + n_done += b_chans; + n_left -= b_chans; + } else { + /* Skip bonded devices before base channel. */ + base_chan -= bdev->nchans; + } + } while (n_left); return insn->n; } @@ -134,99 +135,91 @@ static int bonding_dio_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct comedi_bond_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits; - unsigned int io; - struct BondedDevice *bdev; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; + struct bonded_device *bdev; + struct bonded_device **devs; - if (chan < 0 || chan >= devpriv->nchans) - return -EINVAL; - bdev = devpriv->chanIdDevMap[chan]; + /* + * Locate bonded subdevice and adjust channel. + */ + devs = devpriv->devs; + for (bdev = *devs++; chan >= bdev->nchans; bdev = *devs++) + chan -= bdev->nchans; - /* The input or output configuration of each digital line is + /* + * The input or output configuration of each digital line is * configured by a special insn_config instruction. chanspec * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + * configuration instruction INSN_CONFIG_DIO_OUTPUT, + * INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_QUERY. + * + * Note that INSN_CONFIG_DIO_OUTPUT == COMEDI_OUTPUT, + * and INSN_CONFIG_DIO_INPUT == COMEDI_INPUT. This is deliberate ;) + */ switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: - io = COMEDI_OUTPUT; /* is this really necessary? */ - io_bits |= 1 << chan; - break; case INSN_CONFIG_DIO_INPUT: - io = COMEDI_INPUT; /* is this really necessary? */ - io_bits &= ~(1 << chan); + ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, data[0]); break; case INSN_CONFIG_DIO_QUERY: - data[1] = - (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; + ret = comedi_dio_get_config(bdev->dev, bdev->subdev, chan, + &data[1]); break; default: - return -EINVAL; + ret = -EINVAL; break; } - /* 'real' channel id for this subdev.. */ - chan -= bdev->chanid_offset; - ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io); - if (ret != 1) - return -EINVAL; - /* Finally, save the new io_bits values since we didn't get - an error above. */ - s->io_bits = io_bits; - return insn->n; + if (ret >= 0) + ret = insn->n; + return ret; } -static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen) -{ - void *newmem = kmalloc(newlen, GFP_KERNEL); - - if (newmem && oldmem) - memcpy(newmem, oldmem, min(oldlen, newlen)); - kfree(oldmem); - return newmem; -} - -static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) +static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_bond_private *devpriv = dev->private; + DECLARE_BITMAP(devs_opened, COMEDI_NUM_BOARD_MINORS); int i; - struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS]; - memset(devs_opened, 0, sizeof(devs_opened)); + memset(&devs_opened, 0, sizeof(devs_opened)); devpriv->name[0] = 0; - /* Loop through all comedi devices specified on the command-line, - building our device list */ + /* + * Loop through all comedi devices specified on the command-line, + * building our device list. + */ for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) { - char file[] = "/dev/comediXXXXXX"; + char file[sizeof("/dev/comediXXXXXX")]; int minor = it->options[i]; struct comedi_device *d; - int sdev = -1, nchans, tmp; - struct BondedDevice *bdev = NULL; + int sdev = -1, nchans; + struct bonded_device *bdev; + struct bonded_device **devs; if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) { dev_err(dev->class_dev, "Minor %d is invalid!\n", minor); - return 0; + return -EINVAL; } if (minor == dev->minor) { dev_err(dev->class_dev, "Cannot bond this driver to itself!\n"); - return 0; + return -EINVAL; } - if (devs_opened[minor]) { + if (test_and_set_bit(minor, devs_opened)) { dev_err(dev->class_dev, "Minor %d specified more than once!\n", minor); - return 0; + return -EINVAL; } - snprintf(file, sizeof(file), "/dev/comedi%u", minor); + snprintf(file, sizeof(file), "/dev/comedi%d", minor); file[sizeof(file) - 1] = 0; - d = devs_opened[minor] = comedi_open(file); + d = comedi_open(file); if (!d) { dev_err(dev->class_dev, "Minor %u could not be opened\n", minor); - return 0; + return -ENODEV; } /* Do DIO, as that's all we support now.. */ @@ -237,45 +230,42 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) dev_err(dev->class_dev, "comedi_get_n_channels() returned %d on minor %u subdev %d!\n", nchans, minor, sdev); - return 0; + return -EINVAL; } bdev = kmalloc(sizeof(*bdev), GFP_KERNEL); if (!bdev) - return 0; + return -ENOMEM; bdev->dev = d; bdev->minor = minor; bdev->subdev = sdev; - bdev->subdev_type = COMEDI_SUBD_DIO; bdev->nchans = nchans; - bdev->chanid_offset = devpriv->nchans; + devpriv->nchans += nchans; - /* map channel id's to BondedDevice * pointer.. */ - while (nchans--) - devpriv->chanIdDevMap[devpriv->nchans++] = bdev; - - /* Now put bdev pointer at end of devpriv->devs array - * list.. */ + /* + * Now put bdev pointer at end of devpriv->devs array + * list.. + */ /* ergh.. ugly.. we need to realloc :( */ - tmp = devpriv->ndevs * sizeof(bdev); - devpriv->devs = - Realloc(devpriv->devs, - ++devpriv->ndevs * sizeof(bdev), tmp); - if (!devpriv->devs) { + devs = krealloc(devpriv->devs, + (devpriv->ndevs + 1) * sizeof(*devs), + GFP_KERNEL); + if (!devs) { dev_err(dev->class_dev, "Could not allocate memory. Out of memory?\n"); - return 0; + kfree(bdev); + return -ENOMEM; } - - devpriv->devs[devpriv->ndevs - 1] = bdev; + devpriv->devs = devs; + devpriv->devs[devpriv->ndevs++] = bdev; { - /** Append dev:subdev to devpriv->name */ + /* Append dev:subdev to devpriv->name */ char buf[20]; int left = MAX_BOARD_NAME - strlen(devpriv->name) - 1; - snprintf(buf, sizeof(buf), "%d:%d ", dev->minor, - bdev->subdev); + snprintf(buf, sizeof(buf), "%u:%u ", + bdev->minor, bdev->subdev); buf[sizeof(buf) - 1] = 0; strncat(devpriv->name, buf, left); } @@ -285,10 +275,10 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) if (!devpriv->nchans) { dev_err(dev->class_dev, "No channels found!\n"); - return 0; + return -EINVAL; } - return 1; + return 0; } static int bonding_attach(struct comedi_device *dev, @@ -298,16 +288,16 @@ static int bonding_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* * Setup our bonding from config params.. sets up our private struct.. */ - if (!doDevConfig(dev, it)) - return -EINVAL; + ret = do_dev_config(dev, it); + if (ret) + return ret; dev->board_name = devpriv->name; @@ -329,31 +319,29 @@ static int bonding_attach(struct comedi_device *dev, dev->driver->driver_name, dev->board_name, devpriv->nchans, devpriv->ndevs); - return 1; + return 0; } static void bonding_detach(struct comedi_device *dev) { struct comedi_bond_private *devpriv = dev->private; - unsigned long devs_closed = 0; - if (devpriv) { - while (devpriv->ndevs-- && devpriv->devs) { - struct BondedDevice *bdev; + if (devpriv && devpriv->devs) { + DECLARE_BITMAP(devs_closed, COMEDI_NUM_BOARD_MINORS); + + memset(&devs_closed, 0, sizeof(devs_closed)); + while (devpriv->ndevs--) { + struct bonded_device *bdev; bdev = devpriv->devs[devpriv->ndevs]; if (!bdev) continue; - if (!(devs_closed & (0x1 << bdev->minor))) { + if (!test_and_set_bit(bdev->minor, devs_closed)) comedi_close(bdev->dev); - devs_closed |= (0x1 << bdev->minor); - } kfree(bdev); } kfree(devpriv->devs); devpriv->devs = NULL; - kfree(devpriv); - dev->private = NULL; } } @@ -366,7 +354,5 @@ static struct comedi_driver bonding_driver = { module_comedi_driver(bonding_driver); MODULE_AUTHOR("Calin A. Culianu"); -MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI " - "devices together as one. In the words of John Lennon: " - "'And the world will live as one...'"); +MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI devices together as one."); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c index b3d89c82d08..c33c3e5680a 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ b/drivers/staging/comedi/drivers/comedi_fc.c @@ -1,33 +1,53 @@ /* - comedi/drivers/comedi_fc.c - - This is a place for code driver writers wish to share between - two or more drivers. fc is short - for frank-common. - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ - + * comedi_fc.c + * This is a place for code driver writers wish to share between + * two or more drivers. fc is short for frank-common. + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> #include "../comedidev.h" #include "comedi_fc.h" -static void increment_scan_progress(struct comedi_subdevice *subd, - unsigned int num_bytes) +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) { - struct comedi_async *async = subd->async; - unsigned int scan_length = cfc_bytes_per_scan(subd); + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int num_samples; + unsigned int bits_per_sample; + + switch (s->type) { + case COMEDI_SUBD_DI: + case COMEDI_SUBD_DO: + case COMEDI_SUBD_DIO: + bits_per_sample = 8 * bytes_per_sample(s); + num_samples = (cmd->chanlist_len + bits_per_sample - 1) / + bits_per_sample; + break; + default: + num_samples = cmd->chanlist_len; + break; + } + return num_samples * bytes_per_sample(s); +} +EXPORT_SYMBOL_GPL(cfc_bytes_per_scan); + +void cfc_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes) +{ + struct comedi_async *async = s->async; + unsigned int scan_length = cfc_bytes_per_scan(s); async->scan_progress += num_bytes; if (async->scan_progress >= scan_length) { @@ -35,80 +55,78 @@ static void increment_scan_progress(struct comedi_subdevice *subd, async->events |= COMEDI_CB_EOS; } } +EXPORT_SYMBOL_GPL(cfc_inc_scan_progress); /* Writes an array of data points to comedi's buffer */ -unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, +unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s, void *data, unsigned int num_bytes) { - struct comedi_async *async = subd->async; + struct comedi_async *async = s->async; unsigned int retval; if (num_bytes == 0) return 0; - retval = comedi_buf_write_alloc(async, num_bytes); + retval = comedi_buf_write_alloc(s, num_bytes); if (retval != num_bytes) { - dev_warn(subd->device->class_dev, "comedi: buffer overrun\n"); + dev_warn(s->device->class_dev, "buffer overrun\n"); async->events |= COMEDI_CB_OVERFLOW; return 0; } - comedi_buf_memcpy_to(async, 0, data, num_bytes); - comedi_buf_write_free(async, num_bytes); - increment_scan_progress(subd, num_bytes); + comedi_buf_memcpy_to(s, 0, data, num_bytes); + comedi_buf_write_free(s, num_bytes); + cfc_inc_scan_progress(s, num_bytes); async->events |= COMEDI_CB_BLOCK; return num_bytes; } EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer); -unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *s, void *data, unsigned int num_bytes) { - struct comedi_async *async = subd->async; - if (num_bytes == 0) return 0; - num_bytes = comedi_buf_read_alloc(async, num_bytes); - comedi_buf_memcpy_from(async, 0, data, num_bytes); - comedi_buf_read_free(async, num_bytes); - increment_scan_progress(subd, num_bytes); - async->events |= COMEDI_CB_BLOCK; + num_bytes = comedi_buf_read_alloc(s, num_bytes); + comedi_buf_memcpy_from(s, 0, data, num_bytes); + comedi_buf_read_free(s, num_bytes); + cfc_inc_scan_progress(s, num_bytes); + s->async->events |= COMEDI_CB_BLOCK; return num_bytes; } EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer); unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd) + struct comedi_subdevice *s) { - unsigned int events = subd->async->events; + unsigned int events = s->async->events; if (events == 0) return events; if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) - subd->cancel(dev, subd); + s->cancel(dev, s); - comedi_event(dev, subd); + comedi_event(dev, s); return events; } EXPORT_SYMBOL_GPL(cfc_handle_events); -MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); -MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); -MODULE_LICENSE("GPL"); - static int __init comedi_fc_init_module(void) { return 0; } +module_init(comedi_fc_init_module); static void __exit comedi_fc_cleanup_module(void) { } - -module_init(comedi_fc_init_module); module_exit(comedi_fc_cleanup_module); + +MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); +MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index a4dea7cb86b..541b9371d3d 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -1,72 +1,52 @@ /* - comedi_fc.h - - This is a place for code driver writers wish to share between - two or more drivers. These functions are meant to be used only - by drivers, they are NOT part of the kcomedilib API! - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi_fc.h + * This is a place for code driver writers wish to share between + * two or more drivers. These functions are meant to be used only + * by drivers, they are NOT part of the kcomedilib API! + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #ifndef _COMEDI_FC_H #define _COMEDI_FC_H #include "../comedidev.h" +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *); +void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes); + /* Writes an array of data points to comedi's buffer */ -extern unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); -static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *subd, - short data) +static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s, + unsigned short data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice - *subd, unsigned int data) +static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s, + unsigned int data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -extern unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); -extern unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd); - -static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *subd) -{ - int num_samples; - int bits_per_sample; - - switch (subd->type) { - case COMEDI_SUBD_DI: - case COMEDI_SUBD_DO: - case COMEDI_SUBD_DIO: - bits_per_sample = 8 * bytes_per_sample(subd); - num_samples = (subd->async->cmd.chanlist_len + - bits_per_sample - 1) / bits_per_sample; - break; - default: - num_samples = subd->async->cmd.chanlist_len; - break; - } - return num_samples * bytes_per_sample(subd); -} +unsigned int cfc_handle_events(struct comedi_device *, + struct comedi_subdevice *); /** * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index 772a8f5f0c1..a4274869235 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -1,168 +1,153 @@ /* - comedi/drivers/comedi_parport.c - hardware driver for standard parallel port - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998,2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: comedi_parport -Description: Standard PC parallel port -Author: ds -Status: works in immediate mode -Devices: [standard] parallel port (comedi_parport) -Updated: Tue, 30 Apr 2002 21:11:45 -0700 - -A cheap and easy way to get a few more digital I/O lines. Steal -additional parallel ports from old computers or your neighbors' -computers. - -Option list: - 0: I/O port base for the parallel port. - 1: IRQ - -Parallel Port Lines: - -pin subdev chan aka ---- ------ ---- --- -1 2 0 strobe -2 0 0 data 0 -3 0 1 data 1 -4 0 2 data 2 -5 0 3 data 3 -6 0 4 data 4 -7 0 5 data 5 -8 0 6 data 6 -9 0 7 data 7 -10 1 3 acknowledge -11 1 4 busy -12 1 2 output -13 1 1 printer selected -14 2 1 auto LF -15 1 0 error -16 2 2 init -17 2 3 select printer -18-25 ground - -Notes: - -Subdevices 0 is digital I/O, subdevice 1 is digital input, and -subdevice 2 is digital output. Unlike other Comedi devices, -subdevice 0 defaults to output. - -Pins 13 and 14 are inverted once by Comedi and once by the -hardware, thus cancelling the effect. - -Pin 1 is a strobe, thus acts like one. There's no way in software -to change this, at least on a standard parallel port. - -Subdevice 3 pretends to be a digital input subdevice, but it always -returns 0 when read. However, if you run a command with -scan_begin_src=TRIG_EXT, it uses pin 10 as a external triggering -pin, which can be used to wake up tasks. -*/ + * comedi_parport.c + * Comedi driver for standard parallel port + * + * For more information see: + * http://retired.beyondlogic.org/spp/parallel.htm + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998,2001 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* - see http://www.beyondlogic.org/ for information. - or http://www.linux-magazin.de/ausgabe/1999/10/IO/io.html + * Driver: comedi_parport + * Description: Standard PC parallel port + * Author: ds + * Status: works in immediate mode + * Devices: (standard) parallel port [comedi_parport] + * Updated: Tue, 30 Apr 2002 21:11:45 -0700 + * + * A cheap and easy way to get a few more digital I/O lines. Steal + * additional parallel ports from old computers or your neighbors' + * computers. + * + * Option list: + * 0: I/O port base for the parallel port. + * 1: IRQ (optional) + * + * Parallel Port Lines: + * + * pin subdev chan type name + * ----- ------ ---- ---- -------------- + * 1 2 0 DO strobe + * 2 0 0 DIO data 0 + * 3 0 1 DIO data 1 + * 4 0 2 DIO data 2 + * 5 0 3 DIO data 3 + * 6 0 4 DIO data 4 + * 7 0 5 DIO data 5 + * 8 0 6 DIO data 6 + * 9 0 7 DIO data 7 + * 10 1 3 DI ack + * 11 1 4 DI busy + * 12 1 2 DI paper out + * 13 1 1 DI select in + * 14 2 1 DO auto LF + * 15 1 0 DI error + * 16 2 2 DO init + * 17 2 3 DO select printer + * 18-25 ground + * + * When an IRQ is configured subdevice 3 pretends to be a digital + * input subdevice, but it always returns 0 when read. However, if + * you run a command with scan_begin_src=TRIG_EXT, it uses pin 10 + * as a external trigger, which can be used to wake up tasks. */ -#include "../comedidev.h" +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#include "comedi_fc.h" - -#define PARPORT_SIZE 3 - -#define PARPORT_A 0 -#define PARPORT_B 1 -#define PARPORT_C 2 +#include "../comedidev.h" -struct parport_private { - unsigned int a_data; - unsigned int c_data; - int enable_irq; -}; +#include "comedi_fc.h" -static int parport_insn_a(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +/* + * Register map + */ +#define PARPORT_DATA_REG 0x00 +#define PARPORT_STATUS_REG 0x01 +#define PARPORT_CTRL_REG 0x02 +#define PARPORT_CTRL_IRQ_ENA (1 << 4) +#define PARPORT_CTRL_BIDIR_ENA (1 << 5) + +static int parport_data_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct parport_private *devpriv = dev->private; - - if (data[0]) { - devpriv->a_data &= ~data[0]; - devpriv->a_data |= (data[0] & data[1]); - - outb(devpriv->a_data, dev->iobase + PARPORT_A); - } + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + PARPORT_DATA_REG); - data[1] = inb(dev->iobase + PARPORT_A); + data[1] = inb(dev->iobase + PARPORT_DATA_REG); return insn->n; } -static int parport_insn_config_a(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_data_reg_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct parport_private *devpriv = dev->private; - - if (data[0]) { - s->io_bits = 0xff; - devpriv->c_data &= ~(1 << 5); - } else { - s->io_bits = 0; - devpriv->c_data |= (1 << 5); - } - outb(devpriv->c_data, dev->iobase + PARPORT_C); + unsigned int ctrl; + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0xff); + if (ret) + return ret; + + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + if (s->io_bits) + ctrl &= ~PARPORT_CTRL_BIDIR_ENA; + else + ctrl |= PARPORT_CTRL_BIDIR_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); - return 1; + return insn->n; } -static int parport_insn_b(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_status_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - /* should writes be ignored? */ - /* anyone??? */ - } - - data[1] = (inb(dev->iobase + PARPORT_B) >> 3); + data[1] = inb(dev->iobase + PARPORT_STATUS_REG) >> 3; return insn->n; } -static int parport_insn_c(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_ctrl_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct parport_private *devpriv = dev->private; - - data[0] &= 0x0f; - if (data[0]) { - devpriv->c_data &= ~data[0]; - devpriv->c_data |= (data[0] & data[1]); + unsigned int ctrl; - outb(devpriv->c_data, dev->iobase + PARPORT_C); + if (comedi_dio_update_state(s, data)) { + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl &= (PARPORT_CTRL_IRQ_ENA | PARPORT_CTRL_BIDIR_ENA); + ctrl |= s->state; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); } - data[1] = devpriv->c_data & 0xf; + data[1] = s->state; return insn->n; } -static int parport_intr_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_intr_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { data[1] = 0; return insn->n; @@ -196,7 +181,7 @@ static int parport_intr_cmdtest(struct comedi_device *dev, 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, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -213,12 +198,11 @@ static int parport_intr_cmdtest(struct comedi_device *dev, static int parport_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct parport_private *devpriv = dev->private; + unsigned int ctrl; - devpriv->c_data |= 0x10; - outb(devpriv->c_data, dev->iobase + PARPORT_C); - - devpriv->enable_irq = 1; + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl |= PARPORT_CTRL_IRQ_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -226,12 +210,11 @@ static int parport_intr_cmd(struct comedi_device *dev, static int parport_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct parport_private *devpriv = dev->private; - - devpriv->c_data &= ~0x10; - outb(devpriv->c_data, dev->iobase + PARPORT_C); + unsigned int ctrl; - devpriv->enable_irq = 0; + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl &= ~PARPORT_CTRL_IRQ_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -239,13 +222,14 @@ static int parport_intr_cancel(struct comedi_device *dev, static irqreturn_t parport_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct parport_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[3]; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int ctrl; - if (!devpriv->enable_irq) + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + if (!(ctrl & PARPORT_CTRL_IRQ_ENA)) return IRQ_NONE; - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); @@ -255,80 +239,70 @@ static irqreturn_t parport_interrupt(int irq, void *d) static int parport_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct parport_private *devpriv; struct comedi_subdevice *s; - unsigned int irq; int ret; - ret = comedi_request_region(dev, it->options[0], PARPORT_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x03); if (ret) return ret; - irq = it->options[1]; - if (irq) { - ret = request_irq(irq, parport_interrupt, 0, dev->board_name, - dev); - if (ret < 0) { - dev_err(dev->class_dev, "irq not available\n"); - return -EINVAL; - } - dev->irq = irq; + if (it->options[1]) { + ret = request_irq(it->options[1], parport_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - ret = comedi_alloc_subdevices(dev, 4); + ret = comedi_alloc_subdevices(dev, dev->irq ? 4 : 3); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - + /* Digial I/O subdevice - Parallel port DATA register */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_a; - s->insn_config = parport_insn_config_a; - + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_data_reg_insn_bits; + s->insn_config = parport_data_reg_insn_config; + + /* Digial Input subdevice - Parallel port STATUS register */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 5; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_b; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 5; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_status_reg_insn_bits; + + /* Digial Output subdevice - Parallel port CONTROL register */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_c; - - s = &dev->subdevices[3]; - if (irq) { + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_ctrl_reg_insn_bits; + + if (dev->irq) { + /* Digial Input subdevice - Interrupt support */ + s = &dev->subdevices[3]; dev->read_subdev = s; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_intr_insn; - s->do_cmdtest = parport_intr_cmdtest; - s->do_cmd = parport_intr_cmd; - s->cancel = parport_intr_cancel; - } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_intr_insn_bits; + s->len_chanlist = 1; + s->do_cmdtest = parport_intr_cmdtest; + s->do_cmd = parport_intr_cmd; + s->cancel = parport_intr_cancel; } - devpriv->a_data = 0; - outb(devpriv->a_data, dev->iobase + PARPORT_A); - devpriv->c_data = 0; - outb(devpriv->c_data, dev->iobase + PARPORT_C); + outb(0, dev->iobase + PARPORT_DATA_REG); + outb(0, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -342,5 +316,5 @@ static struct comedi_driver parport_driver = { module_comedi_driver(parport_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi: Standard parallel port driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index 907e7a3822f..67a09aa6b72 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -45,6 +45,7 @@ zero volts). */ +#include <linux/module.h> #include "../comedidev.h" #include <asm/div64.h> @@ -73,11 +74,10 @@ static const int nano_per_micro = 1000; /* fake analog input ranges */ static const struct comedi_lrange waveform_ai_ranges = { - 2, - { - BIP_RANGE(10), - BIP_RANGE(5), - } + 2, { + BIP_RANGE(10), + BIP_RANGE(5) + } }; static unsigned short fake_sawtooth(struct comedi_device *dev, @@ -185,10 +185,10 @@ static void waveform_ai_interrupt(unsigned long arg) (devpriv->usec_remainder + elapsed_time) / devpriv->scan_period; devpriv->usec_remainder = (devpriv->usec_remainder + elapsed_time) % devpriv->scan_period; - async->events = 0; if (cmd->stop_src == TRIG_COUNT) { unsigned int remaining = cmd->stop_arg - devpriv->ai_count; + if (num_scans >= remaining) { /* about to finish */ num_scans = remaining; @@ -199,6 +199,7 @@ static void waveform_ai_interrupt(unsigned long arg) for (i = 0; i < num_scans; i++) { for (j = 0; j < cmd->chanlist_len; j++) { unsigned short sample; + sample = fake_waveform(dev, CR_CHAN(cmd->chanlist[j]), CR_RANGE(cmd->chanlist[j]), devpriv->usec_current + @@ -225,7 +226,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -277,22 +278,18 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; + arg = cmd->scan_begin_arg; /* round to nearest microsec */ - cmd->scan_begin_arg = - nano_per_micro * ((tmp + - (nano_per_micro / 2)) / nano_per_micro); - if (tmp != cmd->scan_begin_arg) - err++; + arg = nano_per_micro * + ((arg + (nano_per_micro / 2)) / nano_per_micro); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; + arg = cmd->convert_arg; /* round to nearest microsec */ - cmd->convert_arg = - nano_per_micro * ((tmp + - (nano_per_micro / 2)) / nano_per_micro); - if (tmp != cmd->convert_arg) - err++; + arg = nano_per_micro * + ((arg + (nano_per_micro / 2)) / nano_per_micro); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -318,12 +315,8 @@ static int waveform_ai_cmd(struct comedi_device *dev, if (cmd->convert_src == TRIG_NOW) devpriv->convert_period = 0; - else if (cmd->convert_src == TRIG_TIMER) + else /* TRIG_TIMER */ devpriv->convert_period = cmd->convert_arg / nano_per_micro; - else { - comedi_error(dev, "bug setting conversion period"); - return -1; - } do_gettimeofday(&devpriv->last); devpriv->usec_current = devpriv->last.tv_usec % devpriv->usec_period; @@ -379,10 +372,9 @@ static int waveform_attach(struct comedi_device *dev, int i; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* set default amplitude and period */ if (amplitude <= 0) @@ -419,11 +411,7 @@ static int waveform_attach(struct comedi_device *dev, s->n_chan = N_CHANS; s->maxdata = 0xffff; s->range_table = &waveform_ai_ranges; - s->len_chanlist = s->n_chan * 2; s->insn_write = waveform_ao_insn_write; - s->do_cmd = NULL; - s->do_cmdtest = NULL; - s->cancel = NULL; /* Our default loopback value is just a 0V flatline */ for (i = 0; i < s->n_chan; i++) diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 0fb9027dde2..0a9c32e9db4 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -25,6 +25,7 @@ Status: works Configuration Options: not applicable, uses comedi PCI auto config */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -39,17 +40,11 @@ Configuration Options: not applicable, uses comedi PCI auto config static int contec_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PIO1616L_DO_REG); - } data[1] = s->state; @@ -97,8 +92,6 @@ static int contec_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = contec_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } @@ -116,7 +109,7 @@ static int contec_pci_dio_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = { +static const struct pci_device_id contec_pci_dio_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c new file mode 100644 index 00000000000..df46e0a5bad --- /dev/null +++ b/drivers/staging/comedi/drivers/dac02.c @@ -0,0 +1,172 @@ +/* + * dac02.c + * Comedi driver for DAC02 compatible boards + * Copyright (C) 2014 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the poc driver + * Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2001 David A. Schleef <ds@schleef.org> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Driver: dac02 + * Description: Comedi driver for DAC02 compatible boards + * Devices: (Keithley Metrabyte) DAC-02 [dac02] + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Tue, 11 Mar 2014 11:27:19 -0700 + * Status: unknown + * + * Configuration options: + * [0] - I/O port base + */ + +#include <linux/module.h> + +#include "../comedidev.h" + +/* + * The output range is selected by jumpering pins on the I/O connector. + * + * Range Chan # Jumper pins Output + * ------------- ------ ------------- ----------------- + * 0 to 5V 0 21 to 22 24 + * 1 15 to 16 18 + * 0 to 10V 0 20 to 22 24 + * 1 14 to 16 18 + * +/-5V 0 21 to 22 23 + * 1 15 to 16 17 + * +/-10V 0 20 to 22 23 + * 1 14 to 16 17 + * 4 to 20mA 0 21 to 22 25 + * 1 15 to 16 19 + * AC reference 0 In on pin 22 24 (2-quadrant) + * In on pin 22 23 (4-quadrant) + * 1 In on pin 16 18 (2-quadrant) + * In on pin 16 17 (4-quadrant) + */ +static const struct comedi_lrange das02_ao_ranges = { + 6, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10), + RANGE_mA(4, 20), + RANGE_ext(0, 1) + } +}; + +struct dac02_private { + unsigned int ao_readback[2]; +}; + +/* + * Register I/O map + */ +#define DAC02_AO_LSB(x) (0x00 + ((x) * 2)) +#define DAC02_AO_MSB(x) (0x01 + ((x) * 2)) + +static int dac02_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dac02_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* + * Unipolar outputs are true binary encoding. + * Bipolar outputs are complementary offset binary + * (that is, 0 = +full scale, maxdata = -full scale). + */ + if (comedi_range_is_bipolar(s, range)) + val = s->maxdata - val; + + /* + * DACs are double-buffered. + * Write LSB then MSB to latch output. + */ + outb((val << 4) & 0xf0, dev->iobase + DAC02_AO_LSB(chan)); + outb((val >> 4) & 0xff, dev->iobase + DAC02_AO_MSB(chan)); + } + + return insn->n; +} + +static int dac02_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dac02_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct dac02_private *devpriv; + struct comedi_subdevice *s; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], 0x08); + if (ret) + return ret; + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + /* Analog Output subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &das02_ao_ranges; + s->insn_write = dac02_ao_insn_write; + s->insn_read = dac02_ao_insn_read; + + return 0; +} + +static struct comedi_driver dac02_driver = { + .driver_name = "dac02", + .module = THIS_MODULE, + .attach = dac02_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dac02_driver); + +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("Comedi driver for DAC02 compatible boards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 44c912b48b6..a8f6036ad82 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -102,6 +102,7 @@ Configuration options: not applicable, uses PCI auto config */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -332,14 +333,28 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) writeAcqScanListEntry(dev, word3); } +static int daqboard2000_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->daq + acqControl); + if (status & context) + return 0; + return -EBUSY; +} + static int daqboard2000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct daqboard2000_private *devpriv = dev->private; - unsigned int val; - int gain, chan, timeout; + int gain, chan; + int ret; int i; writew(DAQBOARD2000_AcqResetScanListFifo | @@ -366,25 +381,24 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, /* Enable reading from the scanlist FIFO */ writew(DAQBOARD2000_SeqStartScanList, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqConfigPipeFull) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqConfigPipeFull); + if (ret) + return ret; + writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqLogicScanning) - break; - /* udelay(2); */ - } - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqResultsFIFOHasValidData) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqLogicScanning); + if (ret) + return ret; + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqResultsFIFOHasValidData); + if (ret) + return ret; + data[i] = readw(devpriv->daq + acqResultsFIFO); writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); @@ -408,6 +422,21 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev, return i; } +static int daqboard2000_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int status; + + status = readw(devpriv->daq + dacControl); + if ((status & ((chan + 1) * 0x0010)) == 0) + return 0; + return -EBUSY; +} + static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -415,8 +444,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, { struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); - unsigned int val; - int timeout; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -430,12 +458,11 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, udelay(1000); #endif writew(data[i], devpriv->daq + dacSetting(chan)); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + dacControl); - if ((val & ((chan + 1) * 0x0010)) == 0) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; #if 0 /* @@ -683,10 +710,9 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; result = comedi_pci_enable(dev); if (result) @@ -737,9 +763,6 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, if (result) return result; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } @@ -772,7 +795,7 @@ static int daqboard2000_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = { +static const struct pci_device_id daqboard2000_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_IOTECH, 0x0409) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 2e7e3e20239..c5e352fb555 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -33,7 +33,7 @@ * cheap das08 hardware doesn't really support them. */ -#include <linux/delay.h> +#include <linux/module.h> #include "../comedidev.h" @@ -120,46 +120,49 @@ /* gainlist same as _pgx_ below */ -static const struct comedi_lrange range_das08_pgl = { 9, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } +static const struct comedi_lrange range_das08_pgl = { + 9, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_das08_pgh = { 12, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.1), - BIP_RANGE(0.05), - BIP_RANGE(0.01), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - } +static const struct comedi_lrange range_das08_pgh = { + 12, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + BIP_RANGE(0.01), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; -static const struct comedi_lrange range_das08_pgm = { 9, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.01), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } +static const struct comedi_lrange range_das08_pgm = { + 9, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.01), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; /* cio-das08jr.pdf @@ -198,17 +201,29 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; -#define TIMEOUT 100000 +static int das08_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS08_STATUS); + if ((status & DAS08_EOC) == 0) + return 0; + return -EBUSY; +} static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das08_board_struct *thisboard = comedi_board(dev); struct das08_private_struct *devpriv = dev->private; - int i, n; + int n; int chan; int range; int lsb, msb; + int ret; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -241,14 +256,10 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); - for (i = 0; i < TIMEOUT; i++) { - if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC)) - break; - } - if (i == TIMEOUT) { - dev_err(dev->class_dev, "timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0); + if (ret) + return ret; + msb = inb(dev->iobase + DAS08_MSB); lsb = inb(dev->iobase + DAS08_LSB); if (thisboard->ai_encoding == das08_encode12) { @@ -279,27 +290,23 @@ static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08_do_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das08_private_struct *devpriv = dev->private; - int wbits; - - /* get current settings of digital output lines */ - wbits = (devpriv->do_mux_bits >> 4) & 0xf; - /* null bits we are going to set */ - wbits &= ~data[0]; - /* set new bit values */ - wbits |= data[0] & data[1]; - /* remember digital output bits */ - /* prevent race with setting of analog input mux */ - spin_lock(&dev->spinlock); - devpriv->do_mux_bits &= ~DAS08_DO_MASK; - devpriv->do_mux_bits |= DAS08_OP(wbits); - outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); - spin_unlock(&dev->spinlock); - data[1] = wbits; + if (comedi_dio_update_state(s, data)) { + /* prevent race with setting of analog input mux */ + spin_lock(&dev->spinlock); + devpriv->do_mux_bits &= ~DAS08_DO_MASK; + devpriv->do_mux_bits |= DAS08_OP(s->state); + outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); + spin_unlock(&dev->spinlock); + } + + data[1] = s->state; return insn->n; } @@ -316,17 +323,13 @@ static int das08jr_di_rbits(struct comedi_device *dev, static int das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct das08_private_struct *devpriv = dev->private; - - /* null bits we are going to set */ - devpriv->do_bits &= ~data[0]; - /* set new bit values */ - devpriv->do_bits |= data[0] & data[1]; - outb(devpriv->do_bits, dev->iobase + DAS08JR_DIO); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS08JR_DIO); - data[1] = devpriv->do_bits; + data[1] = s->state; return insn->n; } @@ -534,9 +537,10 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s = &dev->subdevices[4]; /* 8255 */ if (thisboard->i8255_offset != 0) { - subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase + - thisboard-> - i8255_offset)); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + thisboard->i8255_offset); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index cce1b584200..18cc170facd 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -40,8 +40,9 @@ struct das08_board_struct { }; struct das08_private_struct { - unsigned int do_mux_bits; /* bits for do/mux register on boards without separate do register */ - unsigned int do_bits; /* bits for do register on boards with register dedicated to digital out only */ + unsigned int do_mux_bits; /* bits for do/mux register on boards + * without separate do register + */ const unsigned int *pg_gainlist; unsigned int ao_readback[2]; /* assume 2 AO channels */ }; diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 885fb179c9b..f3ccc2ce6d4 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -39,8 +39,7 @@ Options (for pcm-das08): Command support does not exist, but could be added for this board. */ -#include <linux/delay.h> -#include <linux/slab.h> +#include <linux/module.h> #include "../comedidev.h" @@ -78,10 +77,9 @@ static int das08_cs_auto_attach(struct comedi_device *dev, return ret; iobase = link->resource[0]->start; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; return das08_common_attach(dev, iobase); } diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c index 21a94389b8b..4fb03d3852d 100644 --- a/drivers/staging/comedi/drivers/das08_isa.c +++ b/drivers/staging/comedi/drivers/das08_isa.c @@ -43,6 +43,7 @@ * [0] - base io address */ +#include <linux/module.h> #include "../comedidev.h" #include "das08.h" @@ -177,10 +178,9 @@ static int das08_isa_attach(struct comedi_device *dev, struct das08_private_struct *devpriv; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_request_region(dev, it->options[0], thisboard->iosize); if (ret) diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c index 9c5d234e063..d94af09151b 100644 --- a/drivers/staging/comedi/drivers/das08_pci.c +++ b/drivers/staging/comedi/drivers/das08_pci.c @@ -31,6 +31,7 @@ * Configuration Options: not applicable, uses PCI auto config */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -59,10 +60,9 @@ static int das08_pci_auto_attach(struct comedi_device *dev, struct das08_private_struct *devpriv; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* The das08 driver needs the board_ptr */ dev->board_ptr = &das08_pci_boards[0]; @@ -89,7 +89,7 @@ static int das08_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = { +static const struct pci_device_id das08_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_PCIDAS08) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index dbec3ba9954..2feecf199f2 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -1,80 +1,89 @@ /* - comedi/drivers/das16.c - DAS16 driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com> - Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: das16 -Description: DAS16 compatible boards -Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze -Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g), - DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202), - DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601), - DAS-1602 (das-1602), - [ComputerBoards] PC104-DAS16/JR (pc104-das16jr), - PC104-DAS16JR/16 (pc104-das16jr/16), - CIO-DAS16JR/16 (cio-das16jr/16), - CIO-DAS16/JR (cio-das16/jr), CIO-DAS1401/12 (cio-das1401/12), - CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16), - CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12), - CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330) -Status: works -Updated: 2003-10-12 - -A rewrite of the das16 and das1600 drivers. -Options: - [0] - base io address - [1] - irq (does nothing, irq is not used anymore) - [2] - dma (optional, required for comedi_command support) - [3] - master clock speed in MHz (optional, 1 or 10, ignored if - board can probe clock, defaults to 1) - [4] - analog input range lowest voltage in microvolts (optional, - only useful if your board does not have software - programmable gain) - [5] - analog input range highest voltage in microvolts (optional, - only useful if board does not have software programmable - gain) - [6] - analog output range lowest voltage in microvolts (optional) - [7] - analog output range highest voltage in microvolts (optional) - [8] - use timer mode for DMA. Timer mode is needed e.g. for - buggy DMA controllers in NS CS5530A (Geode Companion), and for - 'jr' cards that lack a hardware fifo. This option is no - longer needed, since timer mode is _always_ used. - -Passing a zero for an option is the same as leaving it unspecified. + * das16.c + * DAS16 driver + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com> + * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -*/ /* + * Driver: das16 + * Description: DAS16 compatible boards + * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze + * Devices: (Keithley Metrabyte) DAS-16 [das-16] + * (Keithley Metrabyte) DAS-16G [das-16g] + * (Keithley Metrabyte) DAS-16F [das-16f] + * (Keithley Metrabyte) DAS-1201 [das-1201] + * (Keithley Metrabyte) DAS-1202 [das-1202] + * (Keithley Metrabyte) DAS-1401 [das-1401] + * (Keithley Metrabyte) DAS-1402 [das-1402] + * (Keithley Metrabyte) DAS-1601 [das-1601] + * (Keithley Metrabyte) DAS-1602 [das-1602] + * (ComputerBoards) PC104-DAS16/JR [pc104-das16jr] + * (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16] + * (ComputerBoards) CIO-DAS16 [cio-das16] + * (ComputerBoards) CIO-DAS16F [cio-das16/f] + * (ComputerBoards) CIO-DAS16/JR [cio-das16/jr] + * (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16] + * (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12] + * (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12] + * (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16] + * (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12] + * (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12] + * (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16] + * (ComputerBoards) CIO-DAS16/330 [cio-das16/330] + * Status: works + * Updated: 2003-10-12 + * + * A rewrite of the das16 and das1600 drivers. + * + * Options: + * [0] - base io address + * [1] - irq (does nothing, irq is not used anymore) + * [2] - dma channel (optional, required for comedi_command support) + * [3] - master clock speed in MHz (optional, 1 or 10, ignored if + * board can probe clock, defaults to 1) + * [4] - analog input range lowest voltage in microvolts (optional, + * only useful if your board does not have software + * programmable gain) + * [5] - analog input range highest voltage in microvolts (optional, + * only useful if board does not have software programmable + * gain) + * [6] - analog output range lowest voltage in microvolts (optional) + * [7] - analog output range highest voltage in microvolts (optional) + * + * Passing a zero for an option is the same as leaving it unspecified. + */ -Testing and debugging help provided by Daniel Koch. - -Keithley Manuals: - 2309.PDF (das16) - 4919.PDF (das1400, 1600) - 4922.PDF (das-1400) - 4923.PDF (das1200, 1400, 1600) - -Computer boards manuals also available from their website -www.measurementcomputing.com - -*/ +/* + * Testing and debugging help provided by Daniel Koch. + * + * Keithley Manuals: + * 2309.PDF (das16) + * 4919.PDF (das1400, 1600) + * 4922.PDF (das-1400) + * 4923.PDF (das1200, 1400, 1600) + * + * Computer boards manuals also available from their website + * www.measurementcomputing.com + */ -#include <linux/pci.h> +#include <linux/module.h> #include <linux/slab.h> +#include <linux/delay.h> +#include <linux/pci.h> #include <linux/interrupt.h> #include <asm/dma.h> @@ -85,214 +94,112 @@ www.measurementcomputing.com #include "8255.h" #include "comedi_fc.h" -#undef DEBUG -/* #define DEBUG */ - -#ifdef DEBUG -#define DEBUG_PRINT(format, args...) \ - printk(KERN_DEBUG "das16: " format, ## args) -#else -#define DEBUG_PRINT(format, args...) -#endif - -#define DAS16_SIZE 20 /* number of ioports */ #define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */ /* - cio-das16.pdf - - "das16" - "das16/f" - - 0 a/d bits 0-3 start 12 bit - 1 a/d bits 4-11 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4 unused ao0_lsb - 5 unused ao0_msb - 6 unused ao1_lsb - 7 unused ao1_msb - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b reserved reserved - cdef 8254 - 0123 8255 - -*/ - -/* - cio-das16jr.pdf - - "das16jr" - - 0 a/d bits 0-3 start 12 bit - 1 a/d bits 4-11 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4567 unused unused - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b gain status gain control - cdef 8254 - -*/ - -/* - cio-das16jr_16.pdf - - "das16jr_16" - - 0 a/d bits 0-7 start 16 bit - 1 a/d bits 8-15 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4567 unused unused - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b gain status gain control - cdef 8254 - -*/ -/* - cio-das160x-1x.pdf - - "das1601/12" - "das1602/12" - "das1602/16" - - 0 a/d bits 0-3 start 12 bit - 1 a/d bits 4-11 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4 unused ao0_lsb - 5 unused ao0_msb - 6 unused ao1_lsb - 7 unused ao1_msb - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b gain status gain control - cdef 8254 - 400 8255 - 404 unused conversion enable - 405 unused burst enable - 406 unused das1600 enable - 407 status - -*/ - -/* size in bytes of a sample from board */ -static const int sample_size = 2; - -#define DAS16_TRIG 0 -#define DAS16_AI_LSB 0 -#define DAS16_AI_MSB 1 -#define DAS16_MUX 2 -#define DAS16_DIO 3 -#define DAS16_AO_LSB(x) ((x) ? 6 : 4) -#define DAS16_AO_MSB(x) ((x) ? 7 : 5) -#define DAS16_STATUS 8 -#define BUSY (1<<7) -#define UNIPOLAR (1<<6) -#define DAS16_MUXBIT (1<<5) -#define DAS16_INT (1<<4) -#define DAS16_CONTROL 9 -#define DAS16_INTE (1<<7) -#define DAS16_IRQ(x) (((x) & 0x7) << 4) -#define DMA_ENABLE (1<<2) -#define PACING_MASK 0x3 -#define INT_PACER 0x03 -#define EXT_PACER 0x02 -#define DAS16_SOFT 0x00 -#define DAS16_PACER 0x0A -#define DAS16_CTR0 (1<<1) -#define DAS16_TRIG0 (1<<0) -#define BURST_LEN_BITS(x) (((x) & 0xf) << 4) -#define DAS16_GAIN 0x0B -#define DAS16_CNTR0_DATA 0x0C -#define DAS16_CNTR1_DATA 0x0D -#define DAS16_CNTR2_DATA 0x0E -#define DAS16_CNTR_CONTROL 0x0F -#define DAS16_TERM_CNT 0x00 -#define DAS16_ONE_SHOT 0x02 -#define DAS16_RATE_GEN 0x04 -#define DAS16_CNTR_LSB_MSB 0x30 -#define DAS16_CNTR0 0x00 -#define DAS16_CNTR1 0x40 -#define DAS16_CNTR2 0x80 - -#define DAS1600_CONV 0x404 -#define DAS1600_CONV_DISABLE 0x40 -#define DAS1600_BURST 0x405 -#define DAS1600_BURST_VAL 0x40 -#define DAS1600_ENABLE 0x406 -#define DAS1600_ENABLE_VAL 0x40 -#define DAS1600_STATUS_B 0x407 -#define DAS1600_BME 0x40 -#define DAS1600_ME 0x20 -#define DAS1600_CD 0x10 -#define DAS1600_WS 0x02 -#define DAS1600_CLK_10MHZ 0x01 - -static const struct comedi_lrange range_das1x01_bip = { 4, { - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - } + * Register I/O map + */ +#define DAS16_TRIG_REG 0x00 +#define DAS16_AI_LSB_REG 0x00 +#define DAS16_AI_MSB_REG 0x01 +#define DAS16_MUX_REG 0x02 +#define DAS16_DIO_REG 0x03 +#define DAS16_AO_LSB_REG(x) ((x) ? 0x06 : 0x04) +#define DAS16_AO_MSB_REG(x) ((x) ? 0x07 : 0x05) +#define DAS16_STATUS_REG 0x08 +#define DAS16_STATUS_BUSY (1 << 7) +#define DAS16_STATUS_UNIPOLAR (1 << 6) +#define DAS16_STATUS_MUXBIT (1 << 5) +#define DAS16_STATUS_INT (1 << 4) +#define DAS16_CTRL_REG 0x09 +#define DAS16_CTRL_INTE (1 << 7) +#define DAS16_CTRL_IRQ(x) (((x) & 0x7) << 4) +#define DAS16_CTRL_DMAE (1 << 2) +#define DAS16_CTRL_PACING_MASK (3 << 0) +#define DAS16_CTRL_INT_PACER (3 << 0) +#define DAS16_CTRL_EXT_PACER (2 << 0) +#define DAS16_CTRL_SOFT_PACER (0 << 0) +#define DAS16_PACER_REG 0x0a +#define DAS16_PACER_BURST_LEN(x) (((x) & 0xf) << 4) +#define DAS16_PACER_CTR0 (1 << 1) +#define DAS16_PACER_TRIG0 (1 << 0) +#define DAS16_GAIN_REG 0x0b +#define DAS16_TIMER_BASE_REG 0x0c /* to 0x0f */ + +#define DAS1600_CONV_REG 0x404 +#define DAS1600_CONV_DISABLE (1 << 6) +#define DAS1600_BURST_REG 0x405 +#define DAS1600_BURST_VAL (1 << 6) +#define DAS1600_ENABLE_REG 0x406 +#define DAS1600_ENABLE_VAL (1 << 6) +#define DAS1600_STATUS_REG 0x407 +#define DAS1600_STATUS_BME (1 << 6) +#define DAS1600_STATUS_ME (1 << 5) +#define DAS1600_STATUS_CD (1 << 4) +#define DAS1600_STATUS_WS (1 << 1) +#define DAS1600_STATUS_CLK_10MHZ (1 << 0) + +static const struct comedi_lrange range_das1x01_bip = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_das1x01_unip = { 4, { - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - } +static const struct comedi_lrange range_das1x01_unip = { + 4, { + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; -static const struct comedi_lrange range_das1x02_bip = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - } +static const struct comedi_lrange range_das1x02_bip = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } }; -static const struct comedi_lrange range_das1x02_unip = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_das1x02_unip = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_das16jr = { 9, { - /* also used by 16/330 */ - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_das16jr = { + 9, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_das16jr_16 = { 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_das16jr_16 = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 }; @@ -330,30 +237,211 @@ static const struct comedi_lrange *const das16_ai_bip_lranges[] = { &range_das1x02_bip, }; -struct munge_info { - uint8_t byte; - unsigned have_byte:1; -}; - struct das16_board { const char *name; - void *ai; - unsigned int ai_nbits; + unsigned int ai_maxdata; unsigned int ai_speed; /* max conversion speed in nanosec */ unsigned int ai_pg; - void *ao; - unsigned int ao_nbits; - void *di; - void *do_; + unsigned int has_ao:1; + unsigned int has_8255:1; unsigned int i8255_offset; - unsigned int i8254_offset; unsigned int size; unsigned int id; }; -#define DAS16_TIMEOUT 1000 +static const struct das16_board das16_boards[] = { + { + .name = "das-16", + .ai_maxdata = 0x0fff, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x00, + }, { + .name = "das-16g", + .ai_maxdata = 0x0fff, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x00, + }, { + .name = "das-16f", + .ai_maxdata = 0x0fff, + .ai_speed = 8500, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x00, + }, { + .name = "cio-das16", + .ai_maxdata = 0x0fff, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x80, + }, { + .name = "cio-das16/f", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x80, + }, { + .name = "cio-das16/jr", + .ai_maxdata = 0x0fff, + .ai_speed = 7692, + .ai_pg = das16_pg_16jr, + .size = 0x10, + .id = 0x00, + }, { + .name = "pc104-das16jr", + .ai_maxdata = 0x0fff, + .ai_speed = 3300, + .ai_pg = das16_pg_16jr, + .size = 0x10, + .id = 0x00, + }, { + .name = "cio-das16jr/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .size = 0x10, + .id = 0x00, + }, { + .name = "pc104-das16jr/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .size = 0x10, + .id = 0x00, + }, { + .name = "das-1201", + .ai_maxdata = 0x0fff, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0x20, + }, { + .name = "das-1202", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0x20, + }, { + .name = "das-1401", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1402", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1601", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1602", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1401/12", + .ai_maxdata = 0x0fff, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1402/12", + .ai_maxdata = 0x0fff, + .ai_speed = 6250, + .ai_pg = das16_pg_1602, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1402/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1601/12", + .ai_maxdata = 0x0fff, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1602/12", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1602/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das16/330", + .ai_maxdata = 0x0fff, + .ai_speed = 3030, + .ai_pg = das16_pg_16jr, + .size = 0x14, + .id = 0xf0, + }, +}; /* Period for timer interrupt in jiffies. It's a function * to deal with possibility of dynamic HZ patches */ @@ -363,59 +451,205 @@ static inline int timer_period(void) } struct das16_private_struct { - unsigned int ai_unipolar; /* unipolar flag */ - unsigned int ai_singleended; /* single ended flag */ - unsigned int clockbase; /* master clock speed in ns */ - volatile unsigned int control_state; /* dma, interrupt and trigger control bits */ - volatile unsigned long adc_byte_count; /* number of bytes remaining */ - /* divisor dividing master clock to get conversion frequency */ - unsigned int divisor1; - /* divisor dividing master clock to get conversion frequency */ - unsigned int divisor2; - unsigned int dma_chan; /* dma channel */ - uint16_t *dma_buffer[2]; - dma_addr_t dma_buffer_addr[2]; - unsigned int current_buffer; - volatile unsigned int dma_transfer_size; /* target number of bytes to transfer per dma shot */ - /** - * user-defined analog input and output ranges - * defined from config options - */ - struct comedi_lrange *user_ai_range_table; - struct comedi_lrange *user_ao_range_table; - - struct timer_list timer; /* for timed interrupt */ - volatile short timer_running; - volatile short timer_mode; /* true if using timer mode */ - - unsigned long extra_iobase; + unsigned int clockbase; + unsigned int ctrl_reg; + unsigned long adc_byte_count; + unsigned int divisor1; + unsigned int divisor2; + unsigned int dma_chan; + uint16_t *dma_buffer[2]; + dma_addr_t dma_buffer_addr[2]; + unsigned int current_buffer; + unsigned int dma_transfer_size; + struct comedi_lrange *user_ai_range_table; + struct comedi_lrange *user_ao_range_table; + struct timer_list timer; + short timer_running; + unsigned long extra_iobase; + unsigned int can_burst:1; }; +static void das16_ai_enable(struct comedi_device *dev, + unsigned int mode, unsigned int src) +{ + struct das16_private_struct *devpriv = dev->private; + + devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | + DAS16_CTRL_DMAE | + DAS16_CTRL_PACING_MASK); + devpriv->ctrl_reg |= mode; + + if (src == TRIG_EXT) + devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER; + else + devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER; + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); +} + +static void das16_ai_disable(struct comedi_device *dev) +{ + struct das16_private_struct *devpriv = dev->private; + + /* disable interrupts, dma and pacer clocked conversions */ + devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | + DAS16_CTRL_DMAE | + DAS16_CTRL_PACING_MASK); + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); +} + +/* the pc104-das16jr (at least) has problems if the dma + transfer is interrupted in the middle of transferring + a 16 bit sample, so this function takes care to get + an even transfer count after disabling dma + channel. +*/ +static int disable_dma_on_even(struct comedi_device *dev) +{ + struct das16_private_struct *devpriv = dev->private; + int residue; + int i; + static const int disable_limit = 100; + static const int enable_timeout = 100; + + disable_dma(devpriv->dma_chan); + residue = get_dma_residue(devpriv->dma_chan); + for (i = 0; i < disable_limit && (residue % 2); ++i) { + int j; + enable_dma(devpriv->dma_chan); + for (j = 0; j < enable_timeout; ++j) { + int new_residue; + udelay(2); + new_residue = get_dma_residue(devpriv->dma_chan); + if (new_residue != residue) + break; + } + disable_dma(devpriv->dma_chan); + residue = get_dma_residue(devpriv->dma_chan); + } + if (i == disable_limit) { + dev_err(dev->class_dev, + "failed to get an even dma transfer, could be trouble\n"); + } + return residue; +} + +static void das16_interrupt(struct comedi_device *dev) +{ + struct das16_private_struct *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned long spin_flags; + unsigned long dma_flags; + int num_bytes, residue; + int buffer_index; + + spin_lock_irqsave(&dev->spinlock, spin_flags); + if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) { + spin_unlock_irqrestore(&dev->spinlock, spin_flags); + return; + } + + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma_chan); + residue = disable_dma_on_even(dev); + + /* figure out how many points to read */ + if (residue > devpriv->dma_transfer_size) { + dev_err(dev->class_dev, "residue > transfer size!\n"); + async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + num_bytes = 0; + } else + num_bytes = devpriv->dma_transfer_size - residue; + + if (cmd->stop_src == TRIG_COUNT && + num_bytes >= devpriv->adc_byte_count) { + num_bytes = devpriv->adc_byte_count; + async->events |= COMEDI_CB_EOA; + } + + buffer_index = devpriv->current_buffer; + devpriv->current_buffer = (devpriv->current_buffer + 1) % 2; + devpriv->adc_byte_count -= num_bytes; + + /* re-enable dma */ + if ((async->events & COMEDI_CB_EOA) == 0) { + set_dma_addr(devpriv->dma_chan, + devpriv->dma_buffer_addr[devpriv->current_buffer]); + set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); + enable_dma(devpriv->dma_chan); + } + release_dma_lock(dma_flags); + + spin_unlock_irqrestore(&dev->spinlock, spin_flags); + + cfc_write_array_to_buffer(s, + devpriv->dma_buffer[buffer_index], num_bytes); + + cfc_handle_events(dev, s); +} + +static void das16_timer_interrupt(unsigned long arg) +{ + struct comedi_device *dev = (struct comedi_device *)arg; + struct das16_private_struct *devpriv = dev->private; + + das16_interrupt(dev); + + if (devpriv->timer_running) + mod_timer(&devpriv->timer, jiffies + timer_period()); +} + +static int das16_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != ((chan0 + i) % s->n_chan)) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; +} + static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct das16_board *board = comedi_board(dev); struct das16_private_struct *devpriv = dev->private; - int err = 0, tmp; - int gain, start_chan, i; - int mask; + int err = 0; + unsigned int trig_mask; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - mask = TRIG_FOLLOW; - /* if board supports burst mode */ - if (board->size > 0x400) - mask |= TRIG_TIMER | TRIG_EXT; - err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask); + trig_mask = TRIG_FOLLOW; + if (devpriv->can_burst) + trig_mask |= TRIG_TIMER | TRIG_EXT; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, trig_mask); - tmp = cmd->convert_src; - mask = TRIG_TIMER | TRIG_EXT; - /* if board supports burst mode */ - if (board->size > 0x400) - mask |= TRIG_NOW; - err |= cfc_check_trigger_src(&cmd->convert_src, mask); + trig_mask = TRIG_TIMER | TRIG_EXT; + if (devpriv->can_burst) + trig_mask |= TRIG_NOW; + err |= cfc_check_trigger_src(&cmd->convert_src, trig_mask); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -466,110 +700,48 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, /* step 4: fix up arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int tmp = cmd->scan_begin_arg; - /* set divisors, correct timing arguments */ - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); - err += (tmp != cmd->scan_begin_arg); + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - unsigned int tmp = cmd->convert_arg; - /* set divisors, correct timing arguments */ - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - err += (tmp != cmd->convert_arg); + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be " - "consecutive channels, " - "counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all " - "have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das16_ai_check_chanlist(dev, s, cmd); + if (err) return 5; return 0; } -/* utility function that suggests a dma transfer size in bytes */ -static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, - const struct comedi_cmd *cmd) -{ - struct das16_private_struct *devpriv = dev->private; - unsigned int size; - unsigned int freq; - - /* if we are using timer interrupt, we don't care how long it - * will take to complete transfer since it will be interrupted - * by timer interrupt */ - if (devpriv->timer_mode) - return DAS16_DMA_SIZE; - - /* otherwise, we are relying on dma terminal count interrupt, - * so pick a reasonable size */ - if (cmd->convert_src == TRIG_TIMER) - freq = 1000000000 / cmd->convert_arg; - else if (cmd->scan_begin_src == TRIG_TIMER) - freq = (1000000000 / cmd->scan_begin_arg) * cmd->chanlist_len; - /* return some default value */ - else - freq = 0xffffffff; - - if (cmd->flags & TRIG_WAKE_EOS) { - size = sample_size * cmd->chanlist_len; - } else { - /* make buffer fill in no more than 1/3 second */ - size = (freq / 3) * sample_size; - } - - /* set a minimum and maximum size allowed */ - if (size > DAS16_DMA_SIZE) - size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size; - else if (size < sample_size) - size = sample_size; - - if (cmd->stop_src == TRIG_COUNT && size > devpriv->adc_byte_count) - size = devpriv->adc_byte_count; - - return size; -} - static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, int rounding_flags) { struct das16_private_struct *devpriv = dev->private; + unsigned long timer_base = dev->iobase + DAS16_TIMER_BASE_REG; - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), - &(devpriv->divisor2), &ns, - rounding_flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, &devpriv->divisor2, + &ns, rounding_flags); - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2); - i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); return ns; } @@ -584,30 +756,21 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) unsigned long flags; int range; - if (devpriv->dma_chan == 0 || (dev->irq == 0 - && devpriv->timer_mode == 0)) { - comedi_error(dev, - "irq (or use of 'timer mode') dma required to " - "execute comedi_cmd"); - return -1; - } if (cmd->flags & TRIG_RT) { - comedi_error(dev, "isa dma transfers cannot be performed with " - "TRIG_RT, aborting"); + dev_err(dev->class_dev, + "isa dma transfers cannot be performed with TRIG_RT, aborting\n"); return -1; } - devpriv->adc_byte_count = - cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t); + devpriv->adc_byte_count = cmd->stop_arg * cfc_bytes_per_scan(s); - /* disable conversions for das1600 mode */ - if (board->size > 0x400) - outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV); + if (devpriv->can_burst) + outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG); /* set scan limits */ byte = CR_CHAN(cmd->chanlist[0]); byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4; - outb(byte, dev->iobase + DAS16_MUX); + outb(byte, dev->iobase + DAS16_MUX_REG); /* set gain (this is also burst rate register but according to * computer boards manual, burst rate does nothing, even on @@ -615,28 +778,27 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) if (board->ai_pg != das16_pg_none) { range = CR_RANGE(cmd->chanlist[0]); outb((das16_gainlists[board->ai_pg])[range], - dev->iobase + DAS16_GAIN); + dev->iobase + DAS16_GAIN_REG); } /* set counter mode and counts */ cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); - DEBUG_PRINT("pacer period: %d ns\n", cmd->convert_arg); /* enable counters */ byte = 0; - /* Enable burst mode if appropriate. */ - if (board->size > 0x400) { + if (devpriv->can_burst) { if (cmd->convert_src == TRIG_NOW) { - outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST); + outb(DAS1600_BURST_VAL, + dev->iobase + DAS1600_BURST_REG); /* set burst length */ - byte |= BURST_LEN_BITS(cmd->chanlist_len - 1); + byte |= DAS16_PACER_BURST_LEN(cmd->chanlist_len - 1); } else { - outb(0, dev->iobase + DAS1600_BURST); + outb(0, dev->iobase + DAS1600_BURST_REG); } } - outb(byte, dev->iobase + DAS16_PACER); + outb(byte, dev->iobase + DAS16_PACER_REG); /* set up dma transfer */ flags = claim_dma_lock(); @@ -647,465 +809,212 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->current_buffer = 0; set_dma_addr(devpriv->dma_chan, devpriv->dma_buffer_addr[devpriv->current_buffer]); - /* set appropriate size of transfer */ - devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, cmd); + devpriv->dma_transfer_size = DAS16_DMA_SIZE; set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(flags); /* set up interrupt */ - if (devpriv->timer_mode) { - devpriv->timer_running = 1; - devpriv->timer.expires = jiffies + timer_period(); - add_timer(&devpriv->timer); - devpriv->control_state &= ~DAS16_INTE; - } else { - /* clear interrupt bit */ - outb(0x00, dev->iobase + DAS16_STATUS); - /* enable interrupts */ - devpriv->control_state |= DAS16_INTE; - } - devpriv->control_state |= DMA_ENABLE; - devpriv->control_state &= ~PACING_MASK; - if (cmd->convert_src == TRIG_EXT) - devpriv->control_state |= EXT_PACER; - else - devpriv->control_state |= INT_PACER; - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); + devpriv->timer_running = 1; + devpriv->timer.expires = jiffies + timer_period(); + add_timer(&devpriv->timer); - /* Enable conversions if using das1600 mode */ - if (board->size > 0x400) - outb(0, dev->iobase + DAS1600_CONV); + das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src); + if (devpriv->can_burst) + outb(0, dev->iobase + DAS1600_CONV_REG); return 0; } static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct das16_board *board = comedi_board(dev); struct das16_private_struct *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); - /* disable interrupts, dma and pacer clocked conversions */ - devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE; - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); - if (devpriv->dma_chan) - disable_dma(devpriv->dma_chan); + + das16_ai_disable(dev); + disable_dma(devpriv->dma_chan); /* disable SW timer */ - if (devpriv->timer_mode && devpriv->timer_running) { + if (devpriv->timer_running) { devpriv->timer_running = 0; del_timer(&devpriv->timer); } - /* disable burst mode */ - if (board->size > 0x400) - outb(0, dev->iobase + DAS1600_BURST); - + if (devpriv->can_burst) + outb(0, dev->iobase + DAS1600_BURST_REG); spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } -static void das16_reset(struct comedi_device *dev) +static void das16_ai_munge(struct comedi_device *dev, + struct comedi_subdevice *s, void *array, + unsigned int num_bytes, + unsigned int start_chan_index) { - outb(0, dev->iobase + DAS16_STATUS); - outb(0, dev->iobase + DAS16_CONTROL); - outb(0, dev->iobase + DAS16_PACER); - outb(0, dev->iobase + DAS16_CNTR_CONTROL); + unsigned int i, num_samples = num_bytes / sizeof(short); + unsigned short *data = array; + + for (i = 0; i < num_samples; i++) { + data[i] = le16_to_cpu(data[i]); + if (s->maxdata == 0x0fff) + data[i] >>= 4; + data[i] &= s->maxdata; + } } -static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS16_STATUS_REG); + if ((status & DAS16_STATUS_BUSY) == 0) + return 0; + return -EBUSY; +} + +static int das16_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct das16_board *board = comedi_board(dev); - struct das16_private_struct *devpriv = dev->private; - int i, n; - int range; - int chan; - int msb, lsb; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int ret; + int i; - /* disable interrupts and pacing */ - devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK; - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); + das16_ai_disable(dev); /* set multiplexer */ - chan = CR_CHAN(insn->chanspec); - chan |= CR_CHAN(insn->chanspec) << 4; - outb(chan, dev->iobase + DAS16_MUX); + outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG); /* set gain */ if (board->ai_pg != das16_pg_none) { - range = CR_RANGE(insn->chanspec); outb((das16_gainlists[board->ai_pg])[range], - dev->iobase + DAS16_GAIN); + dev->iobase + DAS16_GAIN_REG); } - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { /* trigger conversion */ - outb_p(0, dev->iobase + DAS16_TRIG); - - for (i = 0; i < DAS16_TIMEOUT; i++) { - if (!(inb(dev->iobase + DAS16_STATUS) & BUSY)) - break; - } - if (i == DAS16_TIMEOUT) { - printk("das16: timeout\n"); - return -ETIME; - } - msb = inb(dev->iobase + DAS16_AI_MSB); - lsb = inb(dev->iobase + DAS16_AI_LSB); - if (board->ai_nbits == 12) - data[n] = ((lsb >> 4) & 0xf) | (msb << 4); - else - data[n] = lsb | (msb << 8); - - } - - return n; -} - -static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int bits; - - bits = inb(dev->iobase + DAS16_DIO) & 0xf; - data[1] = bits; - data[0] = 0; - - return insn->n; -} + outb_p(0, dev->iobase + DAS16_TRIG_REG); -static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int wbits; + ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0); + if (ret) + return ret; - /* only set bits that have been masked */ - data[0] &= 0xf; - wbits = s->state; - /* zero bits that have been masked */ - wbits &= ~data[0]; - /* set masked bits */ - wbits |= data[0] & data[1]; - s->state = wbits; - data[1] = wbits; + val = inb(dev->iobase + DAS16_AI_MSB_REG) << 8; + val |= inb(dev->iobase + DAS16_AI_LSB_REG); + if (s->maxdata == 0x0fff) + val >>= 4; + val &= s->maxdata; - outb(s->state, dev->iobase + DAS16_DIO); + data[i] = val; + } return insn->n; } -static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - const struct das16_board *board = comedi_board(dev); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; int i; - int lsb, msb; - int chan; - - chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) { - if (board->ao_nbits == 12) { - lsb = (data[i] << 4) & 0xff; - msb = (data[i] >> 4) & 0xff; - } else { - lsb = data[i] & 0xff; - msb = (data[i] >> 8) & 0xff; - } - outb(lsb, dev->iobase + DAS16_AO_LSB(chan)); - outb(msb, dev->iobase + DAS16_AO_MSB(chan)); - } - - return i; -} - -/* the pc104-das16jr (at least) has problems if the dma - transfer is interrupted in the middle of transferring - a 16 bit sample, so this function takes care to get - an even transfer count after disabling dma - channel. -*/ -static int disable_dma_on_even(struct comedi_device *dev) -{ - struct das16_private_struct *devpriv = dev->private; - int residue; - int i; - static const int disable_limit = 100; - static const int enable_timeout = 100; - - disable_dma(devpriv->dma_chan); - residue = get_dma_residue(devpriv->dma_chan); - for (i = 0; i < disable_limit && (residue % 2); ++i) { - int j; - enable_dma(devpriv->dma_chan); - for (j = 0; j < enable_timeout; ++j) { - int new_residue; - udelay(2); - new_residue = get_dma_residue(devpriv->dma_chan); - if (new_residue != residue) - break; - } - disable_dma(devpriv->dma_chan); - residue = get_dma_residue(devpriv->dma_chan); - } - if (i == disable_limit) { - comedi_error(dev, "failed to get an even dma transfer, " - "could be trouble."); - } - return residue; -} - -static void das16_interrupt(struct comedi_device *dev) -{ - const struct das16_board *board = comedi_board(dev); - struct das16_private_struct *devpriv = dev->private; - unsigned long dma_flags, spin_flags; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async; - struct comedi_cmd *cmd; - int num_bytes, residue; - int buffer_index; - - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); - return; - } - /* initialize async here to make sure it is not NULL */ - async = s->async; - cmd = &async->cmd; - - if (devpriv->dma_chan == 0) { - comedi_error(dev, "interrupt with no dma channel?"); - return; - } - - spin_lock_irqsave(&dev->spinlock, spin_flags); - if ((devpriv->control_state & DMA_ENABLE) == 0) { - spin_unlock_irqrestore(&dev->spinlock, spin_flags); - DEBUG_PRINT("interrupt while dma disabled?\n"); - return; - } - - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma_chan); - residue = disable_dma_on_even(dev); - - /* figure out how many points to read */ - if (residue > devpriv->dma_transfer_size) { - comedi_error(dev, "residue > transfer size!\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - num_bytes = 0; - } else - num_bytes = devpriv->dma_transfer_size - residue; - - if (cmd->stop_src == TRIG_COUNT && - num_bytes >= devpriv->adc_byte_count) { - num_bytes = devpriv->adc_byte_count; - async->events |= COMEDI_CB_EOA; - } - - buffer_index = devpriv->current_buffer; - devpriv->current_buffer = (devpriv->current_buffer + 1) % 2; - devpriv->adc_byte_count -= num_bytes; - - /* figure out how many bytes for next transfer */ - if (cmd->stop_src == TRIG_COUNT && devpriv->timer_mode == 0 && - devpriv->dma_transfer_size > devpriv->adc_byte_count) - devpriv->dma_transfer_size = devpriv->adc_byte_count; - - /* re-enable dma */ - if ((async->events & COMEDI_CB_EOA) == 0) { - set_dma_addr(devpriv->dma_chan, - devpriv->dma_buffer_addr[devpriv->current_buffer]); - set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_chan); - /* reenable conversions for das1600 mode, (stupid hardware) */ - if (board->size > 0x400 && devpriv->timer_mode == 0) - outb(0x00, dev->iobase + DAS1600_CONV); + val = data[i]; + val <<= 4; + outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB_REG(chan)); } - release_dma_lock(dma_flags); - - spin_unlock_irqrestore(&dev->spinlock, spin_flags); - - cfc_write_array_to_buffer(s, - devpriv->dma_buffer[buffer_index], num_bytes); - cfc_handle_events(dev, s); + return insn->n; } -static irqreturn_t das16_dma_interrupt(int irq, void *d) +static int das16_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int status; - struct comedi_device *dev = d; - - status = inb(dev->iobase + DAS16_STATUS); + data[1] = inb(dev->iobase + DAS16_DIO_REG) & 0xf; - if ((status & DAS16_INT) == 0) { - DEBUG_PRINT("spurious interrupt\n"); - return IRQ_NONE; - } - - /* clear interrupt */ - outb(0x00, dev->iobase + DAS16_STATUS); - das16_interrupt(dev); - return IRQ_HANDLED; + return insn->n; } -static void das16_timer_interrupt(unsigned long arg) +static int das16_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct comedi_device *dev = (struct comedi_device *)arg; - struct das16_private_struct *devpriv = dev->private; - - das16_interrupt(dev); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS16_DIO_REG); - if (devpriv->timer_running) - mod_timer(&devpriv->timer, jiffies + timer_period()); -} + data[1] = s->state; -static void reg_dump(struct comedi_device *dev) -{ - DEBUG_PRINT("********DAS1600 REGISTER DUMP********\n"); - DEBUG_PRINT("DAS16_MUX: %x\n", inb(dev->iobase + DAS16_MUX)); - DEBUG_PRINT("DAS16_DIO: %x\n", inb(dev->iobase + DAS16_DIO)); - DEBUG_PRINT("DAS16_STATUS: %x\n", inb(dev->iobase + DAS16_STATUS)); - DEBUG_PRINT("DAS16_CONTROL: %x\n", inb(dev->iobase + DAS16_CONTROL)); - DEBUG_PRINT("DAS16_PACER: %x\n", inb(dev->iobase + DAS16_PACER)); - DEBUG_PRINT("DAS16_GAIN: %x\n", inb(dev->iobase + DAS16_GAIN)); - DEBUG_PRINT("DAS16_CNTR_CONTROL: %x\n", - inb(dev->iobase + DAS16_CNTR_CONTROL)); - DEBUG_PRINT("DAS1600_CONV: %x\n", inb(dev->iobase + DAS1600_CONV)); - DEBUG_PRINT("DAS1600_BURST: %x\n", inb(dev->iobase + DAS1600_BURST)); - DEBUG_PRINT("DAS1600_ENABLE: %x\n", inb(dev->iobase + DAS1600_ENABLE)); - DEBUG_PRINT("DAS1600_STATUS_B: %x\n", - inb(dev->iobase + DAS1600_STATUS_B)); + return insn->n; } static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it) { const struct das16_board *board = comedi_board(dev); - struct das16_private_struct *devpriv = dev->private; - int status; int diobits; - /* status is available on all boards */ - - status = inb(dev->iobase + DAS16_STATUS); - - if ((status & UNIPOLAR)) - devpriv->ai_unipolar = 1; - else - devpriv->ai_unipolar = 0; - - - if ((status & DAS16_MUXBIT)) - devpriv->ai_singleended = 1; - else - devpriv->ai_singleended = 0; - - /* diobits indicates boards */ - - diobits = inb(dev->iobase + DAS16_DIO) & 0xf0; - - printk(KERN_INFO " id bits are 0x%02x\n", diobits); + diobits = inb(dev->iobase + DAS16_DIO_REG) & 0xf0; if (board->id != diobits) { - printk(KERN_INFO " requested board's id bits are 0x%x (ignore)\n", - board->id); - } - - return 0; -} - -static int das1600_mode_detect(struct comedi_device *dev) -{ - struct das16_private_struct *devpriv = dev->private; - int status = 0; - - status = inb(dev->iobase + DAS1600_STATUS_B); - - if (status & DAS1600_CLK_10MHZ) { - devpriv->clockbase = 100; - printk(KERN_INFO " 10MHz pacer clock\n"); - } else { - devpriv->clockbase = 1000; - printk(KERN_INFO " 1MHz pacer clock\n"); + dev_err(dev->class_dev, + "requested board's id bits are incorrect (0x%x != 0x%x)\n", + board->id, diobits); + return -EINVAL; } - reg_dump(dev); - return 0; } -static void das16_ai_munge(struct comedi_device *dev, - struct comedi_subdevice *s, void *array, - unsigned int num_bytes, - unsigned int start_chan_index) +static void das16_reset(struct comedi_device *dev) { - const struct das16_board *board = comedi_board(dev); - unsigned int i, num_samples = num_bytes / sizeof(short); - short *data = array; - - for (i = 0; i < num_samples; i++) { - data[i] = le16_to_cpu(data[i]); - if (board->ai_nbits == 12) - data[i] = (data[i] >> 4) & 0xfff; - - } + outb(0, dev->iobase + DAS16_STATUS_REG); + outb(0, dev->iobase + DAS16_CTRL_REG); + outb(0, dev->iobase + DAS16_PACER_REG); + outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg); } -/* - * - * Options list: - * 0 I/O base - * 1 IRQ - * 2 DMA - * 3 Clock speed (in MHz) - */ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct das16_board *board = comedi_board(dev); struct das16_private_struct *devpriv; struct comedi_subdevice *s; + struct comedi_lrange *lrange; + struct comedi_krange *krange; + unsigned int dma_chan = it->options[2]; + unsigned int status; int ret; - unsigned int irq; - unsigned int dma_chan; - int timer_mode; - unsigned long flags; - struct comedi_krange *user_ai_range, *user_ao_range; - -#if 0 - irq = it->options[1]; - timer_mode = it->options[8]; -#endif - /* always use time_mode since using irq can drop samples while - * waiting for dma done interrupt (due to hardware limitations) */ - irq = 0; - timer_mode = 1; - if (timer_mode) - irq = 0; /* check that clock setting is valid */ if (it->options[3]) { if (it->options[3] != 0 && it->options[3] != 1 && it->options[3] != 10) { - printk - ("\n Invalid option. Master clock must be set " - "to 1 or 10 (MHz)\n"); + dev_err(dev->class_dev, + "Invalid option. Master clock must be set to 1 or 10 (MHz)\n"); return -EINVAL; } } - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; if (board->size < 0x400) { ret = comedi_request_region(dev, it->options[0], board->size); @@ -1121,207 +1030,184 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; devpriv->extra_iobase = dev->iobase + 0x400; + devpriv->can_burst = 1; } /* probe id bits to make sure they are consistent */ - if (das16_probe(dev, it)) { - printk(KERN_ERR " id bits do not match selected board, aborting\n"); + if (das16_probe(dev, it)) return -EINVAL; - } /* get master clock speed */ - if (board->size < 0x400) { - if (it->options[3]) - devpriv->clockbase = 1000 / it->options[3]; - else - devpriv->clockbase = 1000; /* 1 MHz default */ - } else { - das1600_mode_detect(dev); - } - - /* now for the irq */ - if (irq > 1 && irq < 8) { - ret = request_irq(irq, das16_dma_interrupt, 0, - dev->board_name, dev); + if (devpriv->can_burst) { + status = inb(dev->iobase + DAS1600_STATUS_REG); - if (ret < 0) - return ret; - dev->irq = irq; - printk(KERN_INFO " ( irq = %u )", irq); - } else if (irq == 0) { - printk(" ( no irq )"); + if (status & DAS1600_STATUS_CLK_10MHZ) + devpriv->clockbase = I8254_OSC_BASE_10MHZ; + else + devpriv->clockbase = I8254_OSC_BASE_1MHZ; } else { - printk(" invalid irq\n"); - return -EINVAL; + if (it->options[3]) + devpriv->clockbase = I8254_OSC_BASE_1MHZ / + it->options[3]; + else + devpriv->clockbase = I8254_OSC_BASE_1MHZ; } - /* initialize dma */ - dma_chan = it->options[2]; + /* initialize dma */ if (dma_chan == 1 || dma_chan == 3) { - /* allocate dma buffers */ + unsigned long flags; int i; - for (i = 0; i < 2; i++) { - devpriv->dma_buffer[i] = pci_alloc_consistent( - NULL, DAS16_DMA_SIZE, - &devpriv->dma_buffer_addr[i]); - if (devpriv->dma_buffer[i] == NULL) - return -ENOMEM; - } if (request_dma(dma_chan, dev->board_name)) { - printk(KERN_ERR " failed to allocate dma channel %i\n", - dma_chan); + dev_err(dev->class_dev, + "failed to request dma channel %i\n", + dma_chan); return -EINVAL; } devpriv->dma_chan = dma_chan; + + /* allocate dma buffers */ + for (i = 0; i < 2; i++) { + void *p; + + p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE, + &devpriv->dma_buffer_addr[i]); + if (!p) + return -ENOMEM; + devpriv->dma_buffer[i] = p; + } + flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); release_dma_lock(flags); - printk(KERN_INFO " ( dma = %u)\n", dma_chan); - } else if (dma_chan == 0) { - printk(KERN_INFO " ( no dma )\n"); - } else { - printk(KERN_ERR " invalid dma channel\n"); - return -EINVAL; + + init_timer(&devpriv->timer); + devpriv->timer.function = das16_timer_interrupt; + devpriv->timer.data = (unsigned long)dev; } - /* get any user-defined input range */ + /* get any user-defined input range */ if (board->ai_pg == das16_pg_none && (it->options[4] || it->options[5])) { - /* allocate single-range range table */ - devpriv->user_ai_range_table = - kmalloc(sizeof(struct comedi_lrange) + - sizeof(struct comedi_krange), GFP_KERNEL); - /* initialize ai range */ - devpriv->user_ai_range_table->length = 1; - user_ai_range = devpriv->user_ai_range_table->range; - user_ai_range->min = it->options[4]; - user_ai_range->max = it->options[5]; - user_ai_range->flags = UNIT_volt; - } - /* get any user-defined output range */ - if (it->options[6] || it->options[7]) { - /* allocate single-range range table */ - devpriv->user_ao_range_table = - kmalloc(sizeof(struct comedi_lrange) + - sizeof(struct comedi_krange), GFP_KERNEL); - /* initialize ao range */ - devpriv->user_ao_range_table->length = 1; - user_ao_range = devpriv->user_ao_range_table->range; - user_ao_range->min = it->options[6]; - user_ao_range->max = it->options[7]; - user_ao_range->flags = UNIT_volt; + /* allocate single-range range table */ + lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL); + if (!lrange) + return -ENOMEM; + + /* initialize ai range */ + devpriv->user_ai_range_table = lrange; + lrange->length = 1; + krange = devpriv->user_ai_range_table->range; + krange->min = it->options[4]; + krange->max = it->options[5]; + krange->flags = UNIT_volt; } - if (timer_mode) { - init_timer(&(devpriv->timer)); - devpriv->timer.function = das16_timer_interrupt; - devpriv->timer.data = (unsigned long)dev; + /* get any user-defined output range */ + if (it->options[6] || it->options[7]) { + /* allocate single-range range table */ + lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL); + if (!lrange) + return -ENOMEM; + + /* initialize ao range */ + devpriv->user_ao_range_table = lrange; + lrange->length = 1; + krange = devpriv->user_ao_range_table->range; + krange->min = it->options[6]; + krange->max = it->options[7]; + krange->flags = UNIT_volt; } - devpriv->timer_mode = timer_mode ? 1 : 0; - ret = comedi_alloc_subdevices(dev, 5); + ret = comedi_alloc_subdevices(dev, 4 + board->has_8255); if (ret) return ret; + status = inb(dev->iobase + DAS16_STATUS_REG); + + /* Analog Input subdevice */ s = &dev->subdevices[0]; - dev->read_subdev = s; - /* ai */ - if (board->ai) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - if (devpriv->ai_singleended) { - s->n_chan = 16; - s->len_chanlist = 16; - s->subdev_flags |= SDF_GROUND; - } else { - s->n_chan = 8; - s->len_chanlist = 8; - s->subdev_flags |= SDF_DIFF; - } - s->maxdata = (1 << board->ai_nbits) - 1; - if (devpriv->user_ai_range_table) { /* user defined ai range */ - s->range_table = devpriv->user_ai_range_table; - } else if (devpriv->ai_unipolar) { - s->range_table = das16_ai_uni_lranges[board->ai_pg]; - } else { - s->range_table = das16_ai_bip_lranges[board->ai_pg]; - } - s->insn_read = board->ai; - s->do_cmdtest = das16_cmd_test; - s->do_cmd = das16_cmd_exec; - s->cancel = das16_cancel; - s->munge = das16_ai_munge; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (status & DAS16_STATUS_MUXBIT) { + s->subdev_flags |= SDF_GROUND; + s->n_chan = 16; } else { - s->type = COMEDI_SUBD_UNUSED; + s->subdev_flags |= SDF_DIFF; + s->n_chan = 8; } - - s = &dev->subdevices[1]; - /* ao */ - if (board->ao) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->maxdata = (1 << board->ao_nbits) - 1; - /* user defined ao range */ - if (devpriv->user_ao_range_table) - s->range_table = devpriv->user_ao_range_table; - else - s->range_table = &range_unknown; - - s->insn_write = board->ao; + s->len_chanlist = s->n_chan; + s->maxdata = board->ai_maxdata; + if (devpriv->user_ai_range_table) { /* user defined ai range */ + s->range_table = devpriv->user_ai_range_table; + } else if (status & DAS16_STATUS_UNIPOLAR) { + s->range_table = das16_ai_uni_lranges[board->ai_pg]; } else { - s->type = COMEDI_SUBD_UNUSED; + s->range_table = das16_ai_bip_lranges[board->ai_pg]; } - - s = &dev->subdevices[2]; - /* di */ - if (board->di) { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = board->di; - } else { - s->type = COMEDI_SUBD_UNUSED; + s->insn_read = das16_ai_insn_read; + if (devpriv->dma_chan) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->do_cmdtest = das16_cmd_test; + s->do_cmd = das16_cmd_exec; + s->cancel = das16_cancel; + s->munge = das16_ai_munge; } - s = &dev->subdevices[3]; - /* do */ - if (board->do_) { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = board->do_; - /* initialize digital output lines */ - outb(s->state, dev->iobase + DAS16_DIO); + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + if (board->has_ao) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = devpriv->user_ao_range_table; + s->insn_write = das16_ao_insn_write; } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } - s = &dev->subdevices[4]; - /* 8255 */ - if (board->i8255_offset != 0) { - subdev_8255_init(dev, s, NULL, (dev->iobase + - board->i8255_offset)); - } else { - s->type = COMEDI_SUBD_UNUSED; + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das16_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das16_do_insn_bits; + + /* initialize digital output lines */ + outb(s->state, dev->iobase + DAS16_DIO_REG); + + /* 8255 Digital I/O subdevice */ + if (board->has_8255) { + s = &dev->subdevices[4]; + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + board->i8255_offset); + if (ret) + return ret; } das16_reset(dev); /* set the interrupt level */ - devpriv->control_state = DAS16_IRQ(dev->irq); - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); - - /* turn on das1600 mode if available */ - if (board->size > 0x400) { - outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE); - outb(0, dev->iobase + DAS1600_CONV); - outb(0, dev->iobase + DAS1600_BURST); + devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq); + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); + + if (devpriv->can_burst) { + outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG); + outb(0, dev->iobase + DAS1600_CONV_REG); + outb(0, dev->iobase + DAS1600_BURST_REG); } return 0; @@ -1331,10 +1217,12 @@ static void das16_detach(struct comedi_device *dev) { const struct das16_board *board = comedi_board(dev); struct das16_private_struct *devpriv = dev->private; + int i; - das16_reset(dev); if (devpriv) { - int i; + if (dev->iobase) + das16_reset(dev); + for (i = 0; i < 2; i++) { if (devpriv->dma_buffer[i]) pci_free_consistent(NULL, DAS16_DMA_SIZE, @@ -1346,312 +1234,15 @@ static void das16_detach(struct comedi_device *dev) free_dma(devpriv->dma_chan); kfree(devpriv->user_ai_range_table); kfree(devpriv->user_ao_range_table); + + if (devpriv->extra_iobase) + release_region(devpriv->extra_iobase, + board->size & 0x3ff); } - if (devpriv->extra_iobase) - release_region(devpriv->extra_iobase, board->size & 0x3ff); + comedi_legacy_detach(dev); } -static const struct das16_board das16_boards[] = { - { - .name = "das-16", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 15000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, { - .name = "das-16g", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 15000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, { - .name = "das-16f", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 8500, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, { - .name = "cio-das16", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 20000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x80, - }, { - .name = "cio-das16/f", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x80, - }, { - .name = "cio-das16/jr", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 7692, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, { - .name = "pc104-das16jr", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 3300, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, { - .name = "cio-das16jr/16", - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_16jr_16, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, { - .name = "pc104-das16jr/16", - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_16jr_16, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, { - .name = "das-1201", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 20000, - .ai_pg = das16_pg_none, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0x20, - }, { - .name = "das-1202", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_none, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0x20, - }, { - .name = "das-1401", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1601, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "das-1402", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "das-1601", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1601, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "das-1602", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "cio-das1401/12", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1601, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "cio-das1402/12", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "cio-das1402/16", - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "cio-das1601/12", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1601, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "cio-das1602/12", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "cio-das1602/16", - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0, - }, { - .name = "cio-das16/330", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 3030, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0xf0, - }, -}; - static struct comedi_driver das16_driver = { .driver_name = "das16", .module = THIS_MODULE, @@ -1664,5 +1255,5 @@ static struct comedi_driver das16_driver = { module_comedi_driver(das16_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 0b33808c3a7..ec039fbff0f 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -52,7 +52,7 @@ Options: irq can be omitted, although the cmd interface will not work without it. */ -#include <linux/ioport.h> +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" @@ -63,8 +63,6 @@ irq can be omitted, although the cmd interface will not work without it. #define DAS16M1_SIZE 16 #define DAS16M1_SIZE2 8 -#define DAS16M1_XTAL 100 /* 10 MHz master clock */ - #define FIFO_SIZE 1024 /* 1024 sample fifo */ /* @@ -112,18 +110,18 @@ irq can be omitted, although the cmd interface will not work without it. #define DAS16M1_82C55 0x400 #define DAS16M1_8254_THIRD 0x404 -static const struct comedi_lrange range_das16m1 = { 9, - { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10), - } +static const struct comedi_lrange range_das16m1 = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; struct das16m1_private_struct { @@ -133,19 +131,18 @@ struct das16m1_private_struct { * needed to keep track of whether new count has been loaded into * counter yet (loaded by first sample conversion) */ u16 initial_hw_count; - short ai_buffer[FIFO_SIZE]; - unsigned int do_bits; /* saves status of digital output bits */ + unsigned short ai_buffer[FIFO_SIZE]; unsigned int divisor1; /* divides master clock to obtain conversion speed */ unsigned int divisor2; /* divides master clock to obtain conversion speed */ unsigned long extra_iobase; }; -static inline short munge_sample(short data) +static inline unsigned short munge_sample(unsigned short data) { return (data >> 4) & 0xfff; } -static void munge_sample_array(short *array, unsigned int num_elements) +static void munge_sample_array(unsigned short *array, unsigned int num_elements) { unsigned int i; @@ -153,11 +150,40 @@ static void munge_sample_array(short *array, unsigned int num_elements) array[i] = munge_sample(array[i]); } +static int das16m1_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int i; + + if (cmd->chanlist_len == 1) + return 0; + + if ((cmd->chanlist_len % 2) != 0) { + dev_dbg(dev->class_dev, + "chanlist must be of even length or length 1\n"); + return -EINVAL; + } + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if ((i % 2) != (chan % 2)) { + dev_dbg(dev->class_dev, + "even/odd channels must go have even/odd chanlist indices\n"); + return -EINVAL; + } + } + + return 0; +} + static int das16m1_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { struct das16m1_private_struct *devpriv = dev->private; - unsigned int err = 0, tmp, i; + int err = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -206,36 +232,20 @@ static int das16m1_cmd_test(struct comedi_device *dev, /* step 4: fix up arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check chanlist against board's peculiarities */ - if (cmd->chanlist && cmd->chanlist_len > 1) { - for (i = 0; i < cmd->chanlist_len; i++) { - /* even/odd channels must go into even/odd queue addresses */ - if ((i % 2) != (CR_CHAN(cmd->chanlist[i]) % 2)) { - comedi_error(dev, "bad chanlist:\n" - " even/odd channels must go have even/odd chanlist indices"); - err++; - } - } - if ((cmd->chanlist_len % 2) != 0) { - comedi_error(dev, - "chanlist must be of even length or length 1"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das16m1_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -243,25 +253,16 @@ static int das16m1_cmd_test(struct comedi_device *dev, return 0; } -/* This function takes a time in nanoseconds and sets the * - * 2 pacer clocks to the closest frequency possible. It also * - * returns the actual sampling period. */ -static unsigned int das16m1_set_pacer(struct comedi_device *dev, - unsigned int ns, int rounding_flags) +static void das16m1_set_pacer(struct comedi_device *dev) { struct das16m1_private_struct *devpriv = dev->private; + unsigned long timer_base = dev->iobase + DAS16M1_8254_SECOND; - i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1), - &(devpriv->divisor2), &ns, - rounding_flags & TRIG_ROUND_MASK); - - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1, - 2); - i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2, - 2); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); - return ns; + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } static int das16m1_cmd_exec(struct comedi_device *dev, @@ -270,13 +271,9 @@ static int das16m1_cmd_exec(struct comedi_device *dev, struct das16m1_private_struct *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned long timer_base = dev->iobase + DAS16M1_8254_FIRST; unsigned int byte, i; - if (dev->irq == 0) { - comedi_error(dev, "irq required to execute comedi_cmd"); - return -1; - } - /* disable interrupts and internal pacer */ devpriv->control_state &= ~INTE & ~PACER_MASK; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); @@ -286,11 +283,11 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* Initialize lower half of hardware counter, used to determine how * many samples are in fifo. Value doesn't actually load into counter * until counter's next clock (the next a/d conversion) */ - i8254_load(dev->iobase + DAS16M1_8254_FIRST, 0, 1, 0, 2); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, 0); /* remember current reading of counter so we know when counter has * actually been loaded */ - devpriv->initial_hw_count = - i8254_read(dev->iobase + DAS16M1_8254_FIRST, 0, 1); + devpriv->initial_hw_count = i8254_read(timer_base, 0, 1); /* setup channel/gain queue */ for (i = 0; i < cmd->chanlist_len; i++) { outb(i, dev->iobase + DAS16M1_QUEUE_ADDR); @@ -300,10 +297,14 @@ static int das16m1_cmd_exec(struct comedi_device *dev, outb(byte, dev->iobase + DAS16M1_QUEUE_DATA); } - /* set counter mode and counts */ - cmd->convert_arg = - das16m1_set_pacer(dev, cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + /* enable interrupts and set internal pacer counter mode and counts */ + devpriv->control_state &= ~PACER_MASK; + if (cmd->convert_src == TRIG_TIMER) { + das16m1_set_pacer(dev); + devpriv->control_state |= INT_PACER; + } else { /* TRIG_EXT */ + devpriv->control_state |= EXT_PACER; + } /* set control & status register */ byte = 0; @@ -316,13 +317,6 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* clear interrupt bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); - /* enable interrupts and internal pacer */ - devpriv->control_state &= ~PACER_MASK; - if (cmd->convert_src == TRIG_TIMER) - devpriv->control_state |= INT_PACER; - else - devpriv->control_state |= EXT_PACER; - devpriv->control_state |= INTE; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); @@ -339,14 +333,27 @@ static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int das16m1_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS16M1_CS); + if (status & IRQDATA) + return 0; + return -EBUSY; +} + static int das16m1_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct das16m1_private_struct *devpriv = dev->private; - int i, n; + int ret; + int n; int byte; - const int timeout = 1000; /* disable interrupts and internal pacer */ devpriv->control_state &= ~INTE & ~PACER_MASK; @@ -364,14 +371,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outb(0, dev->iobase); - for (i = 0; i < timeout; i++) { - if (inb(dev->iobase + DAS16M1_CS) & IRQDATA) - break; - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0); + if (ret) + return ret; + data[n] = munge_sample(inw(dev->iobase)); } @@ -393,22 +396,13 @@ static int das16m1_di_rbits(struct comedi_device *dev, static int das16m1_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct das16m1_private_struct *devpriv = dev->private; - unsigned int wbits; - - /* only set bits that have been masked */ - data[0] &= 0xf; - wbits = devpriv->do_bits; - /* zero bits that have been masked */ - wbits &= ~data[0]; - /* set masked bits */ - wbits |= data[0] & data[1]; - devpriv->do_bits = wbits; - data[1] = wbits; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS16M1_DIO); - outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); + data[1] = s->state; return insn->n; } @@ -424,7 +418,6 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) s = dev->read_subdev; async = s->async; - async->events = 0; cmd = &async->cmd; /* figure out how many samples are in fifo */ @@ -457,8 +450,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) devpriv->adc_count += num_samples; if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { /* end of acquisition */ - das16m1_cancel(dev, s); + if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { + /* end of acquisition */ async->events |= COMEDI_CB_EOA; } } @@ -466,13 +459,11 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) /* this probably won't catch overruns since the card doesn't generate * overrun interrupts, but we might as well try */ if (status & OVRUN) { - das16m1_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; comedi_error(dev, "fifo overflow"); } - comedi_event(dev, s); - + cfc_handle_events(dev, s); } static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) @@ -520,38 +511,26 @@ static irqreturn_t das16m1_interrupt(int irq, void *d) static int das16m1_irq_bits(unsigned int irq) { - int ret; - switch (irq) { case 10: - ret = 0x0; - break; + return 0x0; case 11: - ret = 0x1; - break; + return 0x1; case 12: - ret = 0x2; - break; + return 0x2; case 15: - ret = 0x3; - break; + return 0x3; case 2: - ret = 0x4; - break; + return 0x4; case 3: - ret = 0x5; - break; + return 0x5; case 5: - ret = 0x6; - break; + return 0x6; case 7: - ret = 0x7; - break; + return 0x7; default: - return -1; - break; + return 0x0; } - return ret << 4; } /* @@ -565,12 +544,10 @@ static int das16m1_attach(struct comedi_device *dev, struct das16m1_private_struct *devpriv; struct comedi_subdevice *s; int ret; - unsigned int irq; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_request_region(dev, it->options[0], DAS16M1_SIZE); if (ret) @@ -582,24 +559,12 @@ static int das16m1_attach(struct comedi_device *dev, return ret; devpriv->extra_iobase = dev->iobase + DAS16M1_82C55; - /* now for the irq */ - irq = it->options[1]; - /* make sure it is valid */ - if (das16m1_irq_bits(irq) >= 0) { - ret = request_irq(irq, das16m1_interrupt, 0, - dev->driver->driver_name, dev); - if (ret < 0) - return ret; - dev->irq = irq; - printk - ("irq %u\n", irq); - } else if (irq == 0) { - printk - (", no irq\n"); - } else { - comedi_error(dev, "invalid irq\n" - " valid irqs are 2, 3, 5, 7, 10, 11, 12, or 15\n"); - return -EINVAL; + /* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */ + if ((1 << it->options[1]) & 0xdcfc) { + ret = request_irq(it->options[1], das16m1_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } ret = comedi_alloc_subdevices(dev, 4); @@ -607,20 +572,22 @@ static int das16m1_attach(struct comedi_device *dev, return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; /* ai */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_DIFF; s->n_chan = 8; - s->subdev_flags = SDF_DIFF; - s->len_chanlist = 256; s->maxdata = (1 << 12) - 1; s->range_table = &range_das16m1; s->insn_read = das16m1_ai_rinsn; - s->do_cmdtest = das16m1_cmd_test; - s->do_cmd = das16m1_cmd_exec; - s->cancel = das16m1_cancel; - s->poll = das16m1_poll; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 256; + s->do_cmdtest = das16m1_cmd_test; + s->do_cmd = das16m1_cmd_exec; + s->cancel = das16m1_cancel; + s->poll = das16m1_poll; + } s = &dev->subdevices[1]; /* di */ @@ -650,13 +617,10 @@ static int das16m1_attach(struct comedi_device *dev, outb(TOTAL_CLEAR, dev->iobase + DAS16M1_8254_FIRST_CNTRL); /* initialize digital output lines */ - outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); + outb(0, dev->iobase + DAS16M1_DIO); /* set the interrupt level */ - if (dev->irq) - devpriv->control_state = das16m1_irq_bits(dev->irq); - else - devpriv->control_state = 0; + devpriv->control_state = das16m1_irq_bits(dev->irq) << 4; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); return 0; diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 23b4a661eb1..859519026c4 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -94,12 +94,12 @@ TODO: read insn for analog out */ +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/io.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <asm/dma.h> #include "8253.h" @@ -108,7 +108,6 @@ TODO: /* misc. defines */ #define DAS1800_SIZE 16 /* uses 16 io addresses */ #define FIFO_SIZE 1024 /* 1024 sample fifo */ -#define TIMER_BASE 200 /* 5 Mhz master clock */ #define UNIPOLAR 0x4 /* bit that determines whether input range is uni/bipolar */ #define DMA_BUF_SIZE 0x1ff00 /* size in bytes of dma buffers */ @@ -179,31 +178,29 @@ enum { /* analog input ranges */ static const struct comedi_lrange range_ai_das1801 = { - 8, - { - RANGE(-5, 5), - RANGE(-1, 1), - RANGE(-0.1, 0.1), - RANGE(-0.02, 0.02), - RANGE(0, 5), - RANGE(0, 1), - RANGE(0, 0.1), - RANGE(0, 0.02), - } + 8, { + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02), + UNI_RANGE(5), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) + } }; static const struct comedi_lrange range_ai_das1802 = { - 8, - { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; struct das1800_board { @@ -427,7 +424,6 @@ struct das1800_private { volatile unsigned int count; /* number of data points left to be taken */ unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ - int do_bits; /* digital output bits */ int irq_dma_bits; /* bits for control register b */ /* dma bits for control register b, stored so that dma can be * turned on and off */ @@ -440,16 +436,16 @@ struct das1800_private { uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */ unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */ unsigned long iobase2; /* secondary io address used for analog out on 'ao' boards */ - short ao_update_bits; /* remembers the last write to the 'update' dac */ + unsigned short ao_update_bits; /* remembers the last write to the + * 'update' dac */ }; /* analog out range for 'ao' boards */ /* static const struct comedi_lrange range_ao_2 = { - 2, - { - RANGE(-10, 10), - RANGE(-5, 5), + 2, { + BIP_RANGE(10), + BIP_RANGE(5) } }; */ @@ -463,7 +459,7 @@ static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev, return sample; } -static void munge_data(struct comedi_device *dev, uint16_t * array, +static void munge_data(struct comedi_device *dev, uint16_t *array, unsigned int num_elements) { unsigned int i; @@ -503,7 +499,7 @@ static void das1800_handle_fifo_not_empty(struct comedi_device *dev, struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; - short dpnt; + unsigned short dpnt; int unipolar; struct comedi_cmd *cmd = &s->async->cmd; @@ -551,7 +547,7 @@ static void das1800_flush_dma_channel(struct comedi_device *dev, munge_data(dev, buffer, num_samples); cfc_write_array_to_buffer(s, buffer, num_bytes); - if (s->async->cmd.stop_src == TRIG_COUNT) + if (cmd->stop_src == TRIG_COUNT) devpriv->count -= num_samples; return; @@ -645,12 +641,11 @@ static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) static void das1800_ai_handler(struct comedi_device *dev) { struct das1800_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int status = inb(dev->iobase + DAS1800_STATUS); - async->events = 0; /* select adc for base address + 0 */ outb(ADC, dev->iobase + DAS1800_SELECT); /* dma buffer full */ @@ -669,9 +664,8 @@ static void das1800_ai_handler(struct comedi_device *dev) /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); comedi_error(dev, "DAS1800 FIFO overflow"); - das1800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } /* stop taking data if appropriate */ @@ -684,16 +678,12 @@ static void das1800_ai_handler(struct comedi_device *dev) das1800_flush_dma(dev, s); else das1800_handle_fifo_not_empty(dev, s); - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */ - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - - return; + cfc_handle_events(dev, s); } static int das1800_ai_poll(struct comedi_device *dev, @@ -741,7 +731,7 @@ static irqreturn_t das1800_interrupt(int irq, void *d) /* converts requested conversion timing to timing compatible with * hardware, used only when card is in 'burst mode' */ -static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) +static unsigned int burst_convert_arg(unsigned int convert_arg, int flags) { unsigned int micro_sec; @@ -750,7 +740,7 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) convert_arg = 64000; /* the conversion time must be an integral number of microseconds */ - switch (round_mode) { + switch (flags & TRIG_ROUND_MASK) { case TRIG_ROUND_NEAREST: default: micro_sec = (convert_arg + 500) / 1000; @@ -767,6 +757,26 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) return micro_sec * 1000; } +static int das1800_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int unipolar0 = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR; + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int unipolar = CR_RANGE(cmd->chanlist[i]) & UNIPOLAR; + + if (unipolar != unipolar0) { + dev_dbg(dev->class_dev, + "unipolar and bipolar ranges cannot be mixed in the chanlist\n"); + return -EINVAL; + } + } + + return 0; +} + /* test analog input cmd */ static int das1800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, @@ -775,9 +785,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, const struct das1800_board *thisboard = comedi_board(dev); struct das1800_private *devpriv = dev->private; int err = 0; - unsigned int tmp_arg; - int i; - int unipolar; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -835,72 +843,48 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->convert_src == TRIG_TIMER) { - /* if we are not in burst mode */ - if (cmd->scan_begin_src == TRIG_FOLLOW) { - tmp_arg = cmd->convert_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd-> - flags & TRIG_ROUND_MASK); - if (tmp_arg != cmd->convert_arg) - err++; - } - /* if we are in burst mode */ - else { - /* check that convert_arg is compatible */ - tmp_arg = cmd->convert_arg; - cmd->convert_arg = - burst_convert_arg(cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp_arg != cmd->convert_arg) + if (cmd->scan_begin_src == TRIG_FOLLOW && + cmd->convert_src == TRIG_TIMER) { + /* we are not in burst mode */ + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, cmd->flags); + if (arg != cmd->convert_arg) + err++; + } else if (cmd->convert_src == TRIG_TIMER) { + /* we are in burst mode */ + arg = cmd->convert_arg; + cmd->convert_arg = burst_convert_arg(cmd->convert_arg, + cmd->flags); + if (arg != cmd->convert_arg) + err++; + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->chanlist_len; + if (arg > cmd->scan_begin_arg) { + cmd->scan_begin_arg = arg; err++; - - if (cmd->scan_begin_src == TRIG_TIMER) { - /* if scans are timed faster than conversion rate allows */ - if (cmd->convert_arg * cmd->chanlist_len > - cmd->scan_begin_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * - cmd->chanlist_len; - err++; - } - tmp_arg = cmd->scan_begin_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv-> - divisor1), - &(devpriv-> - divisor2), - &(cmd-> - scan_begin_arg), - cmd-> - flags & - TRIG_ROUND_MASK); - if (tmp_arg != cmd->scan_begin_arg) - err++; } + + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->scan_begin_arg, + cmd->flags); + if (arg != cmd->scan_begin_arg) + err++; } } if (err) return 4; - /* make sure user is not trying to mix unipolar and bipolar ranges */ - if (cmd->chanlist) { - unipolar = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR; - for (i = 1; i < cmd->chanlist_len; i++) { - if (unipolar != (CR_RANGE(cmd->chanlist[i]) & UNIPOLAR)) { - comedi_error(dev, - "unipolar and bipolar ranges cannot be mixed in the chanlist"); - err++; - break; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das1800_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -978,69 +962,29 @@ static int control_c_bits(const struct comedi_cmd *cmd) return control_c; } -/* loads counters with divisor1, divisor2 from private structure */ -static int das1800_set_frequency(struct comedi_device *dev) +static void das1800_setup_counters(struct comedi_device *dev, + const struct comedi_cmd *cmd) { struct das1800_private *devpriv = dev->private; - int err = 0; - - /* counter 1, mode 2 */ - if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1, - 2)) - err++; - /* counter 2, mode 2 */ - if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2, - 2)) - err++; - if (err) - return -1; - - return 0; -} + unsigned long timer_base = dev->iobase + DAS1800_COUNTER; -/* sets up counters */ -static int setup_counters(struct comedi_device *dev, - const struct comedi_cmd *cmd) -{ - struct das1800_private *devpriv = dev->private; - unsigned int period; + /* setup cascaded counters for conversion/scan frequency */ + if ((cmd->scan_begin_src == TRIG_FOLLOW || + cmd->scan_begin_src == TRIG_TIMER) && + cmd->convert_src == TRIG_TIMER) { + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); - /* setup cascaded counters for conversion/scan frequency */ - switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: /* not in burst mode */ - if (cmd->convert_src == TRIG_TIMER) { - /* set conversion frequency */ - period = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &devpriv->divisor1, - &devpriv->divisor2, - &period, - cmd->flags & - TRIG_ROUND_MASK); - if (das1800_set_frequency(dev) < 0) - return -1; - } - break; - case TRIG_TIMER: /* in burst mode */ - /* set scan frequency */ - period = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &devpriv->divisor1, - &devpriv->divisor2, &period, - cmd->flags & TRIG_ROUND_MASK); - if (das1800_set_frequency(dev) < 0) - return -1; - break; - default: - break; + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } - /* setup counter 0 for 'about triggering' */ + /* setup counter 0 for 'about triggering' */ if (cmd->stop_src == TRIG_EXT) { - /* load counter 0 in mode 0 */ - i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0); - } + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); - return 0; + i8254_write(timer_base, 0, 0, 1); + } } /* utility function that suggests a dma transfer size based on the conversion period 'ns' */ @@ -1153,17 +1097,10 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; - int ret; int control_a, control_c; struct comedi_async *async = s->async; const struct comedi_cmd *cmd = &async->cmd; - if (!dev->irq) { - comedi_error(dev, - "no irq assigned for das-1800, cannot do hardware conversions"); - return -1; - } - /* disable dma on TRIG_WAKE_EOS, or TRIG_RT * (because dma in handler is unsafe at hard real-time priority) */ if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) @@ -1190,11 +1127,7 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, /* setup card and start */ program_chanlist(dev, cmd); - ret = setup_counters(dev, cmd); - if (ret < 0) { - comedi_error(dev, "Error setting up counters"); - return ret; - } + das1800_setup_counters(dev, cmd); setup_dma(dev, cmd); outb(control_c, dev->iobase + DAS1800_CONTROL_C); /* set conversion rate and length for burst mode */ @@ -1220,7 +1153,7 @@ static int das1800_ai_rinsn(struct comedi_device *dev, int i, n; int chan, range, aref, chan_range; int timeout = 1000; - short dpnt; + unsigned short dpnt; int conv_flags = 0; unsigned long irq_flags; @@ -1285,7 +1218,7 @@ static int das1800_ao_winsn(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); /* int range = CR_RANGE(insn->chanspec); */ int update_chan = thisboard->ao_n_chan - 1; - short output; + unsigned short output; unsigned long irq_flags; /* card expects two's complement data */ @@ -1319,24 +1252,15 @@ static int das1800_di_rbits(struct comedi_device *dev, return insn->n; } -/* writes to digital output channels */ static int das1800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct das1800_private *devpriv = dev->private; - unsigned int wbits; - - /* only set bits that have been masked */ - data[0] &= (1 << s->n_chan) - 1; - wbits = devpriv->do_bits; - wbits &= ~data[0]; - wbits |= data[0] & data[1]; - devpriv->do_bits = wbits; - - outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS1800_DIGITAL); - data[1] = devpriv->do_bits; + data[1] = s->state; return insn->n; } @@ -1502,7 +1426,7 @@ static int das1800_probe(struct comedi_device *dev) static int das1800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das1800_board *thisboard = comedi_board(dev); + const struct das1800_board *thisboard; struct das1800_private *devpriv; struct comedi_subdevice *s; unsigned int irq = it->options[1]; @@ -1511,10 +1435,9 @@ static int das1800_attach(struct comedi_device *dev, int board; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_request_region(dev, it->options[0], DAS1800_SIZE); if (ret) @@ -1540,43 +1463,34 @@ static int das1800_attach(struct comedi_device *dev, devpriv->iobase2 = iobase2; } - /* grab our IRQ */ - if (irq) { - if (request_irq(irq, das1800_interrupt, 0, - dev->driver->driver_name, dev)) { - dev_dbg(dev->class_dev, "unable to allocate irq %u\n", - irq); - return -EINVAL; - } - } - dev->irq = irq; + if (irq == 3 || irq == 5 || irq == 7 || irq == 10 || irq == 11 || + irq == 15) { + ret = request_irq(irq, das1800_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = irq; - /* set bits that tell card which irq to use */ - switch (irq) { - case 0: - break; - case 3: - devpriv->irq_dma_bits |= 0x8; - break; - case 5: - devpriv->irq_dma_bits |= 0x10; - break; - case 7: - devpriv->irq_dma_bits |= 0x18; - break; - case 10: - devpriv->irq_dma_bits |= 0x28; - break; - case 11: - devpriv->irq_dma_bits |= 0x30; - break; - case 15: - devpriv->irq_dma_bits |= 0x38; - break; - default: - dev_err(dev->class_dev, "irq out of range\n"); - return -EINVAL; - break; + switch (irq) { + case 3: + devpriv->irq_dma_bits |= 0x8; + break; + case 5: + devpriv->irq_dma_bits |= 0x10; + break; + case 7: + devpriv->irq_dma_bits |= 0x18; + break; + case 10: + devpriv->irq_dma_bits |= 0x28; + break; + case 11: + devpriv->irq_dma_bits |= 0x30; + break; + case 15: + devpriv->irq_dma_bits |= 0x38; + break; + } + } } ret = das1800_init_dma(dev, dma0, dma1); @@ -1596,20 +1510,23 @@ static int das1800_attach(struct comedi_device *dev, /* analog input subdevice */ s = &dev->subdevices[0]; - dev->read_subdev = s; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND; if (thisboard->common) s->subdev_flags |= SDF_COMMON; s->n_chan = thisboard->qram_len; - s->len_chanlist = thisboard->qram_len; s->maxdata = (1 << thisboard->resolution) - 1; s->range_table = thisboard->range_ai; - s->do_cmd = das1800_ai_do_cmd; - s->do_cmdtest = das1800_ai_do_cmdtest; s->insn_read = das1800_ai_rinsn; - s->poll = das1800_ai_poll; - s->cancel = das1800_cancel; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmd = das1800_ai_do_cmd; + s->do_cmdtest = das1800_ai_do_cmdtest; + s->poll = das1800_ai_poll; + s->cancel = das1800_cancel; + } /* analog out */ s = &dev->subdevices[1]; @@ -1645,7 +1562,7 @@ static int das1800_attach(struct comedi_device *dev, das1800_cancel(dev, dev->read_subdev); /* initialize digital out channels */ - outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); + outb(0, dev->iobase + DAS1800_DIGITAL); /* initialize analog out channels */ if (thisboard->ao_ability == 1) { diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index f0530778bb3..d18eea6c01a 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -1,320 +1,532 @@ /* - Some comments on the code.. - - - it shouldn't be necessary to use outb_p(). - - - ignoreirq creates a race condition. It needs to be fixed. - + * das6402.c + * Comedi driver for DAS6402 compatible boards + * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Rewrite of an experimental driver by: + * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* - comedi/drivers/das6402.c - An experimental driver for Computerboards' DAS6402 I/O card + * Driver: das6402 + * Description: Keithley Metrabyte DAS6402 (& compatibles) + * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12) + * (Keithley Metrabyte) DAS6402-16 (das6402-16) + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Fri, 14 Mar 2014 10:18:43 -0700 + * Status: unknown + * + * Configuration Options: + * [0] - I/O base address + * [1] - IRQ (optional, needed for async command support) + */ - Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> +#include <linux/module.h> +#include <linux/interrupt.h> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +#include "../comedidev.h" +#include "8253.h" - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - */ /* -Driver: das6402 -Description: Keithley Metrabyte DAS6402 (& compatibles) -Author: Oystein Svendsen <svendsen@pvv.org> -Status: bitrotten -Devices: [Keithley Metrabyte] DAS6402 (das6402) + * Register I/O map + */ +#define DAS6402_AI_DATA_REG 0x00 +#define DAS6402_AI_MUX_REG 0x02 +#define DAS6402_AI_MUX_LO(x) (((x) & 0x3f) << 0) +#define DAS6402_AI_MUX_HI(x) (((x) & 0x3f) << 8) +#define DAS6402_DI_DO_REG 0x03 +#define DAS6402_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define DAS6402_STATUS_REG 0x08 +#define DAS6402_STATUS_FFNE (1 << 0) +#define DAS6402_STATUS_FHALF (1 << 1) +#define DAS6402_STATUS_FFULL (1 << 2) +#define DAS6402_STATUS_XINT (1 << 3) +#define DAS6402_STATUS_INT (1 << 4) +#define DAS6402_STATUS_XTRIG (1 << 5) +#define DAS6402_STATUS_INDGT (1 << 6) +#define DAS6402_STATUS_10MHZ (1 << 7) +#define DAS6402_STATUS_W_CLRINT (1 << 0) +#define DAS6402_STATUS_W_CLRXTR (1 << 1) +#define DAS6402_STATUS_W_CLRXIN (1 << 2) +#define DAS6402_STATUS_W_EXTEND (1 << 4) +#define DAS6402_STATUS_W_ARMED (1 << 5) +#define DAS6402_STATUS_W_POSTMODE (1 << 6) +#define DAS6402_STATUS_W_10MHZ (1 << 7) +#define DAS6402_CTRL_REG 0x09 +#define DAS6402_CTRL_SOFT_TRIG (0 << 0) +#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0) +#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0) +#define DAS6402_CTRL_PACER_TRIG (3 << 0) +#define DAS6402_CTRL_BURSTEN (1 << 2) +#define DAS6402_CTRL_XINTE (1 << 3) +#define DAS6402_CTRL_IRQ(x) ((x) << 4) +#define DAS6402_CTRL_INTE (1 << 7) +#define DAS6402_TRIG_REG 0x0a +#define DAS6402_TRIG_TGEN (1 << 0) +#define DAS6402_TRIG_TGSEL (1 << 1) +#define DAS6402_TRIG_TGPOL (1 << 2) +#define DAS6402_TRIG_PRETRIG (1 << 3) +#define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4)) +#define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4)) +#define DAS6402_MODE_REG 0x0b +#define DAS6402_MODE_RANGE(x) ((x) << 0) +#define DAS6402_MODE_POLLED (0 << 2) +#define DAS6402_MODE_FIFONEPTY (1 << 2) +#define DAS6402_MODE_FIFOHFULL (2 << 2) +#define DAS6402_MODE_EOB (3 << 2) +#define DAS6402_MODE_ENHANCED (1 << 4) +#define DAS6402_MODE_SE (1 << 5) +#define DAS6402_MODE_UNI (1 << 6) +#define DAS6402_MODE_DMA1 (0 << 7) +#define DAS6402_MODE_DMA3 (1 << 7) +#define DAS6402_TIMER_BASE 0x0c + +static const struct comedi_lrange das6402_ai_ranges = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } +}; -This driver has suffered bitrot. -*/ +/* + * Analog output ranges are programmable on the DAS6402/12. + * For the DAS6402/16 the range bits have no function, the + * DAC ranges are selected by switches on the board. + */ +static const struct comedi_lrange das6402_ao_ranges = { + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } +}; -#include <linux/interrupt.h> -#include "../comedidev.h" +struct das6402_boardinfo { + const char *name; + unsigned int maxdata; +}; -#include <linux/ioport.h> - -#define DAS6402_SIZE 16 - -#define N_WORDS (3000*64) - -#define STOP 0 -#define START 1 - -#define SCANL 0x3f00 -#define BYTE unsigned char -#define WORD unsigned short - -/*----- register 8 ----*/ -#define CLRINT 0x01 -#define CLRXTR 0x02 -#define CLRXIN 0x04 -#define EXTEND 0x10 -#define ARMED 0x20 /* enable conting of post sample conv */ -#define POSTMODE 0x40 -#define MHZ 0x80 /* 10 MHz clock */ -/*---------------------*/ - -/*----- register 9 ----*/ -#define IRQ (0x04 << 4) /* these two are */ -#define IRQV 10 /* dependent on each other */ - -#define CONVSRC 0x03 /* trig src is Intarnal pacer */ -#define BURSTEN 0x04 /* enable burst */ -#define XINTE 0x08 /* use external int. trig */ -#define INTE 0x80 /* enable analog interrupts */ -/*---------------------*/ - -/*----- register 10 ---*/ -#define TGEN 0x01 /* Use pin DI1 for externl trigging? */ -#define TGSEL 0x02 /* Use edge triggering */ -#define TGPOL 0x04 /* active edge is falling */ -#define PRETRIG 0x08 /* pretrig */ -/*---------------------*/ - -/*----- register 11 ---*/ -#define EOB 0x0c -#define FIFOHFULL 0x08 -#define GAIN 0x01 -#define FIFONEPTY 0x04 -#define MODE 0x10 -#define SEM 0x20 -#define BIP 0x40 -/*---------------------*/ - -#define M0 0x00 -#define M2 0x04 - -#define C0 0x00 -#define C1 0x40 -#define C2 0x80 -#define RWLH 0x30 +static struct das6402_boardinfo das6402_boards[] = { + { + .name = "das6402-12", + .maxdata = 0x0fff, + }, { + .name = "das6402-16", + .maxdata = 0xffff, + }, +}; struct das6402_private { - int ai_bytes_to_read; + unsigned int irq; + + unsigned int count; + unsigned int divider1; + unsigned int divider2; - int das6402_ignoreirq; + unsigned int ao_range; + unsigned int ao_readback[2]; }; -static void das6402_ai_fifo_dregs(struct comedi_device *dev, - struct comedi_subdevice *s) +static void das6402_set_mode(struct comedi_device *dev, + unsigned int mode) { - while (1) { - if (!(inb(dev->iobase + 8) & 0x01)) - return; - comedi_buf_put(s->async, inw(dev->iobase)); - } + outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG); } -static void das6402_setcounter(struct comedi_device *dev) +static void das6402_set_extended(struct comedi_device *dev, + unsigned int val) { - BYTE p; - unsigned short ctrlwrd; - - /* set up counter0 first, mode 0 */ - p = M0 | C0 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 2000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 12); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 12); - - /* set up counter1, mode 2 */ - p = M2 | C1 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 10; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 13); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 13); - - /* set up counter1, mode 2 */ - p = M2 | C2 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 1000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 14); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 14); + outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG); + outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG); + outb(val, dev->iobase + DAS6402_STATUS_REG); } -static irqreturn_t intr_handler(int irq, void *d) +static void das6402_clear_all_interrupts(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT | + DAS6402_STATUS_W_CLRXTR | + DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG); +} + +static void das6402_ai_clear_eoc(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG); +} + +static void das6402_enable_counter(struct comedi_device *dev, bool load) { - struct comedi_device *dev = d; struct das6402_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + unsigned long timer_iobase = dev->iobase + DAS6402_TIMER_BASE; - if (!dev->attached || devpriv->das6402_ignoreirq) { - dev_warn(dev->class_dev, "BUG: spurious interrupt\n"); - return IRQ_HANDLED; - } -#ifdef DEBUG - printk("das6402: interrupt! das6402_irqcount=%i\n", - devpriv->das6402_irqcount); - printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2)); -#endif - - das6402_ai_fifo_dregs(dev, s); - - if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) { - outw_p(SCANL, dev->iobase + 2); /* clears the fifo */ - outb(0x07, dev->iobase + 8); /* clears all flip-flops */ -#ifdef DEBUG - printk("das6402: Got %i samples\n\n", - devpriv->das6402_wordsread - diff); -#endif - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + if (load) { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_iobase, 0, 0, devpriv->count); + i8254_write(timer_iobase, 0, 1, devpriv->divider1); + i8254_write(timer_iobase, 0, 2, devpriv->divider2); + + } else { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY); } +} - outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */ +static irqreturn_t das6402_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + + das6402_clear_all_interrupts(dev); - comedi_event(dev, s); return IRQ_HANDLED; } -#if 0 -static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) +static int das6402_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { - int i; + return -EINVAL; +} - for (i = 0; i < n; i++) - data[i] = inw(dev->iobase); +static int das6402_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + return -EINVAL; } -#endif static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + return 0; +} + +static void das6402_ai_soft_trig(struct comedi_device *dev) +{ + outw(0, dev->iobase + DAS6402_AI_DATA_REG); +} + +static int das6402_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS6402_STATUS_REG); + if (status & DAS6402_STATUS_FFNE) + return 0; + return -EBUSY; +} + +static int das6402_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned int val; + int ret; + int i; + + val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED; + if (aref == AREF_DIFF) { + if (chan > s->n_chan / 2) + return -EINVAL; + } else { + val |= DAS6402_MODE_SE; + } + if (comedi_range_is_unipolar(s, range)) + val |= DAS6402_MODE_UNI; + + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + das6402_set_mode(dev, val); + + /* load the mux for single channel conversion */ + outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan), + dev->iobase + DAS6402_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + das6402_ai_clear_eoc(dev); + das6402_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0); + if (ret) + break; + + val = inw(dev->iobase + DAS6402_AI_DATA_REG); + + if (s->maxdata == 0x0fff) + val >>= 4; + + data[i] = val; + } + + das6402_ai_clear_eoc(dev); + + return insn->n; +} + +static int das6402_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + /* set the range for this channel */ + val = devpriv->ao_range; + val &= ~DAS6402_AO_RANGE_MASK(chan); + val |= DAS6402_AO_RANGE(chan, range); + if (val != devpriv->ao_range) { + devpriv->ao_range = val; + outb(val, dev->iobase + DAS6402_TRIG_REG); + } /* - * This function should reset the board from whatever condition it - * is in (i.e., acquiring data), to a non-active state. + * The DAS6402/16 has a jumper to select either individual + * update (UPDATE) or simultaneous updating (XFER) of both + * DAC's. In UPDATE mode, when the MSB is written, that DAC + * is updated. In XFER mode, after both DAC's are loaded, + * a read cycle of any DAC register will update both DAC's + * simultaneously. + * + * If you have XFER mode enabled a (*insn_read) will need + * to be performed in order to update the DAC's with the + * last value written. */ + for (i = 0; i < insn->n; i++) { + val = data[i]; + + devpriv->ao_readback[chan] = val; + + if (s->maxdata == 0x0fff) { + /* + * DAS6402/12 has the two 8-bit DAC registers, left + * justified (the 4 LSB bits are don't care). Data + * can be written as one word. + */ + val <<= 4; + outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan)); + } else { + /* + * DAS6402/16 uses both 8-bit DAC registers and needs + * to be written LSB then MSB. + */ + outb(val & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + } + } - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Stopping acquisition\n"); - devpriv->das6402_ignoreirq = 1; - outb_p(0x02, dev->iobase + 10); /* disable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(0, dev->iobase + 9); /* disables interrupts */ - - outw_p(SCANL, dev->iobase + 2); - - return 0; + return insn->n; } -#ifdef unused -static int das6402_ai_mode2(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) +static int das6402_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Starting acquisition\n"); - outb_p(0x03, dev->iobase + 10); /* enable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); + /* + * If XFER mode is enabled, reading any DAC register + * will update both DAC's simultaneously. + */ + inw(dev->iobase + DAS6402_AO_LSB_REG(chan)); - devpriv->ai_bytes_to_read = it->n * sizeof(short); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - /* um... ignoreirq is a nasty race condition */ - devpriv->das6402_ignoreirq = 0; + return insn->n; +} - outw_p(SCANL, dev->iobase + 2); +static int das6402_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + DAS6402_DI_DO_REG); - return 0; + return insn->n; } -#endif -static int board_init(struct comedi_device *dev) +static int das6402_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct das6402_private *devpriv = dev->private; - BYTE b; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS6402_DI_DO_REG); - devpriv->das6402_ignoreirq = 1; + data[1] = s->state; - outb(0x07, dev->iobase + 8); + return insn->n; +} - /* register 11 */ - outb_p(MODE, dev->iobase + 11); - b = BIP | SEM | MODE | GAIN | FIFOHFULL; - outb_p(b, dev->iobase + 11); +static void das6402_reset(struct comedi_device *dev) +{ + struct das6402_private *devpriv = dev->private; - /* register 8 */ - outb_p(EXTEND, dev->iobase + 8); - b = EXTEND | MHZ; - outb_p(b, dev->iobase + 8); - b = MHZ | CLRINT | CLRXTR | CLRXIN; - outb_p(b, dev->iobase + 8); + /* enable "Enhanced" mode */ + outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG); - /* register 9 */ - b = IRQ | CONVSRC | BURSTEN | INTE; - outb_p(b, dev->iobase + 9); + /* enable 10MHz pacer clock */ + das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ); - /* register 10 */ - b = TGSEL | TGEN; - outb_p(b, dev->iobase + 10); + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); - b = 0x07; - outb_p(b, dev->iobase + 8); + /* default ADC to single-ended unipolar 10V inputs */ + das6402_set_mode(dev, DAS6402_MODE_RANGE(0) | + DAS6402_MODE_POLLED | + DAS6402_MODE_SE | + DAS6402_MODE_UNI); - das6402_setcounter(dev); + /* default mux for single channel conversion (channel 0) */ + outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0), + dev->iobase + DAS6402_AI_MUX_REG); - outw_p(SCANL, dev->iobase + 2); /* reset card fifo */ + /* set both DAC's for unipolar 5V output range */ + devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2); + outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG); - devpriv->das6402_ignoreirq = 0; + /* set both DAC's to 0V */ + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + inw(dev->iobase + DAS6402_AO_LSB_REG(0)); - return 0; + das6402_enable_counter(dev, false); + + /* set all digital outputs low */ + outb(0, dev->iobase + DAS6402_DI_DO_REG); + + das6402_clear_all_interrupts(dev); } static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct das6402_boardinfo *board = comedi_board(dev); struct das6402_private *devpriv; - unsigned int irq; - int ret; struct comedi_subdevice *s; + int ret; - ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE); - if (ret) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - irq = it->options[0]; - dev_dbg(dev->class_dev, "( irq = %u )\n", irq); - ret = request_irq(irq, intr_handler, 0, "das6402", dev); - if (ret < 0) + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) return ret; - dev->irq = irq; - - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; + das6402_reset(dev); + + /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ + if ((1 << it->options[1]) & 0x8cec) { + ret = request_irq(it->options[1], das6402_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = it->options[1]; + + switch (dev->irq) { + case 10: + devpriv->irq = 4; + break; + case 11: + devpriv->irq = 1; + break; + case 15: + devpriv->irq = 6; + break; + default: + devpriv->irq = dev->irq; + break; + } + } + } - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - /* ai subdevice */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - /* s->trig[2]=das6402_ai_mode2; */ - s->cancel = das6402_ai_cancel; - s->maxdata = (1 << 12) - 1; - s->len_chanlist = 16; /* ? */ - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 64; + s->maxdata = board->maxdata; + s->range_table = &das6402_ai_ranges; + s->insn_read = das6402_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = das6402_ai_cmdtest; + s->do_cmd = das6402_ai_cmd; + s->cancel = das6402_ai_cancel; + } - board_init(dev); + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = board->maxdata; + s->range_table = &das6402_ao_ranges; + s->insn_write = das6402_ao_insn_write; + s->insn_read = das6402_ao_insn_read; + + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_di_insn_bits; + + /* Digital Input subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_do_insn_bits; return 0; } @@ -324,9 +536,12 @@ static struct comedi_driver das6402_driver = { .module = THIS_MODULE, .attach = das6402_attach, .detach = comedi_legacy_detach, + .board_name = &das6402_boards[0].name, + .num_names = ARRAY_SIZE(das6402_boards), + .offset = sizeof(struct das6402_boardinfo), }; module_comedi_driver(das6402_driver) -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 091cd911b38..6f7f8d531dd 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -56,17 +56,16 @@ cmd triggers supported: */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> #include "8253.h" #include "comedi_fc.h" #define DAS800_SIZE 8 -#define TIMER_BASE 1000 #define N_CHAN_AI 8 /* number of analog input channels */ /* Registers for the das800 */ @@ -225,7 +224,6 @@ struct das800_private { unsigned int divisor1; /* counter 1 value for timed conversions */ unsigned int divisor2; /* counter 2 value for timed conversions */ unsigned int do_bits; /* digital output bits */ - bool forever; /* flag that we should take data forever */ }; static void das800_ind_write(struct comedi_device *dev, @@ -276,31 +274,54 @@ static void das800_disable(struct comedi_device *dev) spin_unlock_irqrestore(&dev->spinlock, irq_flags); } -static int das800_set_frequency(struct comedi_device *dev) +static void das800_set_frequency(struct comedi_device *dev) { struct das800_private *devpriv = dev->private; - int err = 0; - - if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2)) - err++; - if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2)) - err++; - if (err) - return -1; + unsigned long timer_base = dev->iobase + DAS800_8254; - return 0; + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct das800_private *devpriv = dev->private; - devpriv->forever = false; devpriv->count = 0; das800_disable(dev); return 0; } +static int das800_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "chanlist must be consecutive, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; +} + static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -308,6 +329,7 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, const struct das800_board *thisboard = comedi_board(dev); struct das800_private *devpriv = dev->private; int err = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -353,42 +375,20 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - int tmp = cmd->convert_arg; - - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_1MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - unsigned int chan = CR_CHAN(cmd->chanlist[0]); - unsigned int range = CR_RANGE(cmd->chanlist[0]); - unsigned int next; - int i; - - for (i = 1; i < cmd->chanlist_len; i++) { - next = cmd->chanlist[i]; - if (CR_CHAN(next) != (chan + i) % N_CHAN_AI) { - dev_err(dev->class_dev, - "chanlist must be consecutive, counting upwards\n"); - err++; - } - if (CR_RANGE(next) != range) { - dev_err(dev->class_dev, - "chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das800_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -402,9 +402,10 @@ static int das800_ai_do_cmd(struct comedi_device *dev, const struct das800_board *thisboard = comedi_board(dev); struct das800_private *devpriv = dev->private; struct comedi_async *async = s->async; - unsigned int gain = CR_RANGE(async->cmd.chanlist[0]); - unsigned int start_chan = CR_CHAN(async->cmd.chanlist[0]); - unsigned int end_chan = (start_chan + async->cmd.chanlist_len - 1) % 8; + struct comedi_cmd *cmd = &async->cmd; + unsigned int gain = CR_RANGE(cmd->chanlist[0]); + unsigned int start_chan = CR_CHAN(cmd->chanlist[0]); + unsigned int end_chan = (start_chan + cmd->chanlist_len - 1) % 8; unsigned int scan_chans = (end_chan << 3) | start_chan; int conv_bits; unsigned long irq_flags; @@ -422,46 +423,28 @@ static int das800_ai_do_cmd(struct comedi_device *dev, gain &= 0xf; outb(gain, dev->iobase + DAS800_GAIN); - switch (async->cmd.stop_src) { - case TRIG_COUNT: - devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len; - devpriv->forever = false; - break; - case TRIG_NONE: - devpriv->forever = true; + if (cmd->stop_src == TRIG_COUNT) + devpriv->count = cmd->stop_arg * cmd->chanlist_len; + else /* TRIG_NONE */ devpriv->count = 0; - break; - default: - break; - } /* enable auto channel scan, send interrupts on end of conversion * and set clock source to internal or external */ conv_bits = 0; conv_bits |= EACS | IEOC; - if (async->cmd.start_src == TRIG_EXT) + if (cmd->start_src == TRIG_EXT) conv_bits |= DTEN; - switch (async->cmd.convert_src) { - case TRIG_TIMER: + if (cmd->convert_src == TRIG_TIMER) { conv_bits |= CASC | ITE; /* set conversion frequency */ - if (das800_set_frequency(dev) < 0) { - comedi_error(dev, "Error setting up counters"); - return -1; - } - break; - case TRIG_EXT: - break; - default: - break; + das800_set_frequency(dev); } spin_lock_irqsave(&dev->spinlock, irq_flags); das800_ind_write(dev, conv_bits, CONV_CONTROL); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - async->events = 0; das800_enable(dev); return 0; } @@ -479,7 +462,8 @@ static irqreturn_t das800_interrupt(int irq, void *d) struct comedi_device *dev = d; struct das800_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s ? s->async : NULL; + struct comedi_async *async; + struct comedi_cmd *cmd; unsigned long irq_flags; unsigned int status; unsigned int val; @@ -493,6 +477,9 @@ static irqreturn_t das800_interrupt(int irq, void *d) if (!dev->attached) return IRQ_HANDLED; + async = s->async; + cmd = &async->cmd; + spin_lock_irqsave(&dev->spinlock, irq_flags); status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN; /* @@ -524,7 +511,7 @@ static irqreturn_t das800_interrupt(int irq, void *d) val >>= 4; /* 12-bit sample */ /* if there are more data points to collect */ - if (devpriv->count > 0 || devpriv->forever) { + if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) { /* write data point to buffer */ cfc_write_to_buffer(s, val & s->maxdata); devpriv->count--; @@ -534,14 +521,12 @@ static irqreturn_t das800_interrupt(int irq, void *d) if (fifo_overflow) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); - das800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); - async->events = 0; + cfc_handle_events(dev, s); return IRQ_HANDLED; } - if (devpriv->count > 0 || devpriv->forever) { + if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) { /* Re-enable card's interrupt. * We already have spinlock, so indirect addressing is safe */ das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, @@ -553,20 +538,21 @@ static irqreturn_t das800_interrupt(int irq, void *d) das800_disable(dev); async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - async->events = 0; + cfc_handle_events(dev, s); return IRQ_HANDLED; } -static int das800_wait_for_conv(struct comedi_device *dev, int timeout) +static int das800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < timeout; i++) { - if (!(inb(dev->iobase + DAS800_STATUS) & BUSY)) - return 0; - } - return -ETIME; + status = inb(dev->iobase + DAS800_STATUS); + if ((status & BUSY) == 0) + return 0; + return -EBUSY; } static int das800_ai_insn_read(struct comedi_device *dev, @@ -601,7 +587,7 @@ static int das800_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ outb_p(0, dev->iobase + DAS800_MSB); - ret = das800_wait_for_conv(dev, 1000); + ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0); if (ret) return ret; @@ -630,13 +616,9 @@ static int das800_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct das800_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; unsigned long irq_flags; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) { devpriv->do_bits = s->state << 4; spin_lock_irqsave(&dev->spinlock, irq_flags); @@ -692,7 +674,7 @@ static int das800_probe(struct comedi_device *dev) static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das800_board *thisboard = comedi_board(dev); + const struct das800_board *thisboard; struct das800_private *devpriv; struct comedi_subdevice *s; unsigned int irq = it->options[1]; @@ -700,10 +682,9 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) int board; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_request_region(dev, it->options[0], DAS800_SIZE); if (ret) diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index e29847d73b4..ad7a5d53b97 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -32,9 +32,10 @@ Configuration Options: comedi_config /dev/comedi0 dmm32at baseaddr,irq */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> #include "comedi_fc.h" @@ -123,13 +124,12 @@ Configuration Options: /* board AI ranges in comedi structure */ static const struct comedi_lrange dmm32at_airanges = { - 4, - { - UNI_RANGE(10), - UNI_RANGE(5), - BIP_RANGE(10), - BIP_RANGE(5), - } + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + BIP_RANGE(10), + BIP_RANGE(5) + } }; /* register values for above ranges */ @@ -144,13 +144,12 @@ static const unsigned char dmm32at_rangebits[] = { * board. The application should only use the range set by the jumper */ static const struct comedi_lrange dmm32at_aoranges = { - 4, - { - UNI_RANGE(10), - UNI_RANGE(5), - BIP_RANGE(10), - BIP_RANGE(5), - } + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + BIP_RANGE(10), + BIP_RANGE(5) + } }; struct dmm32at_private { @@ -165,24 +164,35 @@ struct dmm32at_private { }; +static int dmm32at_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + context); + if ((status & DMM32AT_STATUS) == 0) + return 0; + return -EBUSY; +} + static int dmm32at_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + int n; unsigned int d; - unsigned char status; unsigned short msb, lsb; unsigned char chan; int range; + int ret; /* get the channel and range number */ chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1); range = CR_RANGE(insn->chanspec); - /* printk("channel=0x%02x, range=%d\n",chan,range); */ - /* zero scan and fifo control and reset fifo */ outb(DMM32AT_FIFORESET, dev->iobase + DMM32AT_FIFOCNTRL); @@ -193,30 +203,20 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev, outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ outb(0xff, dev->iobase + DMM32AT_CONV); + /* wait for conversion to end */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AISTAT); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, + DMM32AT_AISTAT); + if (ret) + return ret; /* read data */ lsb = inb(dev->iobase + DMM32AT_AILSB); @@ -243,13 +243,39 @@ static int dmm32at_ns_to_timer(unsigned int *ns, int round) return *ns; } +static int dmm32at_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; +} + static int dmm32at_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; - int start_chan, gain, i; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -325,50 +351,28 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - dmm32at_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + dmm32at_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - dmm32at_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + dmm32at_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } if (err) return 4; - /* step 5 check the channel list, the channel list for this - board must be consecutive and gains must be the same */ - - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= dmm32at_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -410,8 +414,9 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct dmm32at_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int i, range; - unsigned char chanlo, chanhi, status; + int range; + unsigned char chanlo, chanhi; + int ret; if (!cmd->chanlist) return -EINVAL; @@ -446,16 +451,13 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * isr */ } - /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + /* + * wait for circuit to settle + * we don't have the 'insn' here but it's not needed + */ + ret = comedi_timeout(dev, s, NULL, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; if (devpriv->ai_scans_left > 1) { /* start the clock and enable the interrupts */ @@ -466,14 +468,6 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outb(0xff, dev->iobase + DMM32AT_CONV); } -/* printk("dmmat32 in command\n"); */ - -/* for(i=0;i<cmd->chanlist_len;i++) */ -/* comedi_buf_put(s->async,i*100); */ - -/* s->async->events |= COMEDI_CB_EOA; */ -/* comedi_event(dev, s); */ - return 0; } @@ -514,7 +508,7 @@ static irqreturn_t dmm32at_isr(int irq, void *d) /* invert sign bit to make range unsigned */ samp = ((msb ^ 0x0080) << 8) + lsb; - comedi_buf_put(s->async, samp); + comedi_buf_put(s, samp); } if (devpriv->ai_scans_left != 0xffffffff) { /* TRIG_COUNT */ @@ -536,6 +530,19 @@ static irqreturn_t dmm32at_isr(int irq, void *d) return IRQ_HANDLED; } +static int dmm32at_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + DMM32AT_DACSTAT); + if ((status & DMM32AT_DACBUSY) == 0) + return 0; + return -EBUSY; +} + static int dmm32at_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -544,6 +551,7 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, int i; int chan = CR_CHAN(insn->chanspec); unsigned char hi, lo, status; + int ret; /* Writing a list of values to an AO channel is probably not * very useful, but that's how the interface is defined. */ @@ -555,21 +563,15 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, lo = data[i] & 0x00ff; /* high byte also contains channel number */ hi = (data[i] >> 8) + chan * (1 << 6); - /* printk("writing 0x%02x 0x%02x\n",hi,lo); */ /* write the low and high values to the board */ outb(lo, dev->iobase + DMM32AT_DACLSB); outb(hi, dev->iobase + DMM32AT_DACMSB); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_DACSTAT); - if ((status & DMM32AT_DACBUSY) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0); + if (ret) + return ret; + /* dummy read to update trigger the output */ status = inb(dev->iobase + DMM32AT_DACMSB); @@ -595,83 +597,74 @@ static int dmm32at_ao_rinsn(struct comedi_device *dev, static int dmm32at_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct dmm32at_private *devpriv = dev->private; - unsigned char diobits; - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - /* outw(s->state,dev->iobase + DMM32AT_DIO); */ + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* get access to the DIO regs */ + outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); + + /* if either part of dio is set for output */ + if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || + ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { + val = (s->state & 0x00ff0000) >> 16; + outb(val, dev->iobase + DMM32AT_DIOC); + } + if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { + val = (s->state & 0x0000ff00) >> 8; + outb(val, dev->iobase + DMM32AT_DIOB); + } + if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { + val = (s->state & 0x000000ff); + outb(val, dev->iobase + DMM32AT_DIOA); + } } - /* get access to the DIO regs */ - outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); - - /* if either part of dio is set for output */ - if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || - ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { - diobits = (s->state & 0x00ff0000) >> 16; - outb(diobits, dev->iobase + DMM32AT_DIOC); - } - if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { - diobits = (s->state & 0x0000ff00) >> 8; - outb(diobits, dev->iobase + DMM32AT_DIOB); - } - if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { - diobits = (s->state & 0x000000ff); - outb(diobits, dev->iobase + DMM32AT_DIOA); - } + val = inb(dev->iobase + DMM32AT_DIOA); + val |= inb(dev->iobase + DMM32AT_DIOB) << 8; + val |= inb(dev->iobase + DMM32AT_DIOC) << 16; + s->state = val; - /* now read the state back in */ - s->state = inb(dev->iobase + DMM32AT_DIOC); - s->state <<= 8; - s->state |= inb(dev->iobase + DMM32AT_DIOB); - s->state <<= 8; - s->state |= inb(dev->iobase + DMM32AT_DIOA); - data[1] = s->state; - - /* on return, data[1] contains the value of the digital - * input and output lines. */ - /* data[1]=inw(dev->iobase + DMM32AT_DIO); */ - /* or we could just return the software copy of the output values if - * it was a purely digital output subdevice */ - /* data[1]=s->state; */ + data[1] = val; return insn->n; } static int dmm32at_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct dmm32at_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; unsigned char chanbit; - int chan = CR_CHAN(insn->chanspec); - - if (insn->n != 1) - return -EINVAL; + int ret; - if (chan < 8) + if (chan < 8) { + mask = 0x0000ff; chanbit = DMM32AT_DIRA; - else if (chan < 16) + } else if (chan < 16) { + mask = 0x00ff00; chanbit = DMM32AT_DIRB; - else if (chan < 20) + } else if (chan < 20) { + mask = 0x0f0000; chanbit = DMM32AT_DIRCL; - else + } else { + mask = 0xf00000; chanbit = DMM32AT_DIRCH; + } - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - /* if output clear the bit, otherwise set it */ - if (data[0] == COMEDI_OUTPUT) + if (data[0] == INSN_CONFIG_DIO_OUTPUT) devpriv->dio_config &= ~chanbit; else devpriv->dio_config |= chanbit; @@ -680,7 +673,7 @@ static int dmm32at_dio_insn_config(struct comedi_device *dev, /* set the DIO's to the new configuration setting */ outb(devpriv->dio_config, dev->iobase + DMM32AT_DIOCONF); - return 1; + return insn->n; } static int dmm32at_attach(struct comedi_device *dev, @@ -690,9 +683,6 @@ static int dmm32at_attach(struct comedi_device *dev, int ret; struct comedi_subdevice *s; unsigned char aihi, ailo, fifostat, aistat, intstat, airback; - unsigned int irq; - - irq = it->options[1]; ret = comedi_request_region(dev, it->options[0], DMM32AT_MEMSIZE); if (ret) @@ -731,52 +721,44 @@ static int dmm32at_attach(struct comedi_device *dev, intstat = inb(dev->iobase + DMM32AT_INTCLOCK); airback = inb(dev->iobase + DMM32AT_AIRBACK); - printk(KERN_DEBUG "dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n", - ailo, aihi, fifostat); - printk(KERN_DEBUG - "dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n", - aistat, intstat, airback); - if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) || (aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) { - printk(KERN_ERR "dmmat32: board detection failed\n"); + dev_err(dev->class_dev, "board detection failed\n"); return -EIO; } - /* board is there, register interrupt */ - if (irq) { - ret = request_irq(irq, dmm32at_isr, 0, dev->board_name, dev); - if (ret < 0) { - printk(KERN_ERR "dmm32at: irq conflict\n"); - return ret; - } - dev->irq = irq; + if (it->options[1]) { + ret = request_irq(it->options[1], dmm32at_isr, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; /* we support single-ended (ground) and differential */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; s->n_chan = 32; s->maxdata = 0xffff; s->range_table = &dmm32at_airanges; - s->len_chanlist = 32; /* This is the maximum chanlist length that - the board can handle */ s->insn_read = dmm32at_ai_rinsn; - s->do_cmd = dmm32at_ai_cmd; - s->do_cmdtest = dmm32at_ai_cmdtest; - s->cancel = dmm32at_ai_cancel; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 32; + s->do_cmd = dmm32at_ai_cmd; + s->do_cmdtest = dmm32at_ai_cmdtest; + s->cancel = dmm32at_ai_cancel; + } s = &dev->subdevices[1]; /* analog output subdevice */ @@ -808,11 +790,7 @@ static int dmm32at_attach(struct comedi_device *dev, s->insn_bits = dmm32at_dio_insn_bits; s->insn_config = dmm32at_dio_insn_config; - /* success */ - printk(KERN_INFO "comedi%d: dmm32at: attached\n", dev->minor); - - return 1; - + return 0; } static struct comedi_driver dmm32at_driver = { diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index 8f5006d70da..4263014426f 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -29,9 +29,9 @@ Configuration options: [5] - D/A 1 range (same choices) */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> #define DT2801_TIMEOUT 1000 @@ -90,58 +90,42 @@ Configuration options: #if 0 /* ignore 'defined but not used' warning */ -static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, { - RANGE(-10, - 10), - RANGE(-5, - 5), - RANGE - (-2.5, - 2.5), - RANGE - (-1.25, - 1.25), - } +static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } }; #endif -static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { 4, { - RANGE(-10, - 10), - RANGE(-1, - 1), - RANGE - (-0.1, - 0.1), - RANGE - (-0.02, - 0.02), - } +static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) + } }; #if 0 /* ignore 'defined but not used' warning */ -static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { 4, { - RANGE(0, - 10), - RANGE(0, - 5), - RANGE(0, - 2.5), - RANGE(0, - 1.25), - } +static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; #endif -static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { 4, { - RANGE(0, - 10), - RANGE(0, - 1), - RANGE(0, - 0.1), - RANGE(0, - 0.02), - } +static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { + 4, { + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) + } }; struct dt2801_board { @@ -260,7 +244,8 @@ static int dt2801_readdata(struct comedi_device *dev, int *data) static int dt2801_readdata2(struct comedi_device *dev, int *data) { - int lb, hb; + int lb = 0; + int hb = 0; int ret; ret = dt2801_readdata(dev, &lb); @@ -288,13 +273,6 @@ static int dt2801_writedata(struct comedi_device *dev, unsigned int data) outb_p(data & 0xff, dev->iobase + DT2801_DATA); return 0; } -#if 0 - if (stat & DT_S_READY) { - printk - ("dt2801: ready flag set (bad!) in dt2801_writedata()\n"); - return -EIO; - } -#endif } while (--timeout > 0); return -ETIME; @@ -342,11 +320,11 @@ static int dt2801_writecmd(struct comedi_device *dev, int command) stat = inb_p(dev->iobase + DT2801_STATUS); if (stat & DT_S_COMPOSITE_ERROR) { - printk - ("dt2801: composite-error in dt2801_writecmd(), ignoring\n"); + dev_dbg(dev->class_dev, + "composite-error in %s, ignoring\n", __func__); } if (!(stat & DT_S_READY)) - printk("dt2801: !ready in dt2801_writecmd(), ignoring\n"); + dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__); outb_p(command, dev->iobase + DT2801_CMD); return 0; @@ -358,17 +336,12 @@ static int dt2801_reset(struct comedi_device *dev) unsigned int stat; int timeout; - DPRINTK("dt2801: resetting board...\n"); - DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase), - inb_p(dev->iobase + 1)); - /* pull random data from data port */ inb_p(dev->iobase + DT2801_DATA); inb_p(dev->iobase + DT2801_DATA); inb_p(dev->iobase + DT2801_DATA); inb_p(dev->iobase + DT2801_DATA); - DPRINTK("dt2801: stop\n"); /* dt2801_writecmd(dev,DT_C_STOP); */ outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); @@ -381,12 +354,10 @@ static int dt2801_reset(struct comedi_device *dev) break; } while (timeout--); if (!timeout) - printk("dt2801: timeout 1 status=0x%02x\n", stat); + dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat); - /* printk("dt2801: reading dummy\n"); */ /* dt2801_readdata(dev,&board_code); */ - DPRINTK("dt2801: reset\n"); outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); /* dt2801_writecmd(dev,DT_C_RESET); */ @@ -398,13 +369,10 @@ static int dt2801_reset(struct comedi_device *dev) break; } while (timeout--); if (!timeout) - printk("dt2801: timeout 2 status=0x%02x\n", stat); + dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat); - DPRINTK("dt2801: reading code\n"); dt2801_readdata(dev, &board_code); - DPRINTK("dt2801: ok. code=0x%02x\n", board_code); - return board_code; } @@ -464,12 +432,12 @@ static int dt2801_error(struct comedi_device *dev, int stat) { if (stat < 0) { if (stat == -ETIME) - printk("dt2801: timeout\n"); + dev_dbg(dev->class_dev, "timeout\n"); else - printk("dt2801: error %d\n", stat); + dev_dbg(dev->class_dev, "error %d\n", stat); return stat; } - printk("dt2801: error status 0x%02x, resetting...\n", stat); + dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat); dt2801_reset(dev); dt2801_reset(dev); @@ -528,55 +496,42 @@ static int dt2801_ao_insn_write(struct comedi_device *dev, static int dt2801_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int which = 0; - - if (s == &dev->subdevices[3]) - which = 1; + int which = (s == &dev->subdevices[3]) ? 1 : 0; + unsigned int val = 0; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { dt2801_writecmd(dev, DT_C_WRITE_DIG); dt2801_writedata(dev, which); dt2801_writedata(dev, s->state); } + dt2801_writecmd(dev, DT_C_READ_DIG); dt2801_writedata(dev, which); - dt2801_readdata(dev, data + 1); + dt2801_readdata(dev, &val); + + data[1] = val; return insn->n; } static int dt2801_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int which = 0; - - if (s == &dev->subdevices[3]) - which = 1; - - /* configure */ - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits = 0xff; - dt2801_writecmd(dev, DT_C_SET_DIGOUT); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits = 0; - dt2801_writecmd(dev, DT_C_SET_DIGIN); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - default: - return -EINVAL; - } - dt2801_writedata(dev, which); + int ret; - return 1; + ret = comedi_dio_insn_config(dev, s, insn, data, 0xff); + if (ret) + return ret; + + dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN); + dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0); + + return insn->n; } /* @@ -590,7 +545,7 @@ static int dt2801_dio_insn_config(struct comedi_device *dev, */ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct dt2801_board *board = comedi_board(dev); + const struct dt2801_board *board; struct dt2801_private *devpriv; struct comedi_subdevice *s; int board_code, type; @@ -613,8 +568,8 @@ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (boardtypes[type].boardcode == board_code) goto havetype; } - printk("dt2801: unrecognized board code=0x%02x, contact author\n", - board_code); + dev_dbg(dev->class_dev, + "unrecognized board code=0x%02x, contact author\n", board_code); type = 0; havetype: @@ -627,10 +582,9 @@ havetype: if (ret) goto out; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; dev->board_name = board->name; diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 5348cdae408..ba7c2ba618e 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -41,62 +41,60 @@ Configuration options: [4] - D/A 1 range (same choices) */ -#include <linux/interrupt.h> +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - RANGE(0, 0.625) + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625) } }; static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = { 4, { - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(-0.625, 0.625), - RANGE(-0.3125, 0.3125) + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) } }; static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = { 4, { - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(-0.625, 0.625) + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) } }; static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = { 4, { - RANGE(0, 5), - RANGE(0, 0.5), - RANGE(0, 0.05), - RANGE(0, 0.01) + UNI_RANGE(5), + UNI_RANGE(0.5), + UNI_RANGE(0.05), + UNI_RANGE(0.01) } }; static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = { 4, { - RANGE(-2.5, 2.5), - RANGE(-0.25, 0.25), - RANGE(-0.025, 0.025), - RANGE(-0.005, 0.005) + BIP_RANGE(2.5), + BIP_RANGE(0.25), + BIP_RANGE(0.025), + BIP_RANGE(0.005) } }; static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { 4, { - RANGE(-5, 5), - RANGE(-0.5, 0.5), - RANGE(-0.05, 0.05), - RANGE(-0.01, 0.01) + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.01) } }; @@ -226,50 +224,32 @@ static const struct comedi_lrange *dac_range_types[] = { &range_unipolar5 }; -#define DT2811_TIMEOUT 5 - -#if 0 -static irqreturn_t dt2811_interrupt(int irq, void *d) +static int dt2811_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int lo, hi; - int data; - struct comedi_device *dev = d; - struct dt2811_private *devpriv = dev->private; - - if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); - return IRQ_HANDLED; - } - - lo = inb(dev->iobase + DT2811_ADDATLO); - hi = inb(dev->iobase + DT2811_ADDATHI); - - data = lo + (hi << 8); + unsigned int status; - if (!(--devpriv->ntrig)) { - /* how to turn off acquisition */ - s->async->events |= COMEDI_SB_EOA; - } - comedi_event(dev, s); - return IRQ_HANDLED; + status = inb(dev->iobase + DT2811_ADCSR); + if ((status & DT2811_ADBUSY) == 0) + return 0; + return -EBUSY; } -#endif static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); - int timeout = DT2811_TIMEOUT; + int ret; int i; for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + DT2811_ADGCR); - while (timeout - && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) - timeout--; - if (!timeout) - return -ETIME; + ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0); + if (ret) + return ret; data[i] = inb(dev->iobase + DT2811_ADDATLO); data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; @@ -279,35 +259,6 @@ static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -#if 0 -/* Wow. This is code from the Comedi stone age. But it hasn't been - * replaced, so I'll let it stay. */ -int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) -{ - struct comedi_device *dev = comedi_devices + minor; - - if (adtrig->n < 1) - return 0; - dev->curadchan = adtrig->chan; - switch (dev->i_admode) { - case COMEDI_MDEMAND: - dev->ntrig = adtrig->n - 1; - /* not necessary */ - /*printk("dt2811: AD soft trigger\n"); */ - /*outb(DT2811_CLRERROR|DT2811_INTENB, - dev->iobase+DT2811_ADCSR); */ - outb(dev->curadchan, dev->iobase + DT2811_ADGCR); - do_gettimeofday(&trigtime); - break; - case COMEDI_MCONTS: - dev->ntrig = adtrig->n; - break; - } - - return 0; -} -#endif - static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { @@ -354,11 +305,11 @@ static int dt2811_di_insn_bits(struct comedi_device *dev, static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state, dev->iobase + DT2811_DIO); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DT2811_DIO); data[1] = s->state; @@ -387,10 +338,7 @@ static int dt2811_do_insn_bits(struct comedi_device *dev, */ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - /* int i, irq; */ - /* unsigned long irqs; */ - /* long flags; */ - + /* int i; */ const struct dt2811_board *board = comedi_board(dev); struct dt2811_private *devpriv; int ret; @@ -407,53 +355,13 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) i = inb(dev->iobase + DT2811_ADDATHI); #endif -#if 0 - irq = it->options[1]; - if (irq < 0) { - save_flags(flags); - sti(); - irqs = probe_irq_on(); - - outb(DT2811_CLRERROR | DT2811_INTENB, - dev->iobase + DT2811_ADCSR); - outb(0, dev->iobase + DT2811_ADGCR); - - udelay(100); - - irq = probe_irq_off(irqs); - restore_flags(flags); - - /*outb(DT2811_CLRERROR|DT2811_INTENB, - dev->iobase+DT2811_ADCSR);*/ - - if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) - printk(KERN_ERR "error probing irq (bad)\n"); - dev->irq = 0; - if (irq > 0) { - i = inb(dev->iobase + DT2811_ADDATLO); - i = inb(dev->iobase + DT2811_ADDATHI); - printk(KERN_INFO "(irq = %d)\n", irq); - ret = request_irq(irq, dt2811_interrupt, 0, - dev->board_name, dev); - if (ret < 0) - return -EIO; - dev->irq = irq; - } else if (irq == 0) { - printk(KERN_INFO "(no irq)\n"); - } else { - printk(KERN_ERR "( multiple irq's -- this is bad! )\n"); - } - } -#endif - ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; switch (it->options[2]) { case 0: diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index 87e9749c4be..904c9f0e4af 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -34,10 +34,10 @@ a power of 10, from 1 to 10^7, of which only 3 or 4 are useful. In addition, the clock does not seem to be very accurate. */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> #include "comedi_fc.h" @@ -66,29 +66,35 @@ struct dt2814_private { #define DT2814_TIMEOUT 10 #define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */ +static int dt2814_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2814_CSR); + if (status & DT2814_FINISH) + return 0; + return -EBUSY; +} + static int dt2814_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, hi, lo; + int n, hi, lo; int chan; - int status = 0; + int ret; for (n = 0; n < insn->n; n++) { chan = CR_CHAN(insn->chanspec); outb(chan, dev->iobase + DT2814_CSR); - for (i = 0; i < DT2814_TIMEOUT; i++) { - status = inb(dev->iobase + DT2814_CSR); - printk(KERN_INFO "dt2814: status: %02x\n", status); - udelay(10); - if (status & DT2814_FINISH) - break; - } - if (i >= DT2814_TIMEOUT) { - printk(KERN_INFO "dt2814: status: %02x\n", status); - return -ETIMEDOUT; - } + + ret = comedi_timeout(dev, s, insn, dt2814_ai_eoc, 0); + if (ret) + return ret; hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); @@ -122,7 +128,7 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -164,10 +170,9 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - tmp = cmd->scan_begin_arg; - dt2814_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + dt2814_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); if (err) return 4; @@ -200,7 +205,7 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) int lo, hi; struct comedi_device *dev = d; struct dt2814_private *devpriv = dev->private; - struct comedi_subdevice *s; + struct comedi_subdevice *s = dev->read_subdev; int data; if (!dev->attached) { @@ -208,8 +213,6 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) return IRQ_HANDLED; } - s = &dev->subdevices[0]; - hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); @@ -238,9 +241,9 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct dt2814_private *devpriv; - int i, irq; - int ret; struct comedi_subdevice *s; + int ret; + int i; ret = comedi_request_region(dev, it->options[0], DT2814_SIZE); if (ret) @@ -249,71 +252,41 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(0, dev->iobase + DT2814_CSR); udelay(100); if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) { - printk(KERN_ERR "reset error (fatal)\n"); + dev_err(dev->class_dev, "reset error (fatal)\n"); return -EIO; } i = inb(dev->iobase + DT2814_DATA); i = inb(dev->iobase + DT2814_DATA); - irq = it->options[1]; -#if 0 - if (irq < 0) { - save_flags(flags); - sti(); - irqs = probe_irq_on(); - - outb(0, dev->iobase + DT2814_CSR); - - udelay(100); - - irq = probe_irq_off(irqs); - restore_flags(flags); - if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) - printk(KERN_DEBUG "error probing irq (bad)\n"); - - - i = inb(dev->iobase + DT2814_DATA); - i = inb(dev->iobase + DT2814_DATA); - } -#endif - dev->irq = 0; - if (irq > 0) { - if (request_irq(irq, dt2814_interrupt, 0, "dt2814", dev)) { - printk(KERN_WARNING "(irq %d unavailable)\n", irq); - } else { - printk(KERN_INFO "( irq = %d )\n", irq); - dev->irq = irq; - } - } else if (irq == 0) { - printk(KERN_WARNING "(no irq)\n"); - } else { -#if 0 - printk(KERN_DEBUG "(probe returned multiple irqs--bad)\n"); -#else - printk(KERN_WARNING "(irq probe not implemented)\n"); -#endif + if (it->options[1]) { + ret = request_irq(it->options[1], dt2814_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; s = &dev->subdevices[0]; - dev->read_subdev = s; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = 16; /* XXX */ - s->len_chanlist = 1; s->insn_read = dt2814_ai_insn_read; - s->do_cmd = dt2814_ai_cmd; - s->do_cmdtest = dt2814_ai_cmdtest; s->maxdata = 0xfff; s->range_table = &range_unknown; /* XXX */ + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->do_cmd = dt2814_ai_cmd; + s->do_cmdtest = dt2814_ai_cmdtest; + } return 0; } diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index 0fcd4fe7acd..b9ac4ed8bab 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -51,9 +51,9 @@ Configuration options: [12] - Analog output 7 range configuration (same options) */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> #define DT2815_SIZE 2 @@ -67,15 +67,17 @@ struct dt2815_private { unsigned int ao_readback[8]; }; -static int dt2815_wait_for_status(struct comedi_device *dev, int status) +static int dt2815_ao_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < 100; i++) { - if (inb(dev->iobase + DT2815_STATUS) == status) - break; - } - return status; + status = inb(dev->iobase + DT2815_STATUS); + if (status == context) + return 0; + return -EBUSY; } static int dt2815_ao_insn_read(struct comedi_device *dev, @@ -98,28 +100,23 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct dt2815_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); - unsigned int status; unsigned int lo, hi; + int ret; for (i = 0; i < insn->n; i++) { lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01; hi = (data[i] & 0xff0) >> 4; - status = dt2815_wait_for_status(dev, 0x00); - if (status != 0) { - printk(KERN_WARNING "dt2815: failed to write low byte " - "on %d reason %x\n", chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x00); + if (ret) + return ret; outb(lo, dev->iobase + DT2815_DATA); - status = dt2815_wait_for_status(dev, 0x10); - if (status != 0x10) { - printk(KERN_WARNING "dt2815: failed to write high byte " - "on %d reason %x\n", chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x10); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; } return i; @@ -165,10 +162,9 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; s = &dev->subdevices[0]; /* ao subdevice */ @@ -201,12 +197,13 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) unsigned int program; program = (it->options[4] & 0x3) << 3 | 0x7; outb(program, dev->iobase + DT2815_DATA); - printk(KERN_INFO ", program: 0x%x (@t=%d)\n", - program, i); + dev_dbg(dev->class_dev, "program: 0x%x (@t=%d)\n", + program, i); break; } else if (status != 0x00) { - printk(KERN_WARNING "dt2815: unexpected status 0x%x " - "(@t=%d)\n", status, i); + dev_dbg(dev->class_dev, + "unexpected status 0x%x (@t=%d)\n", + status, i); if (status & 0x60) outb(0x00, dev->iobase + DT2815_STATUS); } diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c index 2f46be715f7..bf589936e54 100644 --- a/drivers/staging/comedi/drivers/dt2817.c +++ b/drivers/staging/comedi/drivers/dt2817.c @@ -33,10 +33,9 @@ Configuration options: [0] - I/O port base base address */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - #define DT2817_SIZE 5 #define DT2817_CR 0 @@ -44,28 +43,26 @@ Configuration options: static int dt2817_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int mask; - int chan; - int oe = 0; - - if (insn->n != 1) - return -EINVAL; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int oe = 0; + unsigned int mask; + int ret; - chan = CR_CHAN(insn->chanspec); if (chan < 8) - mask = 0xff; + mask = 0x000000ff; else if (chan < 16) - mask = 0xff00; + mask = 0x0000ff00; else if (chan < 24) - mask = 0xff0000; + mask = 0x00ff0000; else mask = 0xff000000; - if (data[0]) - s->io_bits |= mask; - else - s->io_bits &= ~mask; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; if (s->io_bits & 0x000000ff) oe |= 0x1; @@ -78,41 +75,36 @@ static int dt2817_dio_insn_config(struct comedi_device *dev, outb(oe, dev->iobase + DT2817_CR); - return 1; + return insn->n; } static int dt2817_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int changed; - - /* It's questionable whether it is more important in - * a driver like this to be deterministic or fast. - * We choose fast. */ - - if (data[0]) { - changed = s->state; - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - changed ^= s->state; - changed &= s->io_bits; - if (changed & 0x000000ff) - outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0); - if (changed & 0x0000ff00) - outb((s->state >> 8) & 0xff, - dev->iobase + DT2817_DATA + 1); - if (changed & 0x00ff0000) - outb((s->state >> 16) & 0xff, - dev->iobase + DT2817_DATA + 2); - if (changed & 0xff000000) - outb((s->state >> 24) & 0xff, - dev->iobase + DT2817_DATA + 3); + unsigned long iobase = dev->iobase + DT2817_DATA; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x000000ff) + outb(s->state & 0xff, iobase + 0); + if (mask & 0x0000ff00) + outb((s->state >> 8) & 0xff, iobase + 1); + if (mask & 0x00ff0000) + outb((s->state >> 16) & 0xff, iobase + 2); + if (mask & 0xff000000) + outb((s->state >> 24) & 0xff, iobase + 3); } - data[1] = inb(dev->iobase + DT2817_DATA + 0); - data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8); - data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16); - data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24); + + val = inb(iobase + 0); + val |= (inb(iobase + 1) << 8); + val |= (inb(iobase + 2) << 16); + val |= (inb(iobase + 3) << 24); + + data[1] = val; return insn->n; } diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index c1950e3b19a..c2a66dcf99f 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -51,18 +51,18 @@ Notes: be fixed to check for this situation and return an error. */ +#include <linux/module.h> #include "../comedidev.h" +#include <linux/delay.h> #include <linux/gfp.h> -#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/io.h> + #include <asm/dma.h> -#include "comedi_fc.h" -#define DEBUG +#include "comedi_fc.h" -#define DT2821_TIMEOUT 100 /* 500 us */ #define DT2821_SIZE 0x10 /* @@ -153,55 +153,55 @@ Notes: static const struct comedi_lrange range_dt282x_ai_lo_bipolar = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25) + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) } }; static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 4, { - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25) + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) } }; static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 4, { - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(-0.625, 0.625) + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) } }; static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 4, { - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - RANGE(0, 0.625), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625) } }; static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 4, { - RANGE(-10, 10), - RANGE(-1, 1), - RANGE(-0.1, 0.1), - RANGE(-0.02, 0.02) + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) } }; static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 4, { - RANGE(0, 10), - RANGE(0, 1), - RANGE(0, 0.1), - RANGE(0, 0.02) + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) } }; @@ -223,7 +223,7 @@ struct dt282x_private { const struct comedi_lrange *darangelist[2]; - short ao[2]; + unsigned short ao[2]; volatile int dacsr; /* software copies of registers */ volatile int adcsr; @@ -234,7 +234,7 @@ struct dt282x_private { struct { int chan; - short *buf; /* DMA buffer */ + unsigned short *buf; /* DMA buffer */ volatile int size; /* size of current transfer */ } dma[2]; int dma_maxsize; /* max size of DMA transfer (in bytes) */ @@ -247,26 +247,6 @@ struct dt282x_private { * Some useless abstractions */ #define chan_to_DAC(a) ((a)&1) -#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY) -#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE) - -/* - * danger! macro abuse... a is the expression to wait on, and b is - * the statement(s) to execute if it doesn't happen. - */ -#define wait_for(a, b) \ - do { \ - int _i; \ - for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \ - if (a) { \ - _i = 0; \ - break; \ - } \ - udelay(5); \ - } \ - if (_i) \ - b \ - } while (0) static int prep_ai_dma(struct comedi_device *dev, int chan, int size); static int prep_ao_dma(struct comedi_device *dev, int chan, int size); @@ -279,7 +259,7 @@ static void dt282x_disable_dma(struct comedi_device *dev); static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2); -static void dt282x_munge(struct comedi_device *dev, short *buf, +static void dt282x_munge(struct comedi_device *dev, unsigned short *buf, unsigned int nbytes) { const struct dt282x_board *board = comedi_board(dev); @@ -304,15 +284,15 @@ static void dt282x_munge(struct comedi_device *dev, short *buf, static void dt282x_ao_dma_interrupt(struct comedi_device *dev) { struct dt282x_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->write_subdev; void *ptr; int size; int i; - struct comedi_subdevice *s = &dev->subdevices[1]; outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); if (!s->async->prealloc_buf) { - printk(KERN_ERR "async->data disappeared. dang!\n"); + dev_err(dev->class_dev, "no buffer in %s\n", __func__); return; } @@ -325,8 +305,7 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); if (size == 0) { - printk(KERN_ERR "dt282x: AO underrun\n"); - dt282x_ao_cancel(dev, s); + dev_err(dev->class_dev, "AO underrun\n"); s->async->events |= COMEDI_CB_OVERFLOW; return; } @@ -337,16 +316,16 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) static void dt282x_ai_dma_interrupt(struct comedi_device *dev) { struct dt282x_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; void *ptr; int size; int i; int ret; - struct comedi_subdevice *s = &dev->subdevices[0]; outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); if (!s->async->prealloc_buf) { - printk(KERN_ERR "async->data disappeared. dang!\n"); + dev_err(dev->class_dev, "no buffer in %s\n", __func__); return; } @@ -361,17 +340,16 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) dt282x_munge(dev, ptr, size); ret = cfc_write_array_to_buffer(s, ptr, size); if (ret != size) { - dt282x_ai_cancel(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; return; } devpriv->nread -= size / 2; if (devpriv->nread < 0) { - printk(KERN_INFO "dt282x: off by one\n"); + dev_info(dev->class_dev, "nread off by one\n"); devpriv->nread = 0; } if (!devpriv->nread) { - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; return; } @@ -446,8 +424,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct dt282x_private *devpriv = dev->private; - struct comedi_subdevice *s; - struct comedi_subdevice *s_ao; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_subdevice *s_ao = dev->write_subdev; unsigned int supcsr, adcsr, dacsr; int handled = 0; @@ -456,8 +434,6 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) return IRQ_HANDLED; } - s = &dev->subdevices[0]; - s_ao = &dev->subdevices[1]; adcsr = inw(dev->iobase + DT2821_ADCSR); dacsr = inw(dev->iobase + DT2821_DACSR); supcsr = inw(dev->iobase + DT2821_SUPCSR); @@ -471,35 +447,26 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) if (adcsr & DT2821_ADERR) { if (devpriv->nread != 0) { comedi_error(dev, "A/D error"); - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_ERROR; } handled = 1; } if (dacsr & DT2821_DAERR) { -#if 0 - static int warn = 5; - if (--warn <= 0) { - disable_irq(dev->irq); - printk(KERN_INFO "disabling irq\n"); - } -#endif comedi_error(dev, "D/A error"); - dt282x_ao_cancel(dev, s_ao); - s->async->events |= COMEDI_CB_ERROR; + s_ao->async->events |= COMEDI_CB_ERROR; handled = 1; } #if 0 if (adcsr & DT2821_ADDONE) { int ret; - short data; + unsigned short data; - data = (short)inw(dev->iobase + DT2821_ADDAT); + data = inw(dev->iobase + DT2821_ADDAT); data &= (1 << board->adbits) - 1; if (devpriv->ad_2scomp) data ^= 1 << (board->adbits - 1); - ret = comedi_buf_put(s->async, data); + ret = comedi_buf_put(s, data); if (ret == 0) s->async->events |= COMEDI_CB_OVERFLOW; @@ -515,9 +482,9 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) handled = 1; } #endif - comedi_event(dev, s); - /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", - adcsr, dacsr, supcsr); */ + cfc_handle_events(dev, s); + cfc_handle_events(dev, s_ao); + return IRQ_RETVAL(handled); } @@ -538,6 +505,29 @@ static void dt282x_load_changain(struct comedi_device *dev, int n, outw(n - 1, dev->iobase + DT2821_CHANCSR); } +static int dt282x_ai_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + DT2821_ADCSR); + switch (context) { + case DT2821_MUXBUSY: + if ((status & DT2821_MUXBUSY) == 0) + return 0; + break; + case DT2821_ADDONE: + if (status & DT2821_ADDONE) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Performs a single A/D conversion. * - Put channel/gain into channel-gain list @@ -550,6 +540,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, { const struct dt282x_board *board = comedi_board(dev); struct dt282x_private *devpriv = dev->private; + int ret; int i; /* XXX should we really be enabling the ad clock here? */ @@ -559,13 +550,18 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, dt282x_load_changain(dev, 1, &insn->chanspec); outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; for (i = 0; i < insn->n; i++) { outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR); - wait_for(ad_done(), comedi_error(dev, "timeout\n"); - return -ETIME;); + + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, + DT2821_ADDONE); + if (ret) + return ret; data[i] = inw(dev->iobase + @@ -582,7 +578,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, { const struct dt282x_board *board = comedi_board(dev); int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -637,10 +633,9 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - tmp = cmd->convert_arg; - dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); if (err) return 4; @@ -654,6 +649,7 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct dt282x_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int timer; + int ret; if (devpriv->usedma == 0) { comedi_error(dev, @@ -699,7 +695,9 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; if (cmd->scan_begin_src == TRIG_FOLLOW) { outw(devpriv->supcsr | DT2821_STRIG, @@ -792,7 +790,7 @@ static int dt282x_ao_insn_write(struct comedi_device *dev, { const struct dt282x_board *board = comedi_board(dev); struct dt282x_private *devpriv = dev->private; - short d; + unsigned short d; unsigned int chan; chan = CR_CHAN(insn->chanspec); @@ -826,7 +824,7 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -853,7 +851,7 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) { /* any count is allowed */ @@ -866,10 +864,9 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - tmp = cmd->scan_begin_arg; - dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); if (err) return 4; @@ -879,18 +876,20 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, } static int dt282x_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int x) + struct comedi_subdevice *s, + unsigned int trig_num) { struct dt282x_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int size; - if (x != 0) + if (trig_num != cmd->start_src) return -EINVAL; size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, devpriv->dma_maxsize); if (size == 0) { - printk(KERN_ERR "dt282x: AO underrun\n"); + dev_err(dev->class_dev, "AO underrun\n"); return -EPIPE; } prep_ao_dma(dev, 0, size); @@ -898,7 +897,7 @@ static int dt282x_ao_inttrig(struct comedi_device *dev, size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, devpriv->dma_maxsize); if (size == 0) { - printk(KERN_ERR "dt282x: AO underrun\n"); + dev_err(dev->class_dev, "AO underrun\n"); return -EPIPE; } prep_ao_dma(dev, 1, size); @@ -963,14 +962,12 @@ static int dt282x_ao_cancel(struct comedi_device *dev, static int dt282x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + DT2821_DIODAT); - } + data[1] = inw(dev->iobase + DT2821_DIODAT); return insn->n; @@ -978,29 +975,32 @@ static int dt282x_dio_insn_bits(struct comedi_device *dev, static int dt282x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct dt282x_private *devpriv = dev->private; - int mask; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; - mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00; - if (data[0]) - s->io_bits |= mask; + if (chan < 8) + mask = 0x00ff; else - s->io_bits &= ~mask; + mask = 0xff00; + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + devpriv->dacsr &= ~(DT2821_LBOE | DT2821_HBOE); if (s->io_bits & 0x00ff) devpriv->dacsr |= DT2821_LBOE; - else - devpriv->dacsr &= ~DT2821_LBOE; if (s->io_bits & 0xff00) devpriv->dacsr |= DT2821_HBOE; - else - devpriv->dacsr &= ~DT2821_HBOE; outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); - return 1; + return insn->n; } static const struct comedi_lrange *const ai_range_table[] = { @@ -1057,10 +1057,8 @@ static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) devpriv->usedma = 0; - if (!dma1 && !dma2) { - printk(KERN_ERR " (no dma)"); + if (!dma1 && !dma2) return 0; - } if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7) return -EINVAL; @@ -1085,12 +1083,8 @@ static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) devpriv->dma_maxsize = PAGE_SIZE; devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) { - printk(KERN_ERR " can't get DMA memory"); + if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) return -ENOMEM; - } - - printk(KERN_INFO " (dma=%d,%d)", dma1, dma2); devpriv->usedma = 1; @@ -1115,9 +1109,9 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct dt282x_board *board = comedi_board(dev); struct dt282x_private *devpriv; - int i, irq; - int ret; struct comedi_subdevice *s; + int ret; + int i; ret = comedi_request_region(dev, it->options[0], DT2821_SIZE); if (ret) @@ -1125,14 +1119,6 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR); i = inw(dev->iobase + DT2821_ADCSR); -#ifdef DEBUG - printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x", - inw(dev->iobase + DT2821_ADCSR), - inw(dev->iobase + DT2821_CHANCSR), - inw(dev->iobase + DT2821_DACSR), - inw(dev->iobase + DT2821_SUPCSR), - inw(dev->iobase + DT2821_TMRCTR)); -#endif if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK) != DT2821_ADCSR_VAL) || @@ -1144,59 +1130,28 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) != DT2821_SUPCSR_VAL) || ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK) != DT2821_TMRCTR_VAL)) { - printk(KERN_ERR " board not found"); + dev_err(dev->class_dev, "board not found\n"); return -EIO; } /* should do board test */ - irq = it->options[opt_irq]; -#if 0 - if (irq < 0) { - unsigned long flags; - int irqs; - - save_flags(flags); - sti(); - irqs = probe_irq_on(); - - /* trigger interrupt */ - - udelay(100); - - irq = probe_irq_off(irqs); - restore_flags(flags); - if (0 /* error */) - printk(KERN_ERR " error probing irq (bad)"); - } -#endif - if (irq > 0) { - printk(KERN_INFO " ( irq = %d )", irq); - ret = request_irq(irq, dt282x_interrupt, 0, + if (it->options[opt_irq] > 0) { + ret = request_irq(it->options[opt_irq], dt282x_interrupt, 0, dev->board_name, dev); - if (ret < 0) { - printk(KERN_ERR " failed to get irq\n"); - return -EIO; - } - dev->irq = irq; - } else if (irq == 0) { - printk(KERN_INFO " (no irq)"); - } else { -#if 0 - printk(KERN_INFO " (probe returned multiple irqs--bad)"); -#else - printk(KERN_INFO " (irq probe not implemented)"); -#endif + if (ret == 0) + dev->irq = it->options[opt_irq]; } - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; - ret = dt282x_grab_dma(dev, it->options[opt_dma1], - it->options[opt_dma2]); - if (ret < 0) - return ret; + if (dev->irq) { + ret = dt282x_grab_dma(dev, it->options[opt_dma1], + it->options[opt_dma2]); + if (ret < 0) + return ret; + } ret = comedi_alloc_subdevices(dev, 3); if (ret) @@ -1204,22 +1159,25 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) s = &dev->subdevices[0]; - dev->read_subdev = s; /* ai subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ | + s->subdev_flags = SDF_READABLE | ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON); s->n_chan = (it->options[opt_diff]) ? board->adchan_di : board->adchan_se; s->insn_read = dt282x_ai_insn_read; - s->do_cmdtest = dt282x_ai_cmdtest; - s->do_cmd = dt282x_ai_cmd; - s->cancel = dt282x_ai_cancel; s->maxdata = (1 << board->adbits) - 1; - s->len_chanlist = 16; s->range_table = opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]); devpriv->ad_2scomp = it->options[opt_ai_twos]; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 16; + s->do_cmdtest = dt282x_ai_cmdtest; + s->do_cmd = dt282x_ai_cmd; + s->cancel = dt282x_ai_cancel; + } s = &dev->subdevices[1]; @@ -1227,15 +1185,10 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (s->n_chan) { /* ao subsystem */ s->type = COMEDI_SUBD_AO; - dev->write_subdev = s; - s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE; + s->subdev_flags = SDF_WRITABLE; s->insn_read = dt282x_ao_insn_read; s->insn_write = dt282x_ao_insn_write; - s->do_cmdtest = dt282x_ao_cmdtest; - s->do_cmd = dt282x_ao_cmd; - s->cancel = dt282x_ao_cancel; s->maxdata = (1 << board->dabits) - 1; - s->len_chanlist = 2; s->range_table_list = devpriv->darangelist; devpriv->darangelist[0] = opt_ao_range_lkup(it->options[opt_ao0_range]); @@ -1243,6 +1196,14 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) opt_ao_range_lkup(it->options[opt_ao1_range]); devpriv->da0_2scomp = it->options[opt_ao0_twos]; devpriv->da1_2scomp = it->options[opt_ao1_twos]; + if (dev->irq) { + dev->write_subdev = s; + s->subdev_flags |= SDF_CMD_WRITE; + s->len_chanlist = 2; + s->do_cmdtest = dt282x_ao_cmdtest; + s->do_cmd = dt282x_ao_cmd; + s->cancel = dt282x_ao_cancel; + } } else { s->type = COMEDI_SUBD_UNUSED; } @@ -1257,8 +1218,6 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 1; s->range_table = &range_digital; - printk(KERN_INFO "\n"); - return 0; } diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 01a2f889d5b..4ab4de00592 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -48,8 +48,7 @@ AO commands are not supported. you the docs without one, also. */ -#define DEBUG 1 - +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -252,24 +251,6 @@ struct dt3k_private { unsigned int ai_rear; }; -#ifdef DEBUG -static char *intr_flags[] = { - "AdFull", "AdSwError", "AdHwError", "DaEmpty", - "DaSwError", "DaHwError", "CtDone", "CmDone", -}; - -static void debug_intr_flags(unsigned int flags) -{ - int i; - printk(KERN_DEBUG "dt3k: intr_flags:"); - for (i = 0; i < 8; i++) { - if (flags & (1 << i)) - printk(KERN_CONT " %s", intr_flags[i]); - } - printk(KERN_CONT "\n"); -} -#endif - #define TIMEOUT 100 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) @@ -330,7 +311,7 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, int rear; int count; int i; - short data; + unsigned short data; front = readw(devpriv->io_addr + DPR_AD_Buf_Front); count = front - devpriv->ai_front; @@ -341,7 +322,7 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, for (i = 0; i < count; i++) { data = readw(devpriv->io_addr + DPR_ADC_buffer + rear); - comedi_buf_put(s->async, data); + comedi_buf_put(s, data); rear++; if (rear >= AI_FIFO_DEPTH) rear = 0; @@ -371,17 +352,13 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct dt3k_private *devpriv = dev->private; - struct comedi_subdevice *s; + struct comedi_subdevice *s = dev->read_subdev; unsigned int status; if (!dev->attached) return IRQ_NONE; - s = &dev->subdevices[0]; status = readw(devpriv->io_addr + DPR_Intr_Flag); -#ifdef DEBUG - debug_intr_flags(status); -#endif if (status & DT3000_ADFULL) { dt3k_ai_empty_fifo(dev, s); @@ -392,12 +369,10 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; debug_n_ints++; - if (debug_n_ints >= 10) { - dt3k_ai_cancel(dev, s); + if (debug_n_ints >= 10) s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -441,7 +416,7 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev, { const struct dt3k_boardtype *this_board = comedi_board(dev); int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -491,25 +466,20 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - dt3k_ns_to_timer(100, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + dt3k_ns_to_timer(100, &arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - dt3k_ns_to_timer(50, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + dt3k_ns_to_timer(50, &arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -641,45 +611,35 @@ static void dt3k_dio_config(struct comedi_device *dev, int bits) static int dt3k_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int mask; - - mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0; - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } - mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3); - dt3k_dio_config(dev, mask); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3)); return insn->n; } static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[1] & data[0]; + if (comedi_dio_update_state(s, data)) dt3k_writesingle(dev, SUBS_DOUT, 0, s->state); - } + data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0); return insn->n; @@ -722,10 +682,9 @@ static int dt3000_auto_attach(struct comedi_device *dev, dev->board_ptr = this_board; dev->board_name = this_board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret < 0) @@ -735,29 +694,33 @@ static int dt3000_auto_attach(struct comedi_device *dev, if (!devpriv->io_addr) return -ENOMEM; - ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED, - dev->board_name, dev); - if (ret) - return ret; - dev->irq = pcidev->irq; + if (pcidev->irq) { + ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; /* ai subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; s->n_chan = this_board->adchan; s->insn_read = dt3k_ai_insn; s->maxdata = (1 << this_board->adbits) - 1; - s->len_chanlist = 512; s->range_table = &range_dt3000_ai; /* XXX */ - s->do_cmd = dt3k_ai_cmd; - s->do_cmdtest = dt3k_ai_cmdtest; - s->cancel = dt3k_ai_cancel; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 512; + s->do_cmd = dt3k_ai_cmd; + s->do_cmdtest = dt3k_ai_cmdtest; + s->cancel = dt3k_ai_cancel; + } s = &dev->subdevices[1]; /* ao subsystem */ @@ -797,8 +760,6 @@ static int dt3000_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_PROC; #endif - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } @@ -828,7 +789,7 @@ static int dt3000_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = { +static const struct pci_device_id dt3000_pci_table[] = { { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 }, { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 }, { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 }, diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 6c60949d919..b3aeb6fb2ad 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -39,10 +39,8 @@ for my needs. */ #include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> #include <linux/module.h> +#include <linux/errno.h> #include <linux/uaccess.h> #include <linux/usb.h> @@ -86,13 +84,9 @@ for my needs. #define F020_MASK_DACxCN_DACxEN 0x80 enum { - /* A/D D/A DI DO CT */ - DT9812_DEVID_DT9812_10, /* 8 2 8 8 1 +/- 10V */ - DT9812_DEVID_DT9812_2PT5, /* 8 2 8 8 1 0-2.44V */ -#if 0 - DT9812_DEVID_DT9813, /* 16 2 4 4 1 +/- 10V */ - DT9812_DEVID_DT9814 /* 24 2 0 0 1 +/- 10V */ -#endif + /* A/D D/A DI DO CT */ + DT9812_DEVID_DT9812_10, /* 8 2 8 8 1 +/- 10V */ + DT9812_DEVID_DT9812_2PT5, /* 8 2 8 8 1 0-2.44V */ }; enum dt9812_gain { @@ -188,8 +182,8 @@ enum { }; struct dt9812_flash_data { - u16 numbytes; - u16 address; + __le16 numbytes; + __le16 address; }; #define DT9812_MAX_NUM_MULTI_BYTE_RDS \ @@ -230,7 +224,7 @@ struct dt9812_rmw_multi { }; struct dt9812_usb_cmd { - u32 cmd; + __le32 cmd; union { struct dt9812_flash_data flash_data_info; struct dt9812_read_multi read_multi_info; @@ -581,15 +575,8 @@ static int dt9812_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) dt9812_digital_out(dev, s->state); - } data[1] = s->state; @@ -707,8 +694,9 @@ static int dt9812_reset_device(struct comedi_device *dev) u32 serial; u16 vendor; u16 product; - u16 tmp16; u8 tmp8; + __le16 tmp16; + __le32 tmp32; int ret; int i; @@ -731,19 +719,19 @@ static int dt9812_reset_device(struct comedi_device *dev) } } - ret = dt9812_read_info(dev, 1, &vendor, sizeof(vendor)); + ret = dt9812_read_info(dev, 1, &tmp16, sizeof(tmp16)); if (ret) { dev_err(dev->class_dev, "failed to read vendor id\n"); return ret; } - vendor = le16_to_cpu(vendor); + vendor = le16_to_cpu(tmp16); - ret = dt9812_read_info(dev, 3, &product, sizeof(product)); + ret = dt9812_read_info(dev, 3, &tmp16, sizeof(tmp16)); if (ret) { dev_err(dev->class_dev, "failed to read product id\n"); return ret; } - product = le16_to_cpu(product); + product = le16_to_cpu(tmp16); ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16)); if (ret) { @@ -752,12 +740,12 @@ static int dt9812_reset_device(struct comedi_device *dev) } devpriv->device = le16_to_cpu(tmp16); - ret = dt9812_read_info(dev, 7, &serial, sizeof(serial)); + ret = dt9812_read_info(dev, 7, &tmp32, sizeof(tmp32)); if (ret) { dev_err(dev->class_dev, "failed to read serial number\n"); return ret; } - serial = le32_to_cpu(serial); + serial = le32_to_cpu(tmp32); /* let the user know what node this device is now attached to */ dev_info(dev->class_dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n", @@ -781,10 +769,9 @@ static int dt9812_auto_attach(struct comedi_device *dev, bool is_unipolar; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; sema_init(&devpriv->sem, 1); usb_set_intfdata(intf, devpriv); diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index e14dd3ae9ec..e5593f8c740 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -33,6 +33,8 @@ their cards in their manuals. */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/pci.h> #include <linux/mutex.h> @@ -40,11 +42,12 @@ #define READ_TIMEOUT 50 -static const struct comedi_lrange range_pci1050_ai = { 3, { - BIP_RANGE(10), - BIP_RANGE(5), - UNI_RANGE(10) - } +static const struct comedi_lrange range_pci1050_ai = { + 3, { + BIP_RANGE(10), + BIP_RANGE(5), + UNI_RANGE(10) + } }; static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 }; @@ -54,18 +57,27 @@ struct dyna_pci10xx_private { unsigned long BADR3; }; -/******************************************************************************/ -/************************** READ WRITE FUNCTIONS ******************************/ -/******************************************************************************/ +static int dyna_pci10xx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw_p(dev->iobase); + if (status & (1 << 15)) + return 0; + return -EBUSY; +} -/* analog input callback */ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; - int n, counter; + int n; u16 d = 0; + int ret = 0; unsigned int chan, range; /* get the channel number and range */ @@ -79,19 +91,13 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, smp_mb(); outw_p(0x0000 + range + chan, dev->iobase + 2); udelay(10); + + ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0); + if (ret) + break; + /* read data */ - for (counter = 0; counter < READ_TIMEOUT; counter++) { - d = inw_p(dev->iobase); - - /* check if read is successful if the EOC bit is set */ - if (d & (1 << 15)) - goto conv_finish; - } - data[n] = 0; - printk(KERN_DEBUG "comedi: dyna_pci10xx: " - "timeout reading analog input\n"); - continue; -conv_finish: + d = inw_p(dev->iobase); /* mask the first 4 bits - EOC bits */ d &= 0x0FFF; data[n] = d; @@ -99,7 +105,7 @@ conv_finish: mutex_unlock(&devpriv->mutex); /* return the number of samples read/written */ - return n; + return ret ? ret : n; } /* analog output callback */ @@ -145,33 +151,23 @@ static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev, return insn->n; } -/* digital output bit interface */ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. - * s->state contains the previous write data - */ mutex_lock(&devpriv->mutex); - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { smp_mb(); outw_p(s->state, devpriv->BADR3); udelay(10); } - /* - * On return, data[1] contains the value of the digital - * input and output lines. We just return the software copy of the - * output values if it was a purely digital output subdevice. - */ data[1] = s->state; mutex_unlock(&devpriv->mutex); + return insn->n; } @@ -183,10 +179,9 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -241,8 +236,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, s->state = 0; s->insn_bits = dyna_pci10xx_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } @@ -269,7 +262,7 @@ static int dyna_pci10xx_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = { +static const struct pci_device_id dyna_pci10xx_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_PLX, 0x1050) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index ff6f0bd7c86..4e410f3b0e2 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -1,111 +1,128 @@ /* - comedi/drivers/fl512.c - Anders Gnistrup <ex18@kalman.iau.dtu.dk> -*/ + * fl512.c + * Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: fl512 -Description: unknown -Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> -Devices: [unknown] FL512 (fl512) -Status: unknown - -Digital I/O is not supported. - -Configuration options: - [0] - I/O port base address -*/ - -#define DEBUG 0 + * Driver: fl512 + * Description: unknown + * Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * Devices: [unknown] FL512 (fl512) + * Status: unknown + * + * Digital I/O is not supported. + * + * Configuration options: + * [0] - I/O port base address + */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> -#define FL512_SIZE 16 /* the size of the used memory */ -struct fl512_private { +/* + * Register I/O map + */ +#define FL512_AI_LSB_REG 0x02 +#define FL512_AI_MSB_REG 0x03 +#define FL512_AI_MUX_REG 0x02 +#define FL512_AI_START_CONV_REG 0x03 +#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2)) - short ao_readback[2]; +struct fl512_private { + unsigned short ao_readback[2]; }; -static const struct comedi_lrange range_fl512 = { 4, { - BIP_RANGE(0.5), - BIP_RANGE(1), - BIP_RANGE(5), - BIP_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(5), - UNI_RANGE(10), - } +static const struct comedi_lrange range_fl512 = { + 4, { + BIP_RANGE(0.5), + BIP_RANGE(1), + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(5), + UNI_RANGE(10) + } }; -/* - * fl512_ai_insn : this is the analog input function - */ -static int fl512_ai_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - unsigned int lo_byte, hi_byte; - char chan = CR_CHAN(insn->chanspec); - unsigned long iobase = dev->iobase; - - for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */ - /* XXX probably can move next step out of for() loop -- will - * make AI a little bit faster. */ - outb(chan, iobase + 2); /* select chan */ - outb(0, iobase + 3); /* start conversion */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + FL512_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + outb(0, dev->iobase + FL512_AI_START_CONV_REG); + /* XXX should test "done" flag instead of delay */ - udelay(30); /* sleep 30 usec */ - lo_byte = inb(iobase + 2); /* low 8 byte */ - hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */ - data[n] = lo_byte + (hi_byte << 8); + udelay(30); + + val = inb(dev->iobase + FL512_AI_LSB_REG); + val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8); + val &= s->maxdata; + + data[i] = val; } - return n; + + return insn->n; } -/* - * fl512_ao_insn : used to write to a DA port n times - */ -static int fl512_ao_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); /* get chan to write */ - unsigned long iobase = dev->iobase; /* get base address */ - - for (n = 0; n < insn->n; n++) { /* write n data set */ - /* write low byte */ - outb(data[n] & 0x0ff, iobase + 4 + 2 * chan); - /* write high byte */ - outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan); - inb(iobase + 4 + 2 * chan); /* trig */ - - devpriv->ao_readback[chan] = data[n]; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* write LSB, MSB then trigger conversion */ + outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan)); + outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan)); + inb(dev->iobase + FL512_AO_TRIG_REG(chan)); } - return n; + devpriv->ao_readback[chan] = val; + + return insn->n; } -/* - * fl512_ao_insn_readback : used to read previous values written to - * DA port - */ -static int fl512_ao_insn_readback(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int fl512_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - return n; + return insn->n; } static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -114,55 +131,38 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], FL512_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; - /* - * this if the definitions of the supdevices, 2 have been defined - */ - /* Analog indput */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* define subdevice as Analog In */ - s->type = COMEDI_SUBD_AI; - /* you can read it from userspace */ - s->subdev_flags = SDF_READABLE | SDF_GROUND; - /* Number of Analog input channels */ - s->n_chan = 16; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when read AD */ - s->insn_read = fl512_ai_insn; - - /* Analog output */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_read = fl512_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* define subdevice as Analog OUT */ - s->type = COMEDI_SUBD_AO; - /* you can write it from userspace */ - s->subdev_flags = SDF_WRITABLE; - /* Number of Analog output channels */ - s->n_chan = 2; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when write DA */ - s->insn_write = fl512_ao_insn; - /* function to call when reading DA */ - s->insn_read = fl512_ao_insn_readback; - - return 1; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_write = fl512_ao_insn_write; + s->insn_read = fl512_ao_insn_read; + + return 0; } static struct comedi_driver fl512_driver = { diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 2fceff93867..22333c1ad88 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -1,24 +1,24 @@ /* - comedi/drivers/gsc_hpdi.c - This is a driver for the General Standards Corporation High - Speed Parallel Digital Interface rs485 boards. - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2003 Coherent Imaging Systems - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * gsc_hpdi.c + * Comedi driver the General Standards Corporation + * High Speed Parallel Digital Interface rs485 boards. + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2003 Coherent Imaging Systems + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* * Driver: gsc_hpdi @@ -40,8 +40,7 @@ * support could be added to this driver. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -51,158 +50,105 @@ #include "plx9080.h" #include "comedi_fc.h" -static void abort_dma(struct comedi_device *dev, unsigned int channel); -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t handle_interrupt(int irq, void *d); -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data); - -#undef HPDI_DEBUG /* disable debugging messages */ -/* #define HPDI_DEBUG enable debugging code */ - -#ifdef HPDI_DEBUG -#define DEBUG_PRINT(format, args...) pr_debug(format , ## args) -#else -#define DEBUG_PRINT(format, args...) no_printk(pr_fmt(format), ## args) -#endif - -#define TIMER_BASE 50 /* 20MHz master clock */ -#define DMA_BUFFER_SIZE 0x10000 -#define NUM_DMA_BUFFERS 4 -#define NUM_DMA_DESCRIPTORS 256 - -enum hpdi_registers { - FIRMWARE_REV_REG = 0x0, - BOARD_CONTROL_REG = 0x4, - BOARD_STATUS_REG = 0x8, - TX_PROG_ALMOST_REG = 0xc, - RX_PROG_ALMOST_REG = 0x10, - FEATURES_REG = 0x14, - FIFO_REG = 0x18, - TX_STATUS_COUNT_REG = 0x1c, - TX_LINE_VALID_COUNT_REG = 0x20, - TX_LINE_INVALID_COUNT_REG = 0x24, - RX_STATUS_COUNT_REG = 0x28, - RX_LINE_COUNT_REG = 0x2c, - INTERRUPT_CONTROL_REG = 0x30, - INTERRUPT_STATUS_REG = 0x34, - TX_CLOCK_DIVIDER_REG = 0x38, - TX_FIFO_SIZE_REG = 0x40, - RX_FIFO_SIZE_REG = 0x44, - TX_FIFO_WORDS_REG = 0x48, - RX_FIFO_WORDS_REG = 0x4c, - INTERRUPT_EDGE_LEVEL_REG = 0x50, - INTERRUPT_POLARITY_REG = 0x54, -}; - -/* bit definitions */ - -enum firmware_revision_bits { - FEATURES_REG_PRESENT_BIT = 0x8000, -}; - -enum board_control_bits { - BOARD_RESET_BIT = 0x1, /* wait 10usec before accessing fifos */ - TX_FIFO_RESET_BIT = 0x2, - RX_FIFO_RESET_BIT = 0x4, - TX_ENABLE_BIT = 0x10, - RX_ENABLE_BIT = 0x20, - DEMAND_DMA_DIRECTION_TX_BIT = 0x40, - /* for ch 0, ch 1 can only transmit (when present) */ - LINE_VALID_ON_STATUS_VALID_BIT = 0x80, - START_TX_BIT = 0x10, - CABLE_THROTTLE_ENABLE_BIT = 0x20, - TEST_MODE_ENABLE_BIT = 0x80000000, -}; - -enum board_status_bits { - COMMAND_LINE_STATUS_MASK = 0x7f, - TX_IN_PROGRESS_BIT = 0x80, - TX_NOT_EMPTY_BIT = 0x100, - TX_NOT_ALMOST_EMPTY_BIT = 0x200, - TX_NOT_ALMOST_FULL_BIT = 0x400, - TX_NOT_FULL_BIT = 0x800, - RX_NOT_EMPTY_BIT = 0x1000, - RX_NOT_ALMOST_EMPTY_BIT = 0x2000, - RX_NOT_ALMOST_FULL_BIT = 0x4000, - RX_NOT_FULL_BIT = 0x8000, - BOARD_JUMPER0_INSTALLED_BIT = 0x10000, - BOARD_JUMPER1_INSTALLED_BIT = 0x20000, - TX_OVERRUN_BIT = 0x200000, - RX_UNDERRUN_BIT = 0x400000, - RX_OVERRUN_BIT = 0x800000, -}; - -static uint32_t almost_full_bits(unsigned int num_words) -{ - /* XXX need to add or subtract one? */ - return (num_words << 16) & 0xff0000; -} - -static uint32_t almost_empty_bits(unsigned int num_words) -{ - return num_words & 0xffff; -} - -enum features_bits { - FIFO_SIZE_PRESENT_BIT = 0x1, - FIFO_WORDS_PRESENT_BIT = 0x2, - LEVEL_EDGE_INTERRUPTS_PRESENT_BIT = 0x4, - GPIO_SUPPORTED_BIT = 0x8, - PLX_DMA_CH1_SUPPORTED_BIT = 0x10, - OVERRUN_UNDERRUN_SUPPORTED_BIT = 0x20, -}; - -enum interrupt_sources { - FRAME_VALID_START_INTR = 0, - FRAME_VALID_END_INTR = 1, - TX_FIFO_EMPTY_INTR = 8, - TX_FIFO_ALMOST_EMPTY_INTR = 9, - TX_FIFO_ALMOST_FULL_INTR = 10, - TX_FIFO_FULL_INTR = 11, - RX_EMPTY_INTR = 12, - RX_ALMOST_EMPTY_INTR = 13, - RX_ALMOST_FULL_INTR = 14, - RX_FULL_INTR = 15, -}; - -static uint32_t intr_bit(int interrupt_source) -{ - return 0x1 << interrupt_source; -} - -static unsigned int fifo_size(uint32_t fifo_size_bits) -{ - return fifo_size_bits & 0xfffff; -} +/* + * PCI BAR2 Register map (devpriv->mmio) + */ +#define FIRMWARE_REV_REG 0x00 +#define FEATURES_REG_PRESENT_BIT (1 << 15) +#define BOARD_CONTROL_REG 0x04 +#define BOARD_RESET_BIT (1 << 0) +#define TX_FIFO_RESET_BIT (1 << 1) +#define RX_FIFO_RESET_BIT (1 << 2) +#define TX_ENABLE_BIT (1 << 4) +#define RX_ENABLE_BIT (1 << 5) +#define DEMAND_DMA_DIRECTION_TX_BIT (1 << 6) /* ch 0 only */ +#define LINE_VALID_ON_STATUS_VALID_BIT (1 << 7) +#define START_TX_BIT (1 << 8) +#define CABLE_THROTTLE_ENABLE_BIT (1 << 9) +#define TEST_MODE_ENABLE_BIT (1 << 31) +#define BOARD_STATUS_REG 0x08 +#define COMMAND_LINE_STATUS_MASK (0x7f << 0) +#define TX_IN_PROGRESS_BIT (1 << 7) +#define TX_NOT_EMPTY_BIT (1 << 8) +#define TX_NOT_ALMOST_EMPTY_BIT (1 << 9) +#define TX_NOT_ALMOST_FULL_BIT (1 << 10) +#define TX_NOT_FULL_BIT (1 << 11) +#define RX_NOT_EMPTY_BIT (1 << 12) +#define RX_NOT_ALMOST_EMPTY_BIT (1 << 13) +#define RX_NOT_ALMOST_FULL_BIT (1 << 14) +#define RX_NOT_FULL_BIT (1 << 15) +#define BOARD_JUMPER0_INSTALLED_BIT (1 << 16) +#define BOARD_JUMPER1_INSTALLED_BIT (1 << 17) +#define TX_OVERRUN_BIT (1 << 21) +#define RX_UNDERRUN_BIT (1 << 22) +#define RX_OVERRUN_BIT (1 << 23) +#define TX_PROG_ALMOST_REG 0x0c +#define RX_PROG_ALMOST_REG 0x10 +#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0) +#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16) +#define FEATURES_REG 0x14 +#define FIFO_SIZE_PRESENT_BIT (1 << 0) +#define FIFO_WORDS_PRESENT_BIT (1 << 1) +#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT (1 << 2) +#define GPIO_SUPPORTED_BIT (1 << 3) +#define PLX_DMA_CH1_SUPPORTED_BIT (1 << 4) +#define OVERRUN_UNDERRUN_SUPPORTED_BIT (1 << 5) +#define FIFO_REG 0x18 +#define TX_STATUS_COUNT_REG 0x1c +#define TX_LINE_VALID_COUNT_REG 0x20, +#define TX_LINE_INVALID_COUNT_REG 0x24 +#define RX_STATUS_COUNT_REG 0x28 +#define RX_LINE_COUNT_REG 0x2c +#define INTERRUPT_CONTROL_REG 0x30 +#define FRAME_VALID_START_INTR (1 << 0) +#define FRAME_VALID_END_INTR (1 << 1) +#define TX_FIFO_EMPTY_INTR (1 << 8) +#define TX_FIFO_ALMOST_EMPTY_INTR (1 << 9) +#define TX_FIFO_ALMOST_FULL_INTR (1 << 10) +#define TX_FIFO_FULL_INTR (1 << 11) +#define RX_EMPTY_INTR (1 << 12) +#define RX_ALMOST_EMPTY_INTR (1 << 13) +#define RX_ALMOST_FULL_INTR (1 << 14) +#define RX_FULL_INTR (1 << 15) +#define INTERRUPT_STATUS_REG 0x34 +#define TX_CLOCK_DIVIDER_REG 0x38 +#define TX_FIFO_SIZE_REG 0x40 +#define RX_FIFO_SIZE_REG 0x44 +#define FIFO_SIZE_MASK (0xfffff << 0) +#define TX_FIFO_WORDS_REG 0x48 +#define RX_FIFO_WORDS_REG 0x4c +#define INTERRUPT_EDGE_LEVEL_REG 0x50 +#define INTERRUPT_POLARITY_REG 0x54 + +#define TIMER_BASE 50 /* 20MHz master clock */ +#define DMA_BUFFER_SIZE 0x10000 +#define NUM_DMA_BUFFERS 4 +#define NUM_DMA_DESCRIPTORS 256 struct hpdi_board { - const char *name; /* board name */ - int device_id; /* pci device id */ - int subdevice_id; /* pci subdevice id */ + const char *name; + int device_id; + int subdevice_id; }; static const struct hpdi_board hpdi_boards[] = { { - .name = "pci-hpdi32", - .device_id = PCI_DEVICE_ID_PLX_9080, - .subdevice_id = 0x2400, + .name = "pci-hpdi32", + .device_id = PCI_DEVICE_ID_PLX_9080, + .subdevice_id = 0x2400, }, #if 0 { - .name = "pxi-hpdi32", - .device_id = 0x9656, - .subdevice_id = 0x2705, + .name = "pxi-hpdi32", + .device_id = 0x9656, + .subdevice_id = 0x2705, }, #endif }; struct hpdi_private { - /* base addresses (ioremapped) */ - void __iomem *plx9080_iobase; - void __iomem *hpdi_iobase; + void __iomem *plx9080_mmio; + void __iomem *mmio; uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ /* physical addresses of dma buffers */ dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; @@ -215,394 +161,232 @@ struct hpdi_private { /* pointer to start of buffers indexed by descriptor */ uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* index of the dma descriptor that is currently being used */ - volatile unsigned int dma_desc_index; + unsigned int dma_desc_index; unsigned int tx_fifo_size; unsigned int rx_fifo_size; - volatile unsigned long dio_count; - /* software copies of values written to hpdi registers */ - volatile uint32_t bits[24]; + unsigned long dio_count; /* number of bytes at which to generate COMEDI_CB_BLOCK events */ - volatile unsigned int block_size; - unsigned dio_config_output:1; + unsigned int block_size; }; -static int dio_config_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) { struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int idx; + unsigned int start; + unsigned int desc; + unsigned int size; + unsigned int next; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - devpriv->dio_config_output = 1; - return insn->n; - break; - case INSN_CONFIG_DIO_INPUT: - devpriv->dio_config_output = 0; - return insn->n; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - devpriv->dio_config_output ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - case INSN_CONFIG_BLOCK_SIZE: - return dio_config_block_size(dev, data); - break; - default: - break; - } - - return -EINVAL; -} - -static void disable_plx_interrupts(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; + if (channel) + next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG); + else + next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + + idx = devpriv->dma_desc_index; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + /* loop until we have read all the full buffers */ + for (desc = 0; (next < start || next >= start + devpriv->block_size) && + desc < devpriv->num_dma_descriptors; desc++) { + /* transfer data from dma buffer to comedi buffer */ + size = devpriv->block_size / sizeof(uint32_t); + if (cmd->stop_src == TRIG_COUNT) { + if (size > devpriv->dio_count) + size = devpriv->dio_count; + devpriv->dio_count -= size; + } + cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx], + size * sizeof(uint32_t)); + idx++; + idx %= devpriv->num_dma_descriptors; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); - writel(0, devpriv->plx9080_iobase + PLX_INTRCS_REG); + devpriv->dma_desc_index = idx; + } + /* XXX check for buffer overrun somehow */ } -/* initialize plx9080 chip */ -static void init_plx9080(struct comedi_device *dev) +static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) { + struct comedi_device *dev = d; struct hpdi_private *devpriv = dev->private; - uint32_t bits; - void __iomem *plx_iobase = devpriv->plx9080_iobase; - - /* plx9080 dump */ - DEBUG_PRINT(" plx interrupt status 0x%x\n", - readl(plx_iobase + PLX_INTRCS_REG)); - DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG)); - DEBUG_PRINT(" plx control reg 0x%x\n", - readl(devpriv->plx9080_iobase + PLX_CONTROL_REG)); - - DEBUG_PRINT(" plx revision 0x%x\n", - readl(plx_iobase + PLX_REVISION_REG)); - DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n", - readl(plx_iobase + PLX_DMA0_MODE_REG)); - DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n", - readl(plx_iobase + PLX_DMA1_MODE_REG)); - DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n", - readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n", - readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n", - readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG)); - DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n", - readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG)); - DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n", - readb(plx_iobase + PLX_DMA0_CS_REG)); - DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n", - readl(plx_iobase + PLX_DMA0_THRESHOLD_REG)); - DEBUG_PRINT(" plx bigend 0x%x\n", readl(plx_iobase + PLX_BIGEND_REG)); -#ifdef __BIG_ENDIAN - bits = BIGEND_DMA0 | BIGEND_DMA1; -#else - bits = 0; -#endif - writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG); - - disable_plx_interrupts(dev); + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + uint32_t hpdi_intr_status, hpdi_board_status; + uint32_t plx_status; + uint32_t plx_bits; + uint8_t dma0_status, dma1_status; + unsigned long flags; - abort_dma(dev, 0); - abort_dma(dev, 1); + if (!dev->attached) + return IRQ_NONE; - /* configure dma0 mode */ - bits = 0; - /* enable ready input */ - bits |= PLX_DMA_EN_READYIN_BIT; - /* enable dma chaining */ - bits |= PLX_EN_CHAIN_BIT; - /* enable interrupt on dma done - * (probably don't need this, since chain never finishes) */ - bits |= PLX_EN_DMA_DONE_INTR_BIT; - /* don't increment local address during transfers - * (we are transferring from a fixed fifo register) */ - bits |= PLX_LOCAL_ADDR_CONST_BIT; - /* route dma interrupt to pci bus */ - bits |= PLX_DMA_INTR_PCI_BIT; - /* enable demand mode */ - bits |= PLX_DEMAND_MODE_BIT; - /* enable local burst mode */ - bits |= PLX_DMA_LOCAL_BURST_EN_BIT; - bits |= PLX_LOCAL_BUS_32_WIDE_BITS; - writel(bits, plx_iobase + PLX_DMA0_MODE_REG); -} + plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG); + if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) + return IRQ_NONE; -/* Allocate and initialize the subdevice structures. - */ -static int setup_subdevices(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int ret; + hpdi_intr_status = readl(devpriv->mmio + INTERRUPT_STATUS_REG); + hpdi_board_status = readl(devpriv->mmio + BOARD_STATUS_REG); - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; + if (hpdi_intr_status) + writel(hpdi_intr_status, devpriv->mmio + INTERRUPT_STATUS_REG); - s = &dev->subdevices[0]; - /* analog input subdevice */ - dev->read_subdev = s; -/* dev->write_subdev = s; */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | SDF_CMD_READ; - s->n_chan = 32; - s->len_chanlist = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = dio_config_insn; - s->do_cmd = hpdi_cmd; - s->do_cmdtest = hpdi_cmd_test; - s->cancel = hpdi_cancel; + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ + writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); - return 0; -} + if (dma0_status & PLX_DMA_EN_BIT) + gsc_hpdi_drain_dma(dev, 0); + } + spin_unlock_irqrestore(&dev->spinlock, flags); -static int init_hpdi(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; - uint32_t plx_intcsr_bits; + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ + writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + } + spin_unlock_irqrestore(&dev->spinlock, flags); - writel(BOARD_RESET_BIT, devpriv->hpdi_iobase + BOARD_CONTROL_REG); - udelay(10); + /* clear possible plx9080 interrupt sources */ + if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ + plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + } - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + RX_PROG_ALMOST_REG); - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + TX_PROG_ALMOST_REG); + if (hpdi_board_status & RX_OVERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo overrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } - devpriv->tx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - TX_FIFO_SIZE_REG)); - devpriv->rx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - RX_FIFO_SIZE_REG)); + if (hpdi_board_status & RX_UNDERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo underrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); + if (devpriv->dio_count == 0) + async->events |= COMEDI_CB_EOA; - /* enable interrupts */ - plx_intcsr_bits = - ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | - ICS_DMA0_E; - writel(plx_intcsr_bits, devpriv->plx9080_iobase + PLX_INTRCS_REG); + cfc_handle_events(dev, s); - return 0; + return IRQ_HANDLED; } -/* setup dma descriptors so a link completes every 'transfer_size' bytes */ -static int setup_dma_descriptors(struct comedi_device *dev, - unsigned int transfer_size) +static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel) { struct hpdi_private *devpriv = dev->private; - unsigned int buffer_index, buffer_offset; - uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI; - unsigned int i; - - if (transfer_size > DMA_BUFFER_SIZE) - transfer_size = DMA_BUFFER_SIZE; - transfer_size -= transfer_size % sizeof(uint32_t); - if (transfer_size == 0) - return -1; - - DEBUG_PRINT(" transfer_size %i\n", transfer_size); - DEBUG_PRINT(" descriptors at 0x%lx\n", - (unsigned long)devpriv->dma_desc_phys_addr); - - buffer_offset = 0; - buffer_index = 0; - for (i = 0; i < NUM_DMA_DESCRIPTORS && - buffer_index < NUM_DMA_BUFFERS; i++) { - devpriv->dma_desc[i].pci_start_addr = - cpu_to_le32(devpriv->dio_buffer_phys_addr[buffer_index] + - buffer_offset); - devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); - devpriv->dma_desc[i].transfer_size = - cpu_to_le32(transfer_size); - devpriv->dma_desc[i].next = - cpu_to_le32((devpriv->dma_desc_phys_addr + (i + - 1) * - sizeof(devpriv->dma_desc[0])) | next_bits); - - devpriv->desc_dio_buffer[i] = - devpriv->dio_buffer[buffer_index] + - (buffer_offset / sizeof(uint32_t)); - - buffer_offset += transfer_size; - if (transfer_size + buffer_offset > DMA_BUFFER_SIZE) { - buffer_offset = 0; - buffer_index++; - } + unsigned long flags; - DEBUG_PRINT(" desc %i\n", i); - DEBUG_PRINT(" start addr virt 0x%p, phys 0x%lx\n", - devpriv->desc_dio_buffer[i], - (unsigned long)devpriv->dma_desc[i]. - pci_start_addr); - DEBUG_PRINT(" next 0x%lx\n", - (unsigned long)devpriv->dma_desc[i].next); - } - devpriv->num_dma_descriptors = i; - /* fix last descriptor to point back to first */ - devpriv->dma_desc[i - 1].next = - cpu_to_le32(devpriv->dma_desc_phys_addr | next_bits); - DEBUG_PRINT(" desc %i next fixup 0x%lx\n", i - 1, - (unsigned long)devpriv->dma_desc[i - 1].next); + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); - devpriv->block_size = transfer_size; + plx9080_abort_dma(devpriv->plx9080_mmio, channel); - return transfer_size; + spin_unlock_irqrestore(&dev->spinlock, flags); } -static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev) +static int gsc_hpdi_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned int i; + struct hpdi_private *devpriv = dev->private; - for (i = 0; i < ARRAY_SIZE(hpdi_boards); i++) - if (pcidev->device == hpdi_boards[i].device_id && - pcidev->subsystem_device == hpdi_boards[i].subdevice_id) - return &hpdi_boards[i]; - return NULL; + writel(0, devpriv->mmio + BOARD_CONTROL_REG); + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); + + gsc_hpdi_abort_dma(dev, 0); + + return 0; } -static int hpdi_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int gsc_hpdi_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct hpdi_board *thisboard; - struct hpdi_private *devpriv; - int i; - int retval; + struct hpdi_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned long flags; + uint32_t bits; - thisboard = hpdi_find_board(pcidev); - if (!thisboard) { - dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n", - pci_name(pcidev)); + if (s->io_bits) return -EINVAL; - } - dev->board_ptr = thisboard; - dev->board_name = thisboard->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; + writel(RX_FIFO_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); - retval = comedi_pci_enable(dev); - if (retval) - return retval; - pci_set_master(pcidev); - - devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0); - devpriv->hpdi_iobase = pci_ioremap_bar(pcidev, 2); - if (!devpriv->plx9080_iobase || !devpriv->hpdi_iobase) { - dev_warn(dev->class_dev, "failed to remap io memory\n"); - return -ENOMEM; - } - - DEBUG_PRINT(" plx9080 remapped to 0x%p\n", devpriv->plx9080_iobase); - DEBUG_PRINT(" hpdi remapped to 0x%p\n", devpriv->hpdi_iobase); + gsc_hpdi_abort_dma(dev, 0); - init_plx9080(dev); + devpriv->dma_desc_index = 0; - /* get irq */ - if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, - dev->board_name, dev)) { - dev_warn(dev->class_dev, - "unable to allocate irq %u\n", pcidev->irq); - return -EINVAL; - } - dev->irq = pcidev->irq; + /* + * These register are supposedly unused during chained dma, + * but I have found that left over values from last operation + * occasionally cause problems with transfer of first dma + * block. Initializing them to zero seems to fix the problem. + */ + writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG); + + /* give location of first dma descriptor */ + bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | + PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; + writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG); + + /* enable dma transfer */ + spin_lock_irqsave(&dev->spinlock, flags); + writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); - dev_dbg(dev->class_dev, " irq %u\n", dev->irq); + if (cmd->stop_src == TRIG_COUNT) + devpriv->dio_count = cmd->stop_arg; + else + devpriv->dio_count = 1; - /* allocate pci dma buffers */ - for (i = 0; i < NUM_DMA_BUFFERS; i++) { - devpriv->dio_buffer[i] = - pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE, - &devpriv->dio_buffer_phys_addr[i]); - DEBUG_PRINT("dio_buffer at virt 0x%p, phys 0x%lx\n", - devpriv->dio_buffer[i], - (unsigned long)devpriv->dio_buffer_phys_addr[i]); - } - /* allocate dma descriptors */ - devpriv->dma_desc = pci_alloc_consistent(pcidev, - sizeof(struct plx_dma_desc) * - NUM_DMA_DESCRIPTORS, - &devpriv->dma_desc_phys_addr); - if (devpriv->dma_desc_phys_addr & 0xf) { - dev_warn(dev->class_dev, - " dma descriptors not quad-word aligned (bug)\n"); - return -EIO; - } + /* clear over/under run status flags */ + writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, + devpriv->mmio + BOARD_STATUS_REG); - retval = setup_dma_descriptors(dev, 0x1000); - if (retval < 0) - return retval; + /* enable interrupts */ + writel(RX_FULL_INTR, devpriv->mmio + INTERRUPT_CONTROL_REG); - retval = setup_subdevices(dev); - if (retval < 0) - return retval; + writel(RX_ENABLE_BIT, devpriv->mmio + BOARD_CONTROL_REG); - return init_hpdi(dev); + return 0; } -static void hpdi_detach(struct comedi_device *dev) +static int gsc_hpdi_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct hpdi_private *devpriv = dev->private; - unsigned int i; + int i; - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv) { - if (devpriv->plx9080_iobase) { - disable_plx_interrupts(dev); - iounmap(devpriv->plx9080_iobase); - } - if (devpriv->hpdi_iobase) - iounmap(devpriv->hpdi_iobase); - /* free pci dma buffers */ - for (i = 0; i < NUM_DMA_BUFFERS; i++) { - if (devpriv->dio_buffer[i]) - pci_free_consistent(pcidev, - DMA_BUFFER_SIZE, - devpriv->dio_buffer[i], - devpriv-> - dio_buffer_phys_addr[i]); + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != i) { + dev_dbg(dev->class_dev, + "chanlist must be ch 0 to 31 in order\n"); + return -EINVAL; } - /* free dma descriptors */ - if (devpriv->dma_desc) - pci_free_consistent(pcidev, - sizeof(struct plx_dma_desc) * - NUM_DMA_DESCRIPTORS, - devpriv->dma_desc, - devpriv->dma_desc_phys_addr); } - comedi_pci_disable(dev); -} - -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data) -{ - unsigned int requested_block_size; - int retval; - - requested_block_size = data[1]; - - retval = setup_dma_descriptors(dev, requested_block_size); - if (retval < 0) - return retval; - - data[1] = retval; - return 2; + return 0; } -static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int gsc_hpdi_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; - int i; + + if (s->io_bits) + return -EINVAL; /* Step 1 : check if triggers are trivially valid */ @@ -626,22 +410,18 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 3: check if arguments are trivially valid */ - if (!cmd->chanlist_len) { + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + + if (!cmd->chanlist_len || !cmd->chanlist) { cmd->chanlist_len = 32; err |= -EINVAL; } err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - switch (cmd->stop_src) { - case TRIG_COUNT: + if (cmd->stop_src == TRIG_COUNT) err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); - break; - case TRIG_NONE: + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } if (err) return 3; @@ -651,276 +431,298 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - if (!cmd->chanlist) - return 0; - - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - /* XXX could support 8 or 16 channels */ - comedi_error(dev, - "chanlist must be ch 0 to 31 in order"); - err++; - break; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= gsc_hpdi_check_chanlist(dev, s, cmd); if (err) return 5; return 0; + } -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +/* setup dma descriptors so a link completes every 'len' bytes */ +static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, + unsigned int len) { struct hpdi_private *devpriv = dev->private; + dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; + uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | + PLX_XFER_LOCAL_TO_PCI; + unsigned int offset = 0; + unsigned int idx = 0; + unsigned int i; - if (devpriv->dio_config_output) + if (len > DMA_BUFFER_SIZE) + len = DMA_BUFFER_SIZE; + len -= len % sizeof(uint32_t); + if (len == 0) return -EINVAL; - else - return di_cmd_test(dev, s, cmd); -} -static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits, - unsigned int offset) -{ - struct hpdi_private *devpriv = dev->private; + for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) { + devpriv->dma_desc[i].pci_start_addr = + cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset); + devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); + devpriv->dma_desc[i].transfer_size = cpu_to_le32(len); + devpriv->dma_desc[i].next = cpu_to_le32((phys_addr + + (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); + + devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + + (offset / sizeof(uint32_t)); + + offset += len; + if (len + offset > DMA_BUFFER_SIZE) { + offset = 0; + idx++; + } + } + devpriv->num_dma_descriptors = i; + /* fix last descriptor to point back to first */ + devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits); - writel(bits | devpriv->bits[offset / sizeof(uint32_t)], - devpriv->hpdi_iobase + offset); + devpriv->block_size = len; + + return len; } -static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int gsc_hpdi_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct hpdi_private *devpriv = dev->private; - uint32_t bits; - unsigned long flags; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; + int ret; - hpdi_writel(dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG); + switch (data[0]) { + case INSN_CONFIG_BLOCK_SIZE: + ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]); + if (ret) + return ret; - DEBUG_PRINT("hpdi: in di_cmd\n"); + data[1] = ret; + break; + default: + ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff); + if (ret) + return ret; + break; + } - abort_dma(dev, 0); + return insn->n; +} - devpriv->dma_desc_index = 0; +static int gsc_hpdi_init(struct comedi_device *dev) +{ + struct hpdi_private *devpriv = dev->private; + uint32_t plx_intcsr_bits; - /* These register are supposedly unused during chained dma, - * but I have found that left over values from last operation - * occasionally cause problems with transfer of first dma - * block. Initializing them to zero seems to fix the problem. */ - writel(0, devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); - /* give location of first dma descriptor */ - bits = - devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; - writel(bits, devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); + /* wait 10usec after reset before accessing fifos */ + writel(BOARD_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + udelay(10); - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - /* enable dma transfer */ - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + RX_PROG_ALMOST_REG); + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + TX_PROG_ALMOST_REG); - if (cmd->stop_src == TRIG_COUNT) - devpriv->dio_count = cmd->stop_arg; - else - devpriv->dio_count = 1; + devpriv->tx_fifo_size = readl(devpriv->mmio + TX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + devpriv->rx_fifo_size = readl(devpriv->mmio + RX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; - /* clear over/under run status flags */ - writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, - devpriv->hpdi_iobase + BOARD_STATUS_REG); - /* enable interrupts */ - writel(intr_bit(RX_FULL_INTR), - devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); - DEBUG_PRINT("hpdi: starting rx\n"); - hpdi_writel(dev, RX_ENABLE_BIT, BOARD_CONTROL_REG); + /* enable interrupts */ + plx_intcsr_bits = + ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | + ICS_DMA0_E; + writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG); return 0; } -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static void gsc_hpdi_init_plx9080(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; + uint32_t bits; + void __iomem *plx_iobase = devpriv->plx9080_mmio; - if (devpriv->dio_config_output) - return -EINVAL; - else - return di_cmd(dev, s); -} +#ifdef __BIG_ENDIAN + bits = BIGEND_DMA0 | BIGEND_DMA1; +#else + bits = 0; +#endif + writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG); -static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - struct comedi_async *async = dev->read_subdev->async; - uint32_t next_transfer_addr; - int j; - int num_samples = 0; - void __iomem *pci_addr_reg; + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); - if (channel) - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; - else - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - - /* loop until we have read all the full buffers */ - j = 0; - for (next_transfer_addr = readl(pci_addr_reg); - (next_transfer_addr < - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) - || next_transfer_addr >= - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) + devpriv->block_size) - && j < devpriv->num_dma_descriptors; j++) { - /* transfer data from dma buffer to comedi buffer */ - num_samples = devpriv->block_size / sizeof(uint32_t); - if (async->cmd.stop_src == TRIG_COUNT) { - if (num_samples > devpriv->dio_count) - num_samples = devpriv->dio_count; - devpriv->dio_count -= num_samples; - } - cfc_write_array_to_buffer(dev->read_subdev, - devpriv->desc_dio_buffer[devpriv-> - dma_desc_index], - num_samples * sizeof(uint32_t)); - devpriv->dma_desc_index++; - devpriv->dma_desc_index %= devpriv->num_dma_descriptors; - - DEBUG_PRINT("next desc addr 0x%lx\n", (unsigned long) - devpriv->dma_desc[devpriv->dma_desc_index]. - next); - DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr); - } - /* XXX check for buffer overrun somehow */ + gsc_hpdi_abort_dma(dev, 0); + gsc_hpdi_abort_dma(dev, 1); + + /* configure dma0 mode */ + bits = 0; + /* enable ready input */ + bits |= PLX_DMA_EN_READYIN_BIT; + /* enable dma chaining */ + bits |= PLX_EN_CHAIN_BIT; + /* enable interrupt on dma done + * (probably don't need this, since chain never finishes) */ + bits |= PLX_EN_DMA_DONE_INTR_BIT; + /* don't increment local address during transfers + * (we are transferring from a fixed fifo register) */ + bits |= PLX_LOCAL_ADDR_CONST_BIT; + /* route dma interrupt to pci bus */ + bits |= PLX_DMA_INTR_PCI_BIT; + /* enable demand mode */ + bits |= PLX_DEMAND_MODE_BIT; + /* enable local burst mode */ + bits |= PLX_DMA_LOCAL_BURST_EN_BIT; + bits |= PLX_LOCAL_BUS_32_WIDE_BITS; + writel(bits, plx_iobase + PLX_DMA0_MODE_REG); } -static irqreturn_t handle_interrupt(int irq, void *d) +static const struct hpdi_board *gsc_hpdi_find_board(struct pci_dev *pcidev) { - struct comedi_device *dev = d; - struct hpdi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - uint32_t hpdi_intr_status, hpdi_board_status; - uint32_t plx_status; - uint32_t plx_bits; - uint8_t dma0_status, dma1_status; - unsigned long flags; + unsigned int i; - if (!dev->attached) - return IRQ_NONE; + for (i = 0; i < ARRAY_SIZE(hpdi_boards); i++) + if (pcidev->device == hpdi_boards[i].device_id && + pcidev->subsystem_device == hpdi_boards[i].subdevice_id) + return &hpdi_boards[i]; + return NULL; +} - plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG); - if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) - return IRQ_NONE; +static int gsc_hpdi_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct hpdi_board *thisboard; + struct hpdi_private *devpriv; + struct comedi_subdevice *s; + int i; + int retval; - hpdi_intr_status = readl(devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - hpdi_board_status = readl(devpriv->hpdi_iobase + BOARD_STATUS_REG); + thisboard = gsc_hpdi_find_board(pcidev); + if (!thisboard) { + dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n", + pci_name(pcidev)); + return -EINVAL; + } + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; - async->events = 0; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - if (hpdi_intr_status) { - DEBUG_PRINT("hpdi: intr status 0x%x, ", hpdi_intr_status); - writel(hpdi_intr_status, - devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - } - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ - writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); + retval = comedi_pci_enable(dev); + if (retval) + return retval; + pci_set_master(pcidev); - DEBUG_PRINT("dma0 status 0x%x\n", dma0_status); - if (dma0_status & PLX_DMA_EN_BIT) - drain_dma_buffers(dev, 0); - DEBUG_PRINT(" cleared dma ch0 interrupt\n"); + devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0); + devpriv->mmio = pci_ioremap_bar(pcidev, 2); + if (!devpriv->plx9080_mmio || !devpriv->mmio) { + dev_warn(dev->class_dev, "failed to remap io memory\n"); + return -ENOMEM; } - spin_unlock_irqrestore(&dev->spinlock, flags); - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - DEBUG_PRINT("dma1 status 0x%x\n", dma1_status); + gsc_hpdi_init_plx9080(dev); - DEBUG_PRINT(" cleared dma ch1 interrupt\n"); + /* get irq */ + if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED, + dev->board_name, dev)) { + dev_warn(dev->class_dev, + "unable to allocate irq %u\n", pcidev->irq); + return -EINVAL; } - spin_unlock_irqrestore(&dev->spinlock, flags); + dev->irq = pcidev->irq; - /* clear possible plx9080 interrupt sources */ - if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits); - } + dev_dbg(dev->class_dev, " irq %u\n", dev->irq); - if (hpdi_board_status & RX_OVERRUN_BIT) { - comedi_error(dev, "rx fifo overrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - DEBUG_PRINT("dma0_status 0x%x\n", - (int)readb(devpriv->plx9080_iobase + - PLX_DMA0_CS_REG)); + /* allocate pci dma buffers */ + for (i = 0; i < NUM_DMA_BUFFERS; i++) { + devpriv->dio_buffer[i] = + pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE, + &devpriv->dio_buffer_phys_addr[i]); } - - if (hpdi_board_status & RX_UNDERRUN_BIT) { - comedi_error(dev, "rx fifo underrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + /* allocate dma descriptors */ + devpriv->dma_desc = pci_alloc_consistent(pcidev, + sizeof(struct plx_dma_desc) * + NUM_DMA_DESCRIPTORS, + &devpriv->dma_desc_phys_addr); + if (devpriv->dma_desc_phys_addr & 0xf) { + dev_warn(dev->class_dev, + " dma descriptors not quad-word aligned (bug)\n"); + return -EIO; } - if (devpriv->dio_count == 0) - async->events |= COMEDI_CB_EOA; - - DEBUG_PRINT("board status 0x%x, ", hpdi_board_status); - DEBUG_PRINT("plx status 0x%x\n", plx_status); - if (async->events) - DEBUG_PRINT(" events 0x%x\n", async->events); - - cfc_handle_events(dev, s); - - return IRQ_HANDLED; -} - -static void abort_dma(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - unsigned long flags; - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); + retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000); + if (retval < 0) + return retval; - plx9080_abort_dma(devpriv->plx9080_iobase, channel); + retval = comedi_alloc_subdevices(dev, 1); + if (retval) + return retval; - spin_unlock_irqrestore(&dev->spinlock, flags); + /* Digital I/O subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | + SDF_CMD_READ; + s->n_chan = 32; + s->len_chanlist = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = gsc_hpdi_dio_insn_config; + s->do_cmd = gsc_hpdi_cmd; + s->do_cmdtest = gsc_hpdi_cmd_test; + s->cancel = gsc_hpdi_cancel; + + return gsc_hpdi_init(dev); } -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +static void gsc_hpdi_detach(struct comedi_device *dev) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct hpdi_private *devpriv = dev->private; + unsigned int i; - hpdi_writel(dev, 0, BOARD_CONTROL_REG); - - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - abort_dma(dev, 0); - - return 0; + if (dev->irq) + free_irq(dev->irq, dev); + if (devpriv) { + if (devpriv->plx9080_mmio) { + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + iounmap(devpriv->plx9080_mmio); + } + if (devpriv->mmio) + iounmap(devpriv->mmio); + /* free pci dma buffers */ + for (i = 0; i < NUM_DMA_BUFFERS; i++) { + if (devpriv->dio_buffer[i]) + pci_free_consistent(pcidev, + DMA_BUFFER_SIZE, + devpriv->dio_buffer[i], + devpriv-> + dio_buffer_phys_addr[i]); + } + /* free dma descriptors */ + if (devpriv->dma_desc) + pci_free_consistent(pcidev, + sizeof(struct plx_dma_desc) * + NUM_DMA_DESCRIPTORS, + devpriv->dma_desc, + devpriv->dma_desc_phys_addr); + } + comedi_pci_disable(dev); } static struct comedi_driver gsc_hpdi_driver = { .driver_name = "gsc_hpdi", .module = THIS_MODULE, - .auto_attach = hpdi_auto_attach, - .detach = hpdi_detach, + .auto_attach = gsc_hpdi_auto_attach, + .detach = gsc_hpdi_detach, }; static int gsc_hpdi_pci_probe(struct pci_dev *dev, @@ -929,7 +731,7 @@ static int gsc_hpdi_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &gsc_hpdi_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = { +static const struct pci_device_id gsc_hpdi_pci_table[] = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX, 0x2400, 0, 0, 0}, { 0 } diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index a11e015dc03..0b8b2162b76 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -42,6 +42,7 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V Configuration options: not applicable, uses PCI auto config */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -90,12 +91,13 @@ Configuration options: not applicable, uses PCI auto config #define Status_IRQ 0x00ff /* All interrupts */ /* Define analogue range */ -static const struct comedi_lrange range_analog = { 4, { - UNI_RANGE(5), - UNI_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(10) - } +static const struct comedi_lrange range_analog = { + 4, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10) + } }; static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; @@ -117,9 +119,7 @@ struct icp_multi_private { unsigned char act_chanlist_len; /* len of scanlist */ unsigned char act_chanlist_pos; /* actual position in MUX list */ unsigned int *ai_chanlist; /* actaul chanlist */ - short *ai_data; /* data buffer */ - short ao_data[4]; /* data output buffer */ - short di_data; /* Digital input data */ + unsigned short ao_data[4]; /* data output buffer */ unsigned int do_data; /* Remember digital output data */ }; @@ -171,12 +171,27 @@ static void setup_channel_list(struct comedi_device *dev, } } +static int icp_multi_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_ADC_CSR); + if ((status & ADC_BSY) == 0) + return 0; + return -EBUSY; +} + static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, timeout; + int ret = 0; + int n; /* Disable A/D conversion ready interrupt */ devpriv->IntEnable &= ~ADC_READY; @@ -199,33 +214,10 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, udelay(1); /* Wait for conversion to complete, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_ADC_CSR) & ADC_BSY)) - goto conv_finish; - - udelay(1); - } + ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0); + if (ret) + break; - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "A/D insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); - - /* Clear data received */ - data[n] = 0; - - return -ETIME; - -conv_finish: data[n] = (readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff; } @@ -238,7 +230,21 @@ conv_finish: devpriv->IntStatus |= ADC_READY; writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); - return n; + return ret ? ret : n; +} + +static int icp_multi_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_DAC_CSR); + if ((status & DAC_BSY) == 0) + return 0; + return -EBUSY; } static int icp_multi_insn_write_ao(struct comedi_device *dev, @@ -246,7 +252,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, chan, range, timeout; + int n, chan, range; + int ret; /* Disable D/A conversion ready interrupt */ devpriv->IntEnable &= ~DAC_READY; @@ -274,33 +281,24 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* Wait for analogue output data register to be * ready for new data, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_DAC_CSR) & DAC_BSY)) - goto dac_ready; - - udelay(1); + ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0); + if (ret) { + /* Disable interrupt */ + devpriv->IntEnable &= ~DAC_READY; + writew(devpriv->IntEnable, + devpriv->io_addr + ICP_MULTI_INT_EN); + + /* Clear interrupt status */ + devpriv->IntStatus |= DAC_READY; + writew(devpriv->IntStatus, + devpriv->io_addr + ICP_MULTI_INT_STAT); + + /* Clear data received */ + devpriv->ao_data[chan] = 0; + + return ret; } - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "D/A insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); - - /* Clear data received */ - devpriv->ao_data[chan] = 0; - - return -ETIME; - -dac_ready: /* Write data to analogue output data register */ writew(data[n], devpriv->io_addr + ICP_MULTI_AO); @@ -347,18 +345,13 @@ static int icp_multi_insn_bits_di(struct comedi_device *dev, static int icp_multi_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - printk(KERN_DEBUG "Digital outputs = %4x \n", s->state); - + if (comedi_dio_update_state(s, data)) writew(s->state, devpriv->io_addr + ICP_MULTI_DO); - } data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); @@ -495,10 +488,9 @@ static int icp_multi_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -548,7 +540,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = 16; s->range_table = &range_digital; - s->io_bits = 0; s->insn_bits = icp_multi_insn_bits_di; s = &dev->subdevices[3]; @@ -558,8 +549,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = 8; s->range_table = &range_digital; - s->io_bits = 0xff; - s->state = 0; s->insn_bits = icp_multi_insn_bits_do; s = &dev->subdevices[4]; @@ -574,9 +563,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, devpriv->valid = 1; - dev_info(dev->class_dev, "%s attached, irq %sabled\n", - dev->board_name, dev->irq ? "en" : "dis"); - return 0; } @@ -607,7 +593,7 @@ static int icp_multi_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &icp_multi_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = { +static const struct pci_device_id icp_multi_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index ee7537daf47..2516ce83483 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -1,662 +1,533 @@ /* - * comedi/drivers/ii_pci20kc.c - * Driver for Intelligent Instruments PCI-20001C carrier board - * and modules. + * ii_pci20kc.c + * Driver for Intelligent Instruments PCI-20001C carrier board and modules. * - * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de> - * with suggestions from David Schleef - * 16.06.2000 - * - * Linux device driver for COMEDI - * Intelligent Instrumentation - * PCI-20001 C-2A Carrier Board - * PCI-20341 M-1A 16-Bit analog input module - * - differential - * - range (-5V - +5V) - * - 16 bit - * PCI-20006 M-2 16-Bit analog output module - * - ranges (-10V - +10V) (0V - +10V) (-5V - +5V) - * - 16 bit - * - * only ONE PCI-20341 module possible - * only ONE PCI-20006 module possible - * no extern trigger implemented - * - * NOT WORKING (but soon) only 4 on-board differential channels supported - * NOT WORKING (but soon) only ONE di-port and ONE do-port supported - * instead of 4 digital ports - * di-port == Port 0 - * do-port == Port 1 - * - * The state of this driver is only a starting point for a complete - * COMEDI-driver. The final driver should support all features of the - * carrier board and modules. + * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de> + * with suggestions from David Schleef 16.06.2000 + */ + +/* + * Driver: ii_pci20kc + * Description: Intelligent Instruments PCI-20001C carrier board + * Devices: (Intelligent Instrumentation) PCI-20001C [ii_pci20kc] + * Author: Markus Kempf <kempf@matsci.uni-sb.de> + * Status: works * - * The test configuration: + * Supports the PCI-20001C-1a and PCI-20001C-2a carrier boards. The + * -2a version has 32 on-board DIO channels. Three add-on modules + * can be added to the carrier board for additional functionality. * - * kernel 2.2.14 with RTAI v1.2 and patch-2.2.14rthal2 - * COMEDI 0.7.45 - * COMEDILIB 0.7.9 + * Supported add-on modules: + * PCI-20006M-1 1 channel, 16-bit analog output module + * PCI-20006M-2 2 channel, 16-bit analog output module + * PCI-20341M-1A 4 channel, 16-bit analog input module * + * Options: + * 0 Board base address + * 1 IRQ (not-used) */ -/* -Driver: ii_pci20kc -Description: Intelligent Instruments PCI-20001C carrier board -Author: Markus Kempf <kempf@matsci.uni-sb.de> -Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc) -Status: works - -Supports the PCI-20001 C-2a Carrier board, and could probably support -the other carrier boards with small modifications. Modules supported -are: - PCI-20006 M-2 16-bit analog output module - PCI-20341 M-1A 16-bit analog input module - -Options: - 0 Board base address - 1 IRQ - 2 first option for module 1 - 3 second option for module 1 - 4 first option for module 2 - 5 second option for module 2 - 6 first option for module 3 - 7 second option for module 3 - -options for PCI-20006M: - first: Analog output channel 0 range configuration - 0 bipolar 10 (-10V -- +10V) - 1 unipolar 10 (0V -- +10V) - 2 bipolar 5 (-5V -- 5V) - second: Analog output channel 1 range configuration - -options for PCI-20341M: - first: Analog input gain configuration - 0 1 - 1 10 - 2 100 - 3 200 -*/ +#include <linux/module.h> #include "../comedidev.h" -#define PCI20000_ID 0x1d -#define PCI20341_ID 0x77 -#define PCI20006_ID 0xe3 -#define PCI20xxx_EMPTY_ID 0xff - -#define PCI20000_OFFSET 0x100 -#define PCI20000_MODULES 3 - -#define PCI20000_DIO_0 0x80 -#define PCI20000_DIO_1 0x81 -#define PCI20000_DIO_2 0xc0 -#define PCI20000_DIO_3 0xc1 -#define PCI20000_DIO_CONTROL_01 0x83 /* port 0, 1 control */ -#define PCI20000_DIO_CONTROL_23 0xc3 /* port 2, 3 control */ -#define PCI20000_DIO_BUFFER 0x82 /* buffer direction & enable */ -#define PCI20000_DIO_EOC 0xef /* even port, control output */ -#define PCI20000_DIO_OOC 0xfd /* odd port, control output */ -#define PCI20000_DIO_EIC 0x90 /* even port, control input */ -#define PCI20000_DIO_OIC 0x82 /* odd port, control input */ -#define DIO_CAND 0x12 /* and bit 1 & 4 of control */ -#define DIO_BE 0x01 /* buffer: port enable */ -#define DIO_BO 0x04 /* buffer: output */ -#define DIO_BI 0x05 /* buffer: input */ -#define DIO_PS_0 0x00 /* buffer: port shift 0 */ -#define DIO_PS_1 0x01 /* buffer: port shift 1 */ -#define DIO_PS_2 0x04 /* buffer: port shift 2 */ -#define DIO_PS_3 0x05 /* buffer: port shift 3 */ - -#define PCI20006_LCHAN0 0x0d -#define PCI20006_STROBE0 0x0b -#define PCI20006_LCHAN1 0x15 -#define PCI20006_STROBE1 0x13 - -#define PCI20341_INIT 0x04 -#define PCI20341_REPMODE 0x00 /* single shot mode */ -#define PCI20341_PACER 0x00 /* Hardware Pacer disabled */ -#define PCI20341_CHAN_NR 0x04 /* number of input channels */ -#define PCI20341_CONFIG_REG 0x10 -#define PCI20341_MOD_STATUS 0x01 -#define PCI20341_OPT_REG 0x11 -#define PCI20341_SET_TIME_REG 0x15 -#define PCI20341_LCHAN_ADDR_REG 0x13 -#define PCI20341_CHAN_LIST 0x80 -#define PCI20341_CC_RESET 0x1b -#define PCI20341_CHAN_RESET 0x19 -#define PCI20341_SOFT_PACER 0x04 -#define PCI20341_STATUS_REG 0x12 -#define PCI20341_LDATA 0x02 -#define PCI20341_DAISY_CHAIN 0x20 /* On-board inputs only */ -#define PCI20341_MUX 0x04 /* Enable on-board MUX */ -#define PCI20341_SCANLIST 0x80 /* Channel/Gain Scan List */ - -union pci20xxx_subdev_private { - void __iomem *iobase; - struct { - void __iomem *iobase; - const struct comedi_lrange *ao_range_list[2]; - /* range of channels of ao module */ - unsigned int last_data[2]; - } pci20006; - struct { - void __iomem *iobase; - int timebase; - int settling_time; - int ai_gain; - } pci20341; +/* + * Register I/O map + */ +#define II20K_MOD_OFFSET 0x100 +#define II20K_ID_REG 0x00 +#define II20K_ID_MOD1_EMPTY (1 << 7) +#define II20K_ID_MOD2_EMPTY (1 << 6) +#define II20K_ID_MOD3_EMPTY (1 << 5) +#define II20K_ID_MASK 0x1f +#define II20K_ID_PCI20001C_1A 0x1b /* no on-board DIO */ +#define II20K_ID_PCI20001C_2A 0x1d /* on-board DIO */ +#define II20K_MOD_STATUS_REG 0x40 +#define II20K_MOD_STATUS_IRQ_MOD1 (1 << 7) +#define II20K_MOD_STATUS_IRQ_MOD2 (1 << 6) +#define II20K_MOD_STATUS_IRQ_MOD3 (1 << 5) +#define II20K_DIO0_REG 0x80 +#define II20K_DIO1_REG 0x81 +#define II20K_DIR_ENA_REG 0x82 +#define II20K_DIR_DIO3_OUT (1 << 7) +#define II20K_DIR_DIO2_OUT (1 << 6) +#define II20K_BUF_DISAB_DIO3 (1 << 5) +#define II20K_BUF_DISAB_DIO2 (1 << 4) +#define II20K_DIR_DIO1_OUT (1 << 3) +#define II20K_DIR_DIO0_OUT (1 << 2) +#define II20K_BUF_DISAB_DIO1 (1 << 1) +#define II20K_BUF_DISAB_DIO0 (1 << 0) +#define II20K_CTRL01_REG 0x83 +#define II20K_CTRL01_SET (1 << 7) +#define II20K_CTRL01_DIO0_IN (1 << 4) +#define II20K_CTRL01_DIO1_IN (1 << 1) +#define II20K_DIO2_REG 0xc0 +#define II20K_DIO3_REG 0xc1 +#define II20K_CTRL23_REG 0xc3 +#define II20K_CTRL23_SET (1 << 7) +#define II20K_CTRL23_DIO2_IN (1 << 4) +#define II20K_CTRL23_DIO3_IN (1 << 1) + +#define II20K_ID_PCI20006M_1 0xe2 /* 1 AO channels */ +#define II20K_ID_PCI20006M_2 0xe3 /* 2 AO channels */ +#define II20K_AO_STRB_REG(x) (0x0b + ((x) * 0x08)) +#define II20K_AO_LSB_REG(x) (0x0d + ((x) * 0x08)) +#define II20K_AO_MSB_REG(x) (0x0e + ((x) * 0x08)) +#define II20K_AO_STRB_BOTH_REG 0x1b + +#define II20K_ID_PCI20341M_1 0x77 /* 4 AI channels */ +#define II20K_AI_STATUS_CMD_REG 0x01 +#define II20K_AI_STATUS_CMD_BUSY (1 << 7) +#define II20K_AI_STATUS_CMD_HW_ENA (1 << 1) +#define II20K_AI_STATUS_CMD_EXT_START (1 << 0) +#define II20K_AI_LSB_REG 0x02 +#define II20K_AI_MSB_REG 0x03 +#define II20K_AI_PACER_RESET_REG 0x04 +#define II20K_AI_16BIT_DATA_REG 0x06 +#define II20K_AI_CONF_REG 0x10 +#define II20K_AI_CONF_ENA (1 << 2) +#define II20K_AI_OPT_REG 0x11 +#define II20K_AI_OPT_TRIG_ENA (1 << 5) +#define II20K_AI_OPT_TRIG_INV (1 << 4) +#define II20K_AI_OPT_TIMEBASE(x) (((x) & 0x3) << 1) +#define II20K_AI_OPT_BURST_MODE (1 << 0) +#define II20K_AI_STATUS_REG 0x12 +#define II20K_AI_STATUS_INT (1 << 7) +#define II20K_AI_STATUS_TRIG (1 << 6) +#define II20K_AI_STATUS_TRIG_ENA (1 << 5) +#define II20K_AI_STATUS_PACER_ERR (1 << 2) +#define II20K_AI_STATUS_DATA_ERR (1 << 1) +#define II20K_AI_STATUS_SET_TIME_ERR (1 << 0) +#define II20K_AI_LAST_CHAN_ADDR_REG 0x13 +#define II20K_AI_CUR_ADDR_REG 0x14 +#define II20K_AI_SET_TIME_REG 0x15 +#define II20K_AI_DELAY_LSB_REG 0x16 +#define II20K_AI_DELAY_MSB_REG 0x17 +#define II20K_AI_CHAN_ADV_REG 0x18 +#define II20K_AI_CHAN_RESET_REG 0x19 +#define II20K_AI_START_TRIG_REG 0x1a +#define II20K_AI_COUNT_RESET_REG 0x1b +#define II20K_AI_CHANLIST_REG 0x80 +#define II20K_AI_CHANLIST_ONBOARD_ONLY (1 << 5) +#define II20K_AI_CHANLIST_GAIN(x) (((x) & 0x3) << 3) +#define II20K_AI_CHANLIST_MUX_ENA (1 << 2) +#define II20K_AI_CHANLIST_CHAN(x) (((x) & 0x3) << 0) +#define II20K_AI_CHANLIST_LEN 0x80 + +/* the AO range is set by jumpers on the 20006M module */ +static const struct comedi_lrange ii20k_ao_ranges = { + 3, { + BIP_RANGE(5), /* Chan 0 - W1/W3 in Chan 1 - W2/W4 in */ + UNI_RANGE(10), /* Chan 0 - W1/W3 out Chan 1 - W2/W4 in */ + BIP_RANGE(10) /* Chan 0 - W1/W3 in Chan 1 - W2/W4 out */ + } +}; + +static const struct comedi_lrange ii20k_ai_ranges = { + 4, { + BIP_RANGE(5), /* gain 1 */ + BIP_RANGE(0.5), /* gain 10 */ + BIP_RANGE(0.05), /* gain 100 */ + BIP_RANGE(0.025) /* gain 200 */ + }, }; -struct pci20xxx_private { +struct ii20k_ao_private { + unsigned int last_data[2]; +}; +struct ii20k_private { void __iomem *ioaddr; - union pci20xxx_subdev_private subdev_private[PCI20000_MODULES]; }; -#define CHAN (CR_CHAN(it->chanlist[0])) +static void __iomem *ii20k_module_iobase(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct ii20k_private *devpriv = dev->private; -static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1); -static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1); -static int pci20xxx_dio_init(struct comedi_device *dev, - struct comedi_subdevice *s); + return devpriv->ioaddr + (s->index + 1) * II20K_MOD_OFFSET; +} -/* - options[0] Board base address - options[1] IRQ - options[2] first option for module 1 - options[3] second option for module 1 - options[4] first option for module 2 - options[5] second option for module 2 - options[6] first option for module 3 - options[7] second option for module 3 - - options for PCI-20341M: - first Analog input gain configuration - 0 == 1 - 1 == 10 - 2 == 100 - 3 == 200 - - options for PCI-20006M: - first Analog output channel 0 range configuration - 0 == bipolar 10 (-10V -- +10V) - 1 == unipolar 10V (0V -- +10V) - 2 == bipolar 5V (-5V -- +5V) - second Analog output channel 1 range configuration - 0 == bipolar 10 (-10V -- +10V) - 1 == unipolar 10V (0V -- +10V) - 2 == bipolar 5V (-5V -- +5V) -*/ -static int pci20xxx_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int ii20k_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pci20xxx_private *devpriv; - unsigned char i; - int ret; - int id; - struct comedi_subdevice *s; - union pci20xxx_subdev_private *sdp; + struct ii20k_ao_private *ao_spriv = s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - ret = comedi_alloc_subdevices(dev, 1 + PCI20000_MODULES); - if (ret) - return ret; + for (i = 0; i < insn->n; i++) + data[i] = ao_spriv->last_data[chan]; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; + return insn->n; +} - devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0]; +static int ii20k_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct ii20k_ao_private *ao_spriv = s->private; + void __iomem *iobase = ii20k_module_iobase(dev, s); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = ao_spriv->last_data[chan]; + int i; - /* Check PCI-20001 C-2A Carrier Board ID */ - if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) { - dev_warn(dev->class_dev, - "PCI-20001 C-2A Carrier Board at base=0x%p not found !\n", - devpriv->ioaddr); - return -EINVAL; - } - dev_info(dev->class_dev, "PCI-20001 C-2A at base=0x%p\n", - devpriv->ioaddr); - - for (i = 0; i < PCI20000_MODULES; i++) { - s = &dev->subdevices[i]; - id = readb(devpriv->ioaddr + (i + 1) * PCI20000_OFFSET); - s->private = devpriv->subdev_private + i; - sdp = s->private; - switch (id) { - case PCI20006_ID: - sdp->pci20006.iobase = - devpriv->ioaddr + (i + 1) * PCI20000_OFFSET; - pci20006_init(dev, s, it->options[2 * i + 2], - it->options[2 * i + 3]); - dev_info(dev->class_dev, - "PCI-20006 module in slot %d\n", i + 1); - break; - case PCI20341_ID: - sdp->pci20341.iobase = - devpriv->ioaddr + (i + 1) * PCI20000_OFFSET; - pci20341_init(dev, s, it->options[2 * i + 2], - it->options[2 * i + 3]); - dev_info(dev->class_dev, - "PCI-20341 module in slot %d\n", i + 1); - break; - default: - dev_warn(dev->class_dev, - "unknown module code 0x%02x in slot %d: module disabled\n", - id, i); /* XXX this looks like a bug! i + 1 ?? */ - /* fall through */ - case PCI20xxx_EMPTY_ID: - s->type = COMEDI_SUBD_UNUSED; - break; - } + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* munge data */ + val += ((s->maxdata + 1) >> 1); + val &= s->maxdata; + + writeb(val & 0xff, iobase + II20K_AO_LSB_REG(chan)); + writeb((val >> 8) & 0xff, iobase + II20K_AO_MSB_REG(chan)); + writeb(0x00, iobase + II20K_AO_STRB_REG(chan)); } - /* initialize struct pci20xxx_private */ - pci20xxx_dio_init(dev, &dev->subdevices[PCI20000_MODULES]); + ao_spriv->last_data[chan] = val; - return 1; + return insn->n; } -static void pci20xxx_detach(struct comedi_device *dev) +static int ii20k_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - /* Nothing to cleanup */ + void __iomem *iobase = ii20k_module_iobase(dev, s); + unsigned char status; + + status = readb(iobase + II20K_AI_STATUS_REG); + if ((status & II20K_AI_STATUS_INT) == 0) + return 0; + return -EBUSY; } -/* pci20006m */ +static void ii20k_ai_setup(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chanspec) +{ + void __iomem *iobase = ii20k_module_iobase(dev, s); + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned char val; -static int pci20006_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pci20006_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + /* initialize module */ + writeb(II20K_AI_CONF_ENA, iobase + II20K_AI_CONF_REG); -static const struct comedi_lrange *pci20006_range_list[] = { - &range_bipolar10, - &range_unipolar10, - &range_bipolar5, -}; + /* software conversion */ + writeb(0, iobase + II20K_AI_STATUS_CMD_REG); -static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1) -{ - union pci20xxx_subdev_private *sdp = s->private; - - if (opt0 < 0 || opt0 > 2) - opt0 = 0; - if (opt1 < 0 || opt1 > 2) - opt1 = 0; - - sdp->pci20006.ao_range_list[0] = pci20006_range_list[opt0]; - sdp->pci20006.ao_range_list[1] = pci20006_range_list[opt1]; - - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->len_chanlist = 2; - s->insn_read = pci20006_insn_read; - s->insn_write = pci20006_insn_write; - s->maxdata = 0xffff; - s->range_table_list = sdp->pci20006.ao_range_list; - return 0; -} + /* set the time base for the settling time counter based on the gain */ + val = (range < 3) ? II20K_AI_OPT_TIMEBASE(0) : II20K_AI_OPT_TIMEBASE(2); + writeb(val, iobase + II20K_AI_OPT_REG); -static int pci20006_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - union pci20xxx_subdev_private *sdp = s->private; + /* set the settling time counter based on the gain */ + val = (range < 2) ? 0x58 : (range < 3) ? 0x93 : 0x99; + writeb(val, iobase + II20K_AI_SET_TIME_REG); - data[0] = sdp->pci20006.last_data[CR_CHAN(insn->chanspec)]; + /* set number of input channels */ + writeb(1, iobase + II20K_AI_LAST_CHAN_ADDR_REG); - return 1; -} + /* set the channel list byte */ + val = II20K_AI_CHANLIST_ONBOARD_ONLY | + II20K_AI_CHANLIST_MUX_ENA | + II20K_AI_CHANLIST_GAIN(range) | + II20K_AI_CHANLIST_CHAN(chan); + writeb(val, iobase + II20K_AI_CHANLIST_REG); -static int pci20006_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - union pci20xxx_subdev_private *sdp = s->private; - int hi, lo; - unsigned int boarddata; - - sdp->pci20006.last_data[CR_CHAN(insn->chanspec)] = data[0]; - boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff); - /* comedi-data -> board-data */ - lo = (boarddata & 0xff); - hi = ((boarddata >> 8) & 0xff); - - switch (CR_CHAN(insn->chanspec)) { - case 0: - writeb(lo, sdp->iobase + PCI20006_LCHAN0); - writeb(hi, sdp->iobase + PCI20006_LCHAN0 + 1); - writeb(0x00, sdp->iobase + PCI20006_STROBE0); - break; - case 1: - writeb(lo, sdp->iobase + PCI20006_LCHAN1); - writeb(hi, sdp->iobase + PCI20006_LCHAN1 + 1); - writeb(0x00, sdp->iobase + PCI20006_STROBE1); - break; - default: - dev_warn(dev->class_dev, "ao channel Error!\n"); - return -EINVAL; - } + /* reset settling time counter and trigger delay counter */ + writeb(0, iobase + II20K_AI_COUNT_RESET_REG); - return 1; + /* reset channel scanner */ + writeb(0, iobase + II20K_AI_CHAN_RESET_REG); } -/* PCI20341M */ - -static int pci20341_insn_read(struct comedi_device *dev, +static int ii20k_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + struct comedi_insn *insn, + unsigned int *data) +{ + void __iomem *iobase = ii20k_module_iobase(dev, s); + int ret; + int i; -static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 }; -static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 }; + ii20k_ai_setup(dev, s, insn->chanspec); -static const struct comedi_lrange range_bipolar0_5 = { - 1, - {BIP_RANGE(0.5)} -}; + for (i = 0; i < insn->n; i++) { + unsigned int val; -static const struct comedi_lrange range_bipolar0_05 = { - 1, - {BIP_RANGE(0.05)} -}; + /* generate a software start convert signal */ + readb(iobase + II20K_AI_PACER_RESET_REG); -static const struct comedi_lrange range_bipolar0_025 = { - 1, - {BIP_RANGE(0.025)} -}; + ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0); + if (ret) + return ret; -static const struct comedi_lrange *const pci20341_ranges[] = { - &range_bipolar5, - &range_bipolar0_5, - &range_bipolar0_05, - &range_bipolar0_025, -}; + val = readb(iobase + II20K_AI_LSB_REG); + val |= (readb(iobase + II20K_AI_MSB_REG) << 8); -static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1) -{ - union pci20xxx_subdev_private *sdp = s->private; - int option; - - /* options handling */ - if (opt0 < 0 || opt0 > 3) - opt0 = 0; - sdp->pci20341.timebase = pci20341_timebase[opt0]; - sdp->pci20341.settling_time = pci20341_settling_time[opt0]; - - /* ai subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - s->n_chan = PCI20341_CHAN_NR; - s->len_chanlist = PCI20341_SCANLIST; - s->insn_read = pci20341_insn_read; - s->maxdata = 0xffff; - s->range_table = pci20341_ranges[opt0]; - - /* depends on gain, trigger, repetition mode */ - option = sdp->pci20341.timebase | PCI20341_REPMODE; - - /* initialize Module */ - writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG); - /* set Pacer */ - writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS); - /* option register */ - writeb(option, sdp->iobase + PCI20341_OPT_REG); - /* settling time counter */ - writeb(sdp->pci20341.settling_time, - sdp->iobase + PCI20341_SET_TIME_REG); - /* trigger not implemented */ - return 0; + /* munge two's complement data */ + val += ((s->maxdata + 1) >> 1); + val &= s->maxdata; + + data[i] = val; + } + + return insn->n; } -static int pci20341_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void ii20k_dio_config(struct comedi_device *dev, + struct comedi_subdevice *s) { - union pci20xxx_subdev_private *sdp = s->private; - unsigned int i = 0, j = 0; - int lo, hi; - unsigned char eoc; /* end of conversion */ - unsigned int clb; /* channel list byte */ - unsigned int boarddata; - - /* write number of input channels */ - writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG); - clb = PCI20341_DAISY_CHAIN | PCI20341_MUX | (sdp->pci20341.ai_gain << 3) - | CR_CHAN(insn->chanspec); - writeb(clb, sdp->iobase + PCI20341_CHAN_LIST); + struct ii20k_private *devpriv = dev->private; + unsigned char ctrl01 = 0; + unsigned char ctrl23 = 0; + unsigned char dir_ena = 0; - /* reset settling time counter and trigger delay counter */ - writeb(0x00, sdp->iobase + PCI20341_CC_RESET); - - writeb(0x00, sdp->iobase + PCI20341_CHAN_RESET); + /* port 0 - channels 0-7 */ + if (s->io_bits & 0x000000ff) { + /* output port */ + ctrl01 &= ~II20K_CTRL01_DIO0_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO0; + dir_ena |= II20K_DIR_DIO0_OUT; + } else { + /* input port */ + ctrl01 |= II20K_CTRL01_DIO0_IN; + dir_ena &= ~II20K_DIR_DIO0_OUT; + } - /* generate Pacer */ + /* port 1 - channels 8-15 */ + if (s->io_bits & 0x0000ff00) { + /* output port */ + ctrl01 &= ~II20K_CTRL01_DIO1_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO1; + dir_ena |= II20K_DIR_DIO1_OUT; + } else { + /* input port */ + ctrl01 |= II20K_CTRL01_DIO1_IN; + dir_ena &= ~II20K_DIR_DIO1_OUT; + } - for (i = 0; i < insn->n; i++) { - /* data polling isn't the niciest way to get the data, I know, - * but there are only 6 cycles (mean) and it is easier than - * the whole interrupt stuff - */ - j = 0; - /* generate Pacer */ - readb(sdp->iobase + PCI20341_SOFT_PACER); - - eoc = readb(sdp->iobase + PCI20341_STATUS_REG); - /* poll Interrupt Flag */ - while ((eoc < 0x80) && j < 100) { - j++; - eoc = readb(sdp->iobase + PCI20341_STATUS_REG); - } - if (j >= 100) { - dev_warn(dev->class_dev, - "AI interrupt channel %i polling exit !\n", i); - return -EINVAL; - } - lo = readb(sdp->iobase + PCI20341_LDATA); - hi = readb(sdp->iobase + PCI20341_LDATA + 1); - boarddata = lo + 0x100 * hi; - - /* board-data -> comedi-data */ - data[i] = (short)((boarddata + 0x8000) & 0xffff); + /* port 2 - channels 16-23 */ + if (s->io_bits & 0x00ff0000) { + /* output port */ + ctrl23 &= ~II20K_CTRL23_DIO2_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO2; + dir_ena |= II20K_DIR_DIO2_OUT; + } else { + /* input port */ + ctrl23 |= II20K_CTRL23_DIO2_IN; + dir_ena &= ~II20K_DIR_DIO2_OUT; } - return i; -} + /* port 3 - channels 24-31 */ + if (s->io_bits & 0xff000000) { + /* output port */ + ctrl23 &= ~II20K_CTRL23_DIO3_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO3; + dir_ena |= II20K_DIR_DIO3_OUT; + } else { + /* input port */ + ctrl23 |= II20K_CTRL23_DIO3_IN; + dir_ena &= ~II20K_DIR_DIO3_OUT; + } -/* native DIO */ + ctrl23 |= II20K_CTRL01_SET; + ctrl23 |= II20K_CTRL23_SET; -static void pci20xxx_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s); -static int pci20xxx_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pci20xxx_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + /* order is important */ + writeb(ctrl01, devpriv->ioaddr + II20K_CTRL01_REG); + writeb(ctrl23, devpriv->ioaddr + II20K_CTRL23_REG); + writeb(dir_ena, devpriv->ioaddr + II20K_DIR_ENA_REG); +} -/* initialize struct pci20xxx_private */ -static int pci20xxx_dio_init(struct comedi_device *dev, - struct comedi_subdevice *s) +static int ii20k_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 32; - s->insn_bits = pci20xxx_dio_insn_bits; - s->insn_config = pci20xxx_dio_insn_config; - s->maxdata = 1; - s->len_chanlist = 32; - s->range_table = &range_digital; - s->io_bits = 0; + if (chan < 8) + mask = 0x000000ff; + else if (chan < 16) + mask = 0x0000ff00; + else if (chan < 24) + mask = 0x00ff0000; + else + mask = 0xff000000; - /* digital I/O lines default to input on board reset. */ - pci20xxx_dio_config(dev, s); + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - return 0; + ii20k_dio_config(dev, s); + + return insn->n; } -static int pci20xxx_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int ii20k_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int mask, bits; - - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x000000ff) - bits = 0x000000ff; - else if (mask & 0x0000ff00) - bits = 0x0000ff00; - else if (mask & 0x00ff0000) - bits = 0x00ff0000; - else - bits = 0xff000000; - if (data[0]) - s->io_bits |= bits; - else - s->io_bits &= ~bits; - pci20xxx_dio_config(dev, s); + struct ii20k_private *devpriv = dev->private; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x000000ff) + writeb((s->state >> 0) & 0xff, + devpriv->ioaddr + II20K_DIO0_REG); + if (mask & 0x0000ff00) + writeb((s->state >> 8) & 0xff, + devpriv->ioaddr + II20K_DIO1_REG); + if (mask & 0x00ff0000) + writeb((s->state >> 16) & 0xff, + devpriv->ioaddr + II20K_DIO2_REG); + if (mask & 0xff000000) + writeb((s->state >> 24) & 0xff, + devpriv->ioaddr + II20K_DIO3_REG); + } - return 1; + data[1] = readb(devpriv->ioaddr + II20K_DIO0_REG); + data[1] |= readb(devpriv->ioaddr + II20K_DIO1_REG) << 8; + data[1] |= readb(devpriv->ioaddr + II20K_DIO2_REG) << 16; + data[1] |= readb(devpriv->ioaddr + II20K_DIO3_REG) << 24; + + return insn->n; } -static int pci20xxx_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int ii20k_init_module(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct pci20xxx_private *devpriv = dev->private; - unsigned int mask = data[0]; - - s->state &= ~mask; - s->state |= (mask & data[1]); - - mask &= s->io_bits; - if (mask & 0x000000ff) - writeb((s->state >> 0) & 0xff, - devpriv->ioaddr + PCI20000_DIO_0); - if (mask & 0x0000ff00) - writeb((s->state >> 8) & 0xff, - devpriv->ioaddr + PCI20000_DIO_1); - if (mask & 0x00ff0000) - writeb((s->state >> 16) & 0xff, - devpriv->ioaddr + PCI20000_DIO_2); - if (mask & 0xff000000) - writeb((s->state >> 24) & 0xff, - devpriv->ioaddr + PCI20000_DIO_3); - - data[1] = readb(devpriv->ioaddr + PCI20000_DIO_0); - data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8; - data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16; - data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24; + struct ii20k_ao_private *ao_spriv; + void __iomem *iobase = ii20k_module_iobase(dev, s); + unsigned char id; + + id = readb(iobase + II20K_ID_REG); + switch (id) { + case II20K_ID_PCI20006M_1: + case II20K_ID_PCI20006M_2: + ao_spriv = comedi_alloc_spriv(s, sizeof(*ao_spriv)); + if (!ao_spriv) + return -ENOMEM; + + /* Analog Output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = (id == II20K_ID_PCI20006M_2) ? 2 : 1; + s->maxdata = 0xffff; + s->range_table = &ii20k_ao_ranges; + s->insn_read = ii20k_ao_insn_read; + s->insn_write = ii20k_ao_insn_write; + break; + case II20K_ID_PCI20341M_1: + /* Analog Input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = 4; + s->maxdata = 0xffff; + s->range_table = &ii20k_ai_ranges; + s->insn_read = ii20k_ai_insn_read; + break; + default: + s->type = COMEDI_SUBD_UNUSED; + break; + } - return insn->n; + return 0; } -static void pci20xxx_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s) +static int ii20k_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - struct pci20xxx_private *devpriv = dev->private; - unsigned char control_01; - unsigned char control_23; - unsigned char buffer; + struct ii20k_private *devpriv; + struct comedi_subdevice *s; + unsigned char id; + bool has_dio; + int ret; - control_01 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_01); - control_23 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_23); - buffer = readb(devpriv->ioaddr + PCI20000_DIO_BUFFER); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - if (s->io_bits & 0x000000ff) { - /* output port 0 */ - control_01 &= PCI20000_DIO_EOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_0))) | (DIO_BO << - DIO_PS_0); - } else { - /* input port 0 */ - control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_EIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_0))); + devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0]; + + id = readb(devpriv->ioaddr + II20K_ID_REG); + switch (id & II20K_ID_MASK) { + case II20K_ID_PCI20001C_1A: + has_dio = false; + break; + case II20K_ID_PCI20001C_2A: + has_dio = true; + break; + default: + return -ENODEV; } - if (s->io_bits & 0x0000ff00) { - /* output port 1 */ - control_01 &= PCI20000_DIO_OOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_1))) | (DIO_BO << - DIO_PS_1); + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + s = &dev->subdevices[0]; + if (id & II20K_ID_MOD1_EMPTY) { + s->type = COMEDI_SUBD_UNUSED; } else { - /* input port 1 */ - control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_OIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_1))); + ret = ii20k_init_module(dev, s); + if (ret) + return ret; } - if (s->io_bits & 0x00ff0000) { - /* output port 2 */ - control_23 &= PCI20000_DIO_EOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_2))) | (DIO_BO << - DIO_PS_2); + + s = &dev->subdevices[1]; + if (id & II20K_ID_MOD2_EMPTY) { + s->type = COMEDI_SUBD_UNUSED; } else { - /* input port 2 */ - control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_EIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_2))); + ret = ii20k_init_module(dev, s); + if (ret) + return ret; } - if (s->io_bits & 0xff000000) { - /* output port 3 */ - control_23 &= PCI20000_DIO_OOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_3))) | (DIO_BO << - DIO_PS_3); + + s = &dev->subdevices[2]; + if (id & II20K_ID_MOD3_EMPTY) { + s->type = COMEDI_SUBD_UNUSED; } else { - /* input port 3 */ - control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_OIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_3))); + ret = ii20k_init_module(dev, s); + if (ret) + return ret; } - writeb(control_01, devpriv->ioaddr + PCI20000_DIO_CONTROL_01); - writeb(control_23, devpriv->ioaddr + PCI20000_DIO_CONTROL_23); - writeb(buffer, devpriv->ioaddr + PCI20000_DIO_BUFFER); -} -#if 0 -static void pci20xxx_do(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct pci20xxx_private *devpriv = dev->private; - - /* XXX if the channel is configured for input, does this - do bad things? */ - /* XXX it would be a good idea to only update the registers - that _need_ to be updated. This requires changes to - comedi, however. */ - writeb((s->state >> 0) & 0xff, devpriv->ioaddr + PCI20000_DIO_0); - writeb((s->state >> 8) & 0xff, devpriv->ioaddr + PCI20000_DIO_1); - writeb((s->state >> 16) & 0xff, devpriv->ioaddr + PCI20000_DIO_2); - writeb((s->state >> 24) & 0xff, devpriv->ioaddr + PCI20000_DIO_3); -} - -static unsigned int pci20xxx_di(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pci20xxx_private *devpriv = dev->private; - unsigned int bits; - - /* XXX same note as above */ - bits = readb(devpriv->ioaddr + PCI20000_DIO_0); - bits |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8; - bits |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16; - bits |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24; + /* Digital I/O subdevice */ + s = &dev->subdevices[3]; + if (has_dio) { + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ii20k_dio_insn_bits; + s->insn_config = ii20k_dio_insn_config; + + /* default all channels to input */ + ii20k_dio_config(dev, s); + } else { + s->type = COMEDI_SUBD_UNUSED; + } - return bits; + return 0; } -#endif -static struct comedi_driver pci20xxx_driver = { +static struct comedi_driver ii20k_driver = { .driver_name = "ii_pci20kc", .module = THIS_MODULE, - .attach = pci20xxx_attach, - .detach = pci20xxx_detach, + .attach = ii20k_attach, + .detach = comedi_legacy_detach, }; -module_comedi_driver(pci20xxx_driver); +module_comedi_driver(ii20k_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 94609f4aa4c..a8db9d86aad 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -38,6 +38,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/ctype.h> @@ -50,23 +51,55 @@ #include "jr3_pci.h" #define PCI_VENDOR_ID_JR3 0x1762 -#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111 -#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111 -#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112 -#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 -#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 -struct jr3_pci_dev_private { - struct jr3_t __iomem *iobase; - int n_channels; - struct timer_list timer; +enum jr3_pci_boardid { + BOARD_JR3_1, + BOARD_JR3_2, + BOARD_JR3_3, + BOARD_JR3_4, }; -struct poll_delay_t { +struct jr3_pci_board { + const char *name; + int n_subdevs; +}; + +static const struct jr3_pci_board jr3_pci_boards[] = { + [BOARD_JR3_1] = { + .name = "jr3_pci_1", + .n_subdevs = 1, + }, + [BOARD_JR3_2] = { + .name = "jr3_pci_2", + .n_subdevs = 2, + }, + [BOARD_JR3_3] = { + .name = "jr3_pci_3", + .n_subdevs = 3, + }, + [BOARD_JR3_4] = { + .name = "jr3_pci_4", + .n_subdevs = 4, + }, +}; + +struct jr3_pci_transform { + struct { + u16 link_type; + s16 link_amount; + } link[8]; +}; + +struct jr3_pci_poll_delay { int min; int max; }; +struct jr3_pci_dev_private { + struct jr3_t __iomem *iobase; + struct timer_list timer; +}; + struct jr3_pci_subdev_private { struct jr3_channel __iomem *channel; unsigned long next_time_min; @@ -78,7 +111,6 @@ struct jr3_pci_subdev_private { state_jr3_init_use_offset_complete, state_jr3_done } state; - int channel_no; int serial_no; int model_no; struct { @@ -91,9 +123,9 @@ struct jr3_pci_subdev_private { int retries; }; -static struct poll_delay_t poll_delay_min_max(int min, int max) +static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max) { - struct poll_delay_t result; + struct jr3_pci_poll_delay result; result.min = min; result.max = max; @@ -105,15 +137,8 @@ static int is_complete(struct jr3_channel __iomem *channel) return get_s16(&channel->command_word0) == 0; } -struct transform_t { - struct { - u16 link_type; - s16 link_amount; - } link[8]; -}; - static void set_transforms(struct jr3_channel __iomem *channel, - struct transform_t transf, short num) + struct jr3_pci_transform transf, short num) { int i; @@ -193,110 +218,99 @@ static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem return result; } +static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int val = 0; + + if (spriv->state != state_jr3_done) + return 0; + + if (chan < 56) { + unsigned int axis = chan % 8; + unsigned filter = chan / 8; + + switch (axis) { + case 0: + val = get_s16(&spriv->channel->filter[filter].fx); + break; + case 1: + val = get_s16(&spriv->channel->filter[filter].fy); + break; + case 2: + val = get_s16(&spriv->channel->filter[filter].fz); + break; + case 3: + val = get_s16(&spriv->channel->filter[filter].mx); + break; + case 4: + val = get_s16(&spriv->channel->filter[filter].my); + break; + case 5: + val = get_s16(&spriv->channel->filter[filter].mz); + break; + case 6: + val = get_s16(&spriv->channel->filter[filter].v1); + break; + case 7: + val = get_s16(&spriv->channel->filter[filter].v2); + break; + } + val += 0x4000; + } else if (chan == 56) { + val = get_u16(&spriv->channel->model_no); + } else if (chan == 57) { + val = get_u16(&spriv->channel->serial_no); + } + + return val; +} + static int jr3_pci_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int result; - struct jr3_pci_subdev_private *p; - int channel; - - p = s->private; - channel = CR_CHAN(insn->chanspec); - if (p == NULL || channel > 57) { - result = -EINVAL; - } else { - int i; - - result = insn->n; - if (p->state != state_jr3_done || - (get_u16(&p->channel->errors) & (watch_dog | watch_dog2 | - sensor_change))) { - /* No sensor or sensor changed */ - if (p->state == state_jr3_done) { - /* Restart polling */ - p->state = state_jr3_poll; - } - result = -EAGAIN; - } - for (i = 0; i < insn->n; i++) { - if (channel < 56) { - int axis, filter; - - axis = channel % 8; - filter = channel / 8; - if (p->state != state_jr3_done) { - data[i] = 0; - } else { - int F = 0; - switch (axis) { - case 0: - F = get_s16(&p->channel-> - filter[filter].fx); - break; - case 1: - F = get_s16(&p->channel-> - filter[filter].fy); - break; - case 2: - F = get_s16(&p->channel-> - filter[filter].fz); - break; - case 3: - F = get_s16(&p->channel-> - filter[filter].mx); - break; - case 4: - F = get_s16(&p->channel-> - filter[filter].my); - break; - case 5: - F = get_s16(&p->channel-> - filter[filter].mz); - break; - case 6: - F = get_s16(&p->channel-> - filter[filter].v1); - break; - case 7: - F = get_s16(&p->channel-> - filter[filter].v2); - break; - } - data[i] = F + 0x4000; - } - } else if (channel == 56) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->model_no); - } else if (channel == 57) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->serial_no); - } + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + u16 errors; + int i; + + if (!spriv) + return -EINVAL; + + errors = get_u16(&spriv->channel->errors); + if (spriv->state != state_jr3_done || + (errors & (watch_dog | watch_dog2 | sensor_change))) { + /* No sensor or sensor changed */ + if (spriv->state == state_jr3_done) { + /* Restart polling */ + spriv->state = state_jr3_poll; } + return -EAGAIN; } - return result; + + for (i = 0; i < insn->n; i++) + data[i] = jr3_pci_ai_read_chan(dev, s, chan); + + return insn->n; } static int jr3_pci_open(struct comedi_device *dev) { + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; int i; - struct jr3_pci_dev_private *devpriv = dev->private; dev_dbg(dev->class_dev, "jr3_pci_open\n"); - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p; - - p = dev->subdevices[i].private; - if (p) { - dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", p, - p->serial_no, p->channel_no); - } + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + if (spriv) + dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", + spriv, spriv->serial_no, s->index); } return 0; } @@ -325,271 +339,262 @@ static int read_idm_word(const u8 *data, size_t size, int *pos, return result; } -static int jr3_download_firmware(struct comedi_device *dev, - const u8 *data, size_t size, - unsigned long context) +static int jr3_check_firmware(struct comedi_device *dev, + const u8 *data, size_t size) { + int more = 1; + int pos = 0; + /* * IDM file format is: * { count, address, data <count> } * * ffff */ - int result, more, pos, OK; - - result = 0; - more = 1; - pos = 0; - OK = 0; while (more) { - unsigned int count, addr; + unsigned int count = 0; + unsigned int addr = 0; more = more && read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) { - OK = 1; - break; - } + if (more && count == 0xffff) + return 0; + more = more && read_idm_word(data, size, &pos, &addr); while (more && count > 0) { - unsigned int dummy; + unsigned int dummy = 0; + more = more && read_idm_word(data, size, &pos, &dummy); count--; } } - if (!OK) { - result = -ENODATA; - } else { - int i; - struct jr3_pci_dev_private *p = dev->private; + return -ENODATA; +} + +static void jr3_write_firmware(struct comedi_device *dev, + int subdev, const u8 *data, size_t size) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_t __iomem *iobase = devpriv->iobase; + u32 __iomem *lo; + u32 __iomem *hi; + int more = 1; + int pos = 0; + + while (more) { + unsigned int count = 0; + unsigned int addr = 0; + + more = more && read_idm_word(data, size, &pos, &count); + if (more && count == 0xffff) + return; + + more = more && read_idm_word(data, size, &pos, &addr); + + dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n", + subdev, count, addr); + + while (more && count > 0) { + if (addr & 0x4000) { + /* 16 bit data, never seen in real life!! */ + unsigned int data1 = 0; - for (i = 0; i < p->n_channels; i++) { - struct jr3_pci_subdev_private *sp; + more = more && + read_idm_word(data, size, &pos, &data1); + count--; + /* jr3[addr + 0x20000 * pnum] = data1; */ + } else { + /* Download 24 bit program */ + unsigned int data1 = 0; + unsigned int data2 = 0; + + lo = &iobase->channel[subdev].program_lo[addr]; + hi = &iobase->channel[subdev].program_hi[addr]; - sp = dev->subdevices[i].private; - more = 1; - pos = 0; - while (more) { - unsigned int count, addr; more = more && - read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) - break; + read_idm_word(data, size, &pos, &data1); more = more && - read_idm_word(data, size, &pos, &addr); - dev_dbg(dev->class_dev, - "Loading#%d %4.4x bytes at %4.4x\n", - i, count, addr); - while (more && count > 0) { - if (addr & 0x4000) { - /* 16 bit data, never seen - * in real life!! */ - unsigned int data1; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - count--; - /* jr3[addr + 0x20000 * pnum] = - data1; */ - } else { - /* Download 24 bit program */ - unsigned int data1, data2; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - more = more && - read_idm_word(data, size, - &pos, - &data2); - count -= 2; - if (more) { - set_u16(&p-> - iobase->channel - [i].program_low - [addr], data1); - udelay(1); - set_u16(&p-> - iobase->channel - [i].program_high - [addr], data2); - udelay(1); - } - } - addr++; + read_idm_word(data, size, &pos, &data2); + count -= 2; + if (more) { + set_u16(lo, data1); + udelay(1); + set_u16(hi, data2); + udelay(1); } } + addr++; } } - return result; } -static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s) +static int jr3_download_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { - struct poll_delay_t result = poll_delay_min_max(1000, 2000); - struct jr3_pci_subdev_private *p = s->private; - int i; + int subdev; + int ret; - if (p) { - struct jr3_channel __iomem *channel = p->channel; - int errors = get_u16(&channel->errors); - - if (errors != p->errors) - p->errors = errors; - - if (errors & (watch_dog | watch_dog2 | sensor_change)) - /* Sensor communication lost, force poll mode */ - p->state = state_jr3_poll; - - switch (p->state) { - case state_jr3_poll: { - u16 model_no = get_u16(&channel->model_no); - u16 serial_no = get_u16(&channel->serial_no); - if ((errors & (watch_dog | watch_dog2)) || - model_no == 0 || serial_no == 0) { - /* - * Still no sensor, keep on polling. - * Since it takes up to 10 seconds - * for offsets to stabilize, polling - * each second should suffice. - */ - result = poll_delay_min_max(1000, 2000); - } else { - p->retries = 0; - p->state = - state_jr3_init_wait_for_offset; - result = poll_delay_min_max(1000, 2000); - } - } - break; - case state_jr3_init_wait_for_offset: - p->retries++; - if (p->retries < 10) { - /* Wait for offeset to stabilize - * (< 10 s according to manual) */ - result = poll_delay_min_max(1000, 2000); - } else { - struct transform_t transf; + /* verify IDM file format */ + ret = jr3_check_firmware(dev, data, size); + if (ret) + return ret; - p->model_no = get_u16(&channel->model_no); - p->serial_no = get_u16(&channel->serial_no); + /* write firmware to each subdevice */ + for (subdev = 0; subdev < dev->n_subdevices; subdev++) + jr3_write_firmware(dev, subdev, data, size); - /* Transformation all zeros */ - for (i = 0; i < ARRAY_SIZE(transf.link); i++) { - transf.link[i].link_type = - (enum link_types)0; - transf.link[i].link_amount = 0; - } + return 0; +} - set_transforms(channel, transf, 0); - use_transform(channel, 0); - p->state = state_jr3_init_transform_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_transform_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - /* Set full scale */ - struct six_axis_t min_full_scale; - struct six_axis_t max_full_scale; - - min_full_scale = get_min_full_scales(channel); - max_full_scale = get_max_full_scales(channel); - set_full_scales(channel, max_full_scale); - - p->state = - state_jr3_init_set_full_scale_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_set_full_scale_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - struct force_array __iomem *full_scale; - - /* Use ranges in kN or we will - * overflow around 2000N! */ - full_scale = &channel->full_scale; - p->range[0].range.min = - -get_s16(&full_scale->fx) * 1000; - p->range[0].range.max = - get_s16(&full_scale->fx) * 1000; - p->range[1].range.min = - -get_s16(&full_scale->fy) * 1000; - p->range[1].range.max = - get_s16(&full_scale->fy) * 1000; - p->range[2].range.min = - -get_s16(&full_scale->fz) * 1000; - p->range[2].range.max = - get_s16(&full_scale->fz) * 1000; - p->range[3].range.min = - -get_s16(&full_scale->mx) * 100; - p->range[3].range.max = - get_s16(&full_scale->mx) * 100; - p->range[4].range.min = - -get_s16(&full_scale->my) * 100; - p->range[4].range.max = - get_s16(&full_scale->my) * 100; - p->range[5].range.min = - -get_s16(&full_scale->mz) * 100; - p->range[5].range.max = - get_s16(&full_scale->mz) * 100; /* ?? */ - p->range[6].range.min = - -get_s16(&full_scale->v1) * 100;/* ?? */ - p->range[6].range.max = - get_s16(&full_scale->v1) * 100; /* ?? */ - p->range[7].range.min = - -get_s16(&full_scale->v2) * 100;/* ?? */ - p->range[7].range.max = - get_s16(&full_scale->v2) * 100; /* ?? */ - p->range[8].range.min = 0; - p->range[8].range.max = 65535; - - use_offset(channel, 0); - p->state = state_jr3_init_use_offset_complete; - /* Allow 40 ms for completion */ - result = poll_delay_min_max(40, 100); - } - break; - case state_jr3_init_use_offset_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - set_s16(&channel->offsets.fx, 0); - set_s16(&channel->offsets.fy, 0); - set_s16(&channel->offsets.fz, 0); - set_s16(&channel->offsets.mx, 0); - set_s16(&channel->offsets.my, 0); - set_s16(&channel->offsets.mz, 0); +static struct jr3_pci_poll_delay jr3_pci_poll_subdevice(struct comedi_subdevice *s) +{ + struct jr3_pci_subdev_private *spriv = s->private; + struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000); + struct jr3_channel __iomem *channel; + u16 model_no; + u16 serial_no; + int errors; + int i; - set_offset(channel); + if (!spriv) + return result; - p->state = state_jr3_done; + channel = spriv->channel; + errors = get_u16(&channel->errors); + + if (errors != spriv->errors) + spriv->errors = errors; + + /* Sensor communication lost? force poll mode */ + if (errors & (watch_dog | watch_dog2 | sensor_change)) + spriv->state = state_jr3_poll; + + switch (spriv->state) { + case state_jr3_poll: + model_no = get_u16(&channel->model_no); + serial_no = get_u16(&channel->serial_no); + + if ((errors & (watch_dog | watch_dog2)) || + model_no == 0 || serial_no == 0) { + /* + * Still no sensor, keep on polling. + * Since it takes up to 10 seconds for offsets to + * stabilize, polling each second should suffice. + */ + } else { + spriv->retries = 0; + spriv->state = state_jr3_init_wait_for_offset; + } + break; + case state_jr3_init_wait_for_offset: + spriv->retries++; + if (spriv->retries < 10) { + /* + * Wait for offeset to stabilize + * (< 10 s according to manual) + */ + } else { + struct jr3_pci_transform transf; + + spriv->model_no = get_u16(&channel->model_no); + spriv->serial_no = get_u16(&channel->serial_no); + + /* Transformation all zeros */ + for (i = 0; i < ARRAY_SIZE(transf.link); i++) { + transf.link[i].link_type = (enum link_types)0; + transf.link[i].link_amount = 0; } - break; - case state_jr3_done: - poll_delay_min_max(10000, 20000); - break; - default: - poll_delay_min_max(1000, 2000); - break; + + set_transforms(channel, transf, 0); + use_transform(channel, 0); + spriv->state = state_jr3_init_transform_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_transform_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + /* Set full scale */ + struct six_axis_t min_full_scale; + struct six_axis_t max_full_scale; + + min_full_scale = get_min_full_scales(channel); + max_full_scale = get_max_full_scales(channel); + set_full_scales(channel, max_full_scale); + + spriv->state = state_jr3_init_set_full_scale_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_set_full_scale_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + struct force_array __iomem *fs = &channel->full_scale; + + /* Use ranges in kN or we will overflow around 2000N! */ + spriv->range[0].range.min = -get_s16(&fs->fx) * 1000; + spriv->range[0].range.max = get_s16(&fs->fx) * 1000; + spriv->range[1].range.min = -get_s16(&fs->fy) * 1000; + spriv->range[1].range.max = get_s16(&fs->fy) * 1000; + spriv->range[2].range.min = -get_s16(&fs->fz) * 1000; + spriv->range[2].range.max = get_s16(&fs->fz) * 1000; + spriv->range[3].range.min = -get_s16(&fs->mx) * 100; + spriv->range[3].range.max = get_s16(&fs->mx) * 100; + spriv->range[4].range.min = -get_s16(&fs->my) * 100; + spriv->range[4].range.max = get_s16(&fs->my) * 100; + spriv->range[5].range.min = -get_s16(&fs->mz) * 100; + /* the next five are questionable */ + spriv->range[5].range.max = get_s16(&fs->mz) * 100; + spriv->range[6].range.min = -get_s16(&fs->v1) * 100; + spriv->range[6].range.max = get_s16(&fs->v1) * 100; + spriv->range[7].range.min = -get_s16(&fs->v2) * 100; + spriv->range[7].range.max = get_s16(&fs->v2) * 100; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65535; + + use_offset(channel, 0); + spriv->state = state_jr3_init_use_offset_complete; + /* Allow 40 ms for completion */ + result = poll_delay_min_max(40, 100); + } + break; + case state_jr3_init_use_offset_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + set_s16(&channel->offsets.fx, 0); + set_s16(&channel->offsets.fy, 0); + set_s16(&channel->offsets.fz, 0); + set_s16(&channel->offsets.mx, 0); + set_s16(&channel->offsets.my, 0); + set_s16(&channel->offsets.mz, 0); + + set_offset(channel); + + spriv->state = state_jr3_done; } + break; + case state_jr3_done: + result = poll_delay_min_max(10000, 20000); + break; + default: + break; } + return result; } static void jr3_pci_poll_dev(unsigned long data) { - unsigned long flags; struct comedi_device *dev = (struct comedi_device *)data; struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + unsigned long flags; unsigned long now; int delay; int i; @@ -597,18 +602,22 @@ static void jr3_pci_poll_dev(unsigned long data) spin_lock_irqsave(&dev->spinlock, flags); delay = 1000; now = jiffies; - /* Poll all channels that are ready to be polled */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *subdevpriv = - dev->subdevices[i].private; - if (now > subdevpriv->next_time_min) { - struct poll_delay_t sub_delay; - - sub_delay = jr3_pci_poll_subdevice(&dev->subdevices[i]); - subdevpriv->next_time_min = - jiffies + msecs_to_jiffies(sub_delay.min); - subdevpriv->next_time_max = - jiffies + msecs_to_jiffies(sub_delay.max); + + /* Poll all channels that are ready to be polled */ + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + + if (now > spriv->next_time_min) { + struct jr3_pci_poll_delay sub_delay; + + sub_delay = jr3_pci_poll_subdevice(s); + + spriv->next_time_min = jiffies + + msecs_to_jiffies(sub_delay.min); + spriv->next_time_max = jiffies + + msecs_to_jiffies(sub_delay.max); + if (sub_delay.max && sub_delay.max < delay) /* * Wake up as late as possible -> @@ -623,13 +632,58 @@ static void jr3_pci_poll_dev(unsigned long data) add_timer(&devpriv->timer); } +static struct jr3_pci_subdev_private * +jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + int j; + int k; + + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) + return NULL; + + spriv->channel = &devpriv->iobase->channel[s->index].data; + + for (j = 0; j < 8; j++) { + spriv->range[j].length = 1; + spriv->range[j].range.min = -1000000; + spriv->range[j].range.max = 1000000; + + for (k = 0; k < 7; k++) { + spriv->range_table_list[j + k * 8] = + (struct comedi_lrange *)&spriv->range[j]; + spriv->maxdata_list[j + k * 8] = 0x7fff; + } + } + spriv->range[8].length = 1; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65536; + + spriv->range_table_list[56] = (struct comedi_lrange *)&spriv->range[8]; + spriv->range_table_list[57] = (struct comedi_lrange *)&spriv->range[8]; + spriv->maxdata_list[56] = 0xffff; + spriv->maxdata_list[57] = 0xffff; + + dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", + spriv->channel, devpriv->iobase, + ((char __iomem *)spriv->channel - + (char __iomem *)devpriv->iobase)); + + return spriv; +} + static int jr3_pci_auto_attach(struct comedi_device *dev, - unsigned long context_unused) + unsigned long context) { - int result; struct pci_dev *pcidev = comedi_to_pci_dev(dev); - int i; + static const struct jr3_pci_board *board = NULL; struct jr3_pci_dev_private *devpriv; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + int ret; + int i; if (sizeof(struct jr3_channel) != 0xc00) { dev_err(dev->class_dev, @@ -638,107 +692,56 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, return -EINVAL; } - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (context < ARRAY_SIZE(jr3_pci_boards)) + board = &jr3_pci_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; init_timer(&devpriv->timer); - switch (pcidev->device) { - case PCI_DEVICE_ID_JR3_1_CHANNEL: - case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW: - devpriv->n_channels = 1; - break; - case PCI_DEVICE_ID_JR3_2_CHANNEL: - devpriv->n_channels = 2; - break; - case PCI_DEVICE_ID_JR3_3_CHANNEL: - devpriv->n_channels = 3; - break; - case PCI_DEVICE_ID_JR3_4_CHANNEL: - devpriv->n_channels = 4; - break; - default: - dev_err(dev->class_dev, "jr3_pci: pci %s not supported\n", - pci_name(pcidev)); - return -EINVAL; - break; - } - result = comedi_pci_enable(dev); - if (result) - return result; + ret = comedi_pci_enable(dev); + if (ret) + return ret; devpriv->iobase = pci_ioremap_bar(pcidev, 0); if (!devpriv->iobase) return -ENOMEM; - result = comedi_alloc_subdevices(dev, devpriv->n_channels); - if (result) - return result; + ret = comedi_alloc_subdevices(dev, board->n_subdevs); + if (ret) + return ret; dev->open = jr3_pci_open; - for (i = 0; i < devpriv->n_channels; i++) { - dev->subdevices[i].type = COMEDI_SUBD_AI; - dev->subdevices[i].subdev_flags = SDF_READABLE | SDF_GROUND; - dev->subdevices[i].n_chan = 8 * 7 + 2; - dev->subdevices[i].insn_read = jr3_pci_ai_insn_read; - dev->subdevices[i].private = - kzalloc(sizeof(struct jr3_pci_subdev_private), - GFP_KERNEL); - if (dev->subdevices[i].private) { - struct jr3_pci_subdev_private *p; - int j; - - p = dev->subdevices[i].private; - p->channel = &devpriv->iobase->channel[i].data; - dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", - p->channel, devpriv->iobase, - ((char __iomem *)p->channel - - (char __iomem *)devpriv->iobase)); - p->channel_no = i; - for (j = 0; j < 8; j++) { - int k; - - p->range[j].length = 1; - p->range[j].range.min = -1000000; - p->range[j].range.max = 1000000; - for (k = 0; k < 7; k++) { - p->range_table_list[j + k * 8] = - (struct comedi_lrange *)&p-> - range[j]; - p->maxdata_list[j + k * 8] = 0x7fff; - } - } - p->range[8].length = 1; - p->range[8].range.min = 0; - p->range[8].range.max = 65536; - - p->range_table_list[56] = - (struct comedi_lrange *)&p->range[8]; - p->range_table_list[57] = - (struct comedi_lrange *)&p->range[8]; - p->maxdata_list[56] = 0xffff; - p->maxdata_list[57] = 0xffff; - /* Channel specific range and maxdata */ - dev->subdevices[i].range_table = NULL; - dev->subdevices[i].range_table_list = - p->range_table_list; - dev->subdevices[i].maxdata = 0; - dev->subdevices[i].maxdata_list = p->maxdata_list; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8 * 7 + 2; + s->insn_read = jr3_pci_ai_insn_read; + + spriv = jr3_pci_alloc_spriv(dev, s); + if (spriv) { + /* Channel specific range and maxdata */ + s->range_table_list = spriv->range_table_list; + s->maxdata_list = spriv->maxdata_list; } } /* Reset DSP card */ writel(0, &devpriv->iobase->channel[0].reset); - result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, - "comedi/jr3pci.idm", - jr3_download_firmware, 0); - dev_dbg(dev->class_dev, "Firmare load %d\n", result); - - if (result < 0) - return result; + ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + "comedi/jr3pci.idm", + jr3_download_firmware, 0); + dev_dbg(dev->class_dev, "Firmare load %d\n", ret); + if (ret < 0) + return ret; /* * TODO: use firmware to load preferred offset tables. Suggested * format: @@ -761,11 +764,12 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, } /* Start card timer */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p = dev->subdevices[i].private; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; - p->next_time_min = jiffies + msecs_to_jiffies(500); - p->next_time_max = jiffies + msecs_to_jiffies(2000); + spriv->next_time_min = jiffies + msecs_to_jiffies(500); + spriv->next_time_max = jiffies + msecs_to_jiffies(2000); } devpriv->timer.data = (unsigned long)dev; @@ -773,21 +777,16 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, devpriv->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&devpriv->timer); - return result; + return 0; } static void jr3_pci_detach(struct comedi_device *dev) { - int i; struct jr3_pci_dev_private *devpriv = dev->private; if (devpriv) { del_timer_sync(&devpriv->timer); - if (dev->subdevices) { - for (i = 0; i < devpriv->n_channels; i++) - kfree(dev->subdevices[i].private); - } if (devpriv->iobase) iounmap(devpriv->iobase); } @@ -807,12 +806,12 @@ static int jr3_pci_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &jr3_pci_driver, id->driver_data); } -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) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) }, +static const struct pci_device_id jr3_pci_pci_table[] = { + { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, + { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, + { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, { 0 } }; MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index 3317f7a04c4..20478ae8fad 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.h +++ b/drivers/staging/comedi/drivers/jr3_pci.h @@ -671,11 +671,11 @@ struct jr3_channel { struct jr3_t { struct { - u32 program_low[0x4000]; /* 0x00000 - 0x10000 */ + u32 program_lo[0x4000]; /* 0x00000 - 0x10000 */ struct jr3_channel data; /* 0x10000 - 0x10c00 */ char pad2[0x30000 - 0x00c00]; /* 0x10c00 - 0x40000 */ - u32 program_high[0x8000]; /* 0x40000 - 0x60000 */ - u32 reset; /* 0x60000 - 0x60004 */ + u32 program_hi[0x8000]; /* 0x40000 - 0x60000 */ + u32 reset; /* 0x60000 - 0x60004 */ char pad3[0x20000 - 0x00004]; /* 0x60004 - 0x80000 */ } channel[4]; }; diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index f10cf10e5fe..ec43c38958d 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -1,91 +1,113 @@ /* - comedi/drivers/ke_counter.c - Comedi driver for Kolter-Electronic PCI Counter 1 Card - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ke_counter -Description: Driver for Kolter Electronic Counter Card -Devices: [Kolter Electronic] PCI Counter Card (ke_counter) -Author: Michael Hillmann -Updated: Mon, 14 Apr 2008 15:42:42 +0100 -Status: tested - -Configuration Options: not applicable, uses PCI auto config - -This driver is a simple driver to read the counter values from -Kolter Electronic PCI Counter Card. -*/ + * ke_counter.c + * Comedi driver for Kolter-Electronic PCI Counter 1 Card + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +/* + * Driver: ke_counter + * Description: Driver for Kolter Electronic Counter Card + * Devices: (Kolter Electronic) PCI Counter Card [ke_counter] + * Author: Michael Hillmann + * Updated: Mon, 14 Apr 2008 15:42:42 +0100 + * Status: tested + * + * Configuration Options: not applicable, uses PCI auto config + */ + +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" -#define CNT_CARD_DEVICE_ID 0x0014 +/* + * PCI BAR 0 Register I/O map + */ +#define KE_RESET_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LSB_REG(x) (0x04 + ((x) * 0x20)) +#define KE_MID_REG(x) (0x08 + ((x) * 0x20)) +#define KE_MSB_REG(x) (0x0c + ((x) * 0x20)) +#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20)) +#define KE_OSC_SEL_REG 0xf8 +#define KE_OSC_SEL_EXT (1 << 0) +#define KE_OSC_SEL_4MHZ (2 << 0) +#define KE_OSC_SEL_20MHZ (3 << 0) +#define KE_DO_REG 0xfc + +static int ke_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; -/*-- counter write ----------------------------------------------------------*/ + for (i = 0; i < insn->n; i++) { + val = data[0]; -/* This should be used only for resetting the counters; maybe it is better - to make a special command 'reset'. */ -static int cnt_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - - outb((unsigned char)((data[0] >> 24) & 0xff), - dev->iobase + chan * 0x20 + 0x10); - outb((unsigned char)((data[0] >> 16) & 0xff), - dev->iobase + chan * 0x20 + 0x0c); - outb((unsigned char)((data[0] >> 8) & 0xff), - dev->iobase + chan * 0x20 + 0x08); - outb((unsigned char)((data[0] >> 0) & 0xff), - dev->iobase + chan * 0x20 + 0x04); - - /* return the number of samples written */ - return 1; -} + /* Order matters */ + outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan)); + outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan)); + outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan)); + } -/*-- counter read -----------------------------------------------------------*/ + return insn->n; +} -static int cnt_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int ke_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char a0, a1, a2, a3, a4; - int chan = CR_CHAN(insn->chanspec); - int result; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - a0 = inb(dev->iobase + chan * 0x20); - a1 = inb(dev->iobase + chan * 0x20 + 0x04); - a2 = inb(dev->iobase + chan * 0x20 + 0x08); - a3 = inb(dev->iobase + chan * 0x20 + 0x0c); - a4 = inb(dev->iobase + chan * 0x20 + 0x10); + for (i = 0; i < insn->n; i++) { + /* Order matters */ + inb(dev->iobase + KE_LATCH_REG(chan)); - result = (a1 + (a2 * 256) + (a3 * 65536)); - if (a4 > 0) - result = result - s->maxdata; + val = inb(dev->iobase + KE_LSB_REG(chan)); + val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8); + val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16); + val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24); - *data = (unsigned int)result; + data[i] = val; + } - /* return the number of samples read */ - return 1; + return insn->n; } -static int cnt_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int ke_counter_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + KE_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int ke_counter_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct comedi_subdevice *s; @@ -96,30 +118,32 @@ static int cnt_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 0); - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; - - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; - s->n_chan = 3; - s->maxdata = 0x00ffffff; - s->insn_read = cnt_rinsn; - s->insn_write = cnt_winsn; - - /* select 20MHz clock */ - outb(3, dev->iobase + 248); - - /* reset all counters */ - outb(0, dev->iobase); - outb(0, dev->iobase + 0x20); - outb(0, dev->iobase + 0x40); - - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0x01ffffff; + s->range_table = &range_unknown; + s->insn_read = ke_counter_insn_read; + s->insn_write = ke_counter_insn_write; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ke_counter_do_insn_bits; + + outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG); + + outb(0, dev->iobase + KE_RESET_REG(0)); + outb(0, dev->iobase + KE_RESET_REG(1)); + outb(0, dev->iobase + KE_RESET_REG(2)); return 0; } @@ -127,7 +151,7 @@ static int cnt_auto_attach(struct comedi_device *dev, static struct comedi_driver ke_counter_driver = { .driver_name = "ke_counter", .module = THIS_MODULE, - .auto_attach = cnt_auto_attach, + .auto_attach = ke_counter_auto_attach, .detach = comedi_pci_disable, }; @@ -138,8 +162,8 @@ static int ke_counter_pci_probe(struct pci_dev *dev, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, +static const struct pci_device_id ke_counter_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) }, { 0 } }; MODULE_DEVICE_TABLE(pci, ke_counter_pci_table); @@ -153,5 +177,5 @@ static struct pci_driver ke_counter_pci_driver = { module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index c2308fd24d6..25ce2f78db8 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -40,6 +40,7 @@ broken. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -327,13 +328,12 @@ static const struct me4000_board me4000_boards[] = { }; static const struct comedi_lrange me4000_ai_range = { - 4, - { - UNI_RANGE(2.5), - UNI_RANGE(10), - BIP_RANGE(2.5), - BIP_RANGE(10), - } + 4, { + UNI_RANGE(2.5), + UNI_RANGE(10), + BIP_RANGE(2.5), + BIP_RANGE(10) + } }; #define FIRMWARE_NOT_AVAILABLE 1 @@ -426,7 +426,7 @@ static int xilinx_download(struct comedi_device *dev) static void me4000_reset(struct comedi_device *dev) { struct me4000_info *info = dev->private; - unsigned long val; + unsigned int val; int chan; /* Make a hardware reset */ @@ -479,9 +479,9 @@ static int me4000_ai_insn_read(struct comedi_device *dev, int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); - unsigned long entry = 0; - unsigned long tmp; - long lval; + unsigned int entry = 0; + unsigned int tmp; + unsigned int lval; if (insn->n == 0) { return 0; @@ -585,7 +585,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, static int me4000_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned long tmp; + unsigned int tmp; /* Stop any running conversion */ tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); @@ -598,67 +598,35 @@ static int me4000_ai_cancel(struct comedi_device *dev, return 0; } -static int ai_check_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int me4000_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - const struct me4000_board *thisboard = comedi_board(dev); - int aref; + const struct me4000_board *board = comedi_board(dev); + unsigned int max_diff_chan = board->ai_diff_nchan; + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; - /* Check whether a channel list is available */ - if (!cmd->chanlist_len) { - dev_err(dev->class_dev, "No channel list available\n"); - return -EINVAL; - } - - /* Check the channel list size */ - if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) { - dev_err(dev->class_dev, "Channel list is to large\n"); - return -EINVAL; - } - - /* Check the pointer */ - if (!cmd->chanlist) { - dev_err(dev->class_dev, "NULL pointer to channel list\n"); - return -EFAULT; - } - - /* Check whether aref is equal for all entries */ - aref = CR_AREF(cmd->chanlist[0]); for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_AREF(cmd->chanlist[i]) != aref) { - dev_err(dev->class_dev, + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (aref != aref0) { + dev_dbg(dev->class_dev, "Mode is not equal for all entries\n"); return -EINVAL; } - } - /* Check whether channels are available for this ending */ - if (aref == SDF_DIFF) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= - thisboard->ai_diff_nchan) { - dev_err(dev->class_dev, - "Channel number to high\n"); - return -EINVAL; - } - } - } else { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) { - dev_err(dev->class_dev, + if (aref == SDF_DIFF) { + if (chan >= max_diff_chan) { + dev_dbg(dev->class_dev, "Channel number to high\n"); return -EINVAL; } - } - } - /* Check if bipolar is set for all entries when in differential mode */ - if (aref == SDF_DIFF) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_RANGE(cmd->chanlist[i]) != 1 && - CR_RANGE(cmd->chanlist[i]) != 2) { - dev_err(dev->class_dev, + if (!comedi_range_is_bipolar(s, range)) { + dev_dbg(dev->class_dev, "Bipolar is not selected in differential mode\n"); return -EINVAL; } @@ -782,7 +750,7 @@ static int ai_prepare(struct comedi_device *dev, unsigned int scan_ticks, unsigned int chan_ticks) { - unsigned long tmp = 0; + unsigned int tmp = 0; /* Write timer arguments */ ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks); @@ -934,22 +902,13 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, err |= -EINVAL; } - if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) { - } else if (cmd->stop_src == TRIG_COUNT && - cmd->scan_end_src == TRIG_NONE) { - } else if (cmd->stop_src == TRIG_NONE && - cmd->scan_end_src == TRIG_COUNT) { - } else if (cmd->stop_src == TRIG_COUNT && - cmd->scan_end_src == TRIG_COUNT) { - } else { - err |= -EINVAL; - } - if (err) return 2; /* Step 3: check if arguments are trivially valid */ + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + if (cmd->chanlist_len < 1) { cmd->chanlist_len = 1; err |= -EINVAL; @@ -1091,10 +1050,11 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, if (err) return 4; - /* - * Stage 5. Check the channel list. - */ - if (ai_check_chanlist(dev, s, cmd)) + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= me4000_ai_check_chanlist(dev, s, cmd); + + if (err) return 5; return 0; @@ -1104,23 +1064,14 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) { unsigned int tmp; struct comedi_device *dev = dev_id; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; int i; int c = 0; - long lval; + unsigned int lval; if (!dev->attached) return IRQ_NONE; - /* Reset all events */ - s->async->events = 0; - - /* Check if irq number is right */ - if (irq != dev->irq) { - dev_err(dev->class_dev, "Incorrect interrupt num: %d\n", irq); - return IRQ_HANDLED; - } - if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { /* Read status register to find out what happened */ @@ -1173,7 +1124,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; - if (!comedi_buf_put(s->async, lval)) { + if (!comedi_buf_put(s, lval)) { /* * Buffer overflow, so stop conversion * and disable all interrupts @@ -1218,7 +1169,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; - if (!comedi_buf_put(s->async, lval)) { + if (!comedi_buf_put(s, lval)) { dev_err(dev->class_dev, "Buffer overflow\n"); s->async->events |= COMEDI_CB_OVERFLOW; break; @@ -1251,7 +1202,7 @@ static int me4000_ao_insn_write(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); - unsigned long tmp; + unsigned int tmp; if (insn->n == 0) { return 0; @@ -1312,29 +1263,12 @@ static int me4000_ao_insn_read(struct comedi_device *dev, return 1; } -/*============================================================================= - Digital I/O section - ===========================================================================*/ - static int me4000_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* - * The insn data consists of a mask in data[0] and the new data - * in data[1]. The mask defines which bits we are concerning about. - * The new data must be anded with the mask. - * Each channel corresponds to a bit. - */ - if (data[0]) { - /* Check if requested ports are configured for output */ - if ((s->io_bits & data[0]) != data[0]) - return -EIO; - - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - - /* Write out the new digital output lines */ + if (comedi_dio_update_state(s, data)) { outl((s->state >> 0) & 0xFF, dev->iobase + ME4000_DIO_PORT_0_REG); outl((s->state >> 8) & 0xFF, @@ -1345,8 +1279,6 @@ static int me4000_dio_insn_bits(struct comedi_device *dev, dev->iobase + ME4000_DIO_PORT_3_REG); } - /* On return, data[1] contains the value of - the digital input and output lines. */ data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) | ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) | ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) | @@ -1357,98 +1289,57 @@ static int me4000_dio_insn_bits(struct comedi_device *dev, static int me4000_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned long tmp; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + unsigned int tmp; + int ret; - switch (data[0]) { - default: - return -EINVAL; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - case INSN_CONFIG_DIO_INPUT: - case INSN_CONFIG_DIO_OUTPUT: - break; - } + if (chan < 8) + mask = 0x000000ff; + else if (chan < 16) + mask = 0x0000ff00; + else if (chan < 24) + mask = 0x00ff0000; + else + mask = 0xff000000; - /* - * The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT. - * On the ME-4000 it is only possible to switch port wise (8 bit) - */ + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG); + tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | ME4000_DIO_CTRL_BIT_MODE_1 | + ME4000_DIO_CTRL_BIT_MODE_2 | ME4000_DIO_CTRL_BIT_MODE_3 | + ME4000_DIO_CTRL_BIT_MODE_4 | ME4000_DIO_CTRL_BIT_MODE_5 | + ME4000_DIO_CTRL_BIT_MODE_6 | ME4000_DIO_CTRL_BIT_MODE_7); + if (s->io_bits & 0x000000ff) + tmp |= ME4000_DIO_CTRL_BIT_MODE_0; + if (s->io_bits & 0x0000ff00) + tmp |= ME4000_DIO_CTRL_BIT_MODE_2; + if (s->io_bits & 0x00ff0000) + tmp |= ME4000_DIO_CTRL_BIT_MODE_4; + if (s->io_bits & 0xff000000) + tmp |= ME4000_DIO_CTRL_BIT_MODE_6; - if (data[0] == INSN_CONFIG_DIO_OUTPUT) { - if (chan < 8) { - s->io_bits |= 0xFF; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | - ME4000_DIO_CTRL_BIT_MODE_1); - tmp |= ME4000_DIO_CTRL_BIT_MODE_0; - } else if (chan < 16) { - /* - * Chech for optoisolated ME-4000 version. - * If one the first port is a fixed output - * port and the second is a fixed input port. - */ - if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) - return -ENODEV; - - s->io_bits |= 0xFF00; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | - ME4000_DIO_CTRL_BIT_MODE_3); - tmp |= ME4000_DIO_CTRL_BIT_MODE_2; - } else if (chan < 24) { - s->io_bits |= 0xFF0000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 | - ME4000_DIO_CTRL_BIT_MODE_5); - tmp |= ME4000_DIO_CTRL_BIT_MODE_4; - } else if (chan < 32) { - s->io_bits |= 0xFF000000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 | - ME4000_DIO_CTRL_BIT_MODE_7); - tmp |= ME4000_DIO_CTRL_BIT_MODE_6; - } else { - return -EINVAL; - } - } else { - if (chan < 8) { - /* - * Chech for optoisolated ME-4000 version. - * If one the first port is a fixed output - * port and the second is a fixed input port. - */ - if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) - return -ENODEV; - - s->io_bits &= ~0xFF; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | - ME4000_DIO_CTRL_BIT_MODE_1); - } else if (chan < 16) { - s->io_bits &= ~0xFF00; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | - ME4000_DIO_CTRL_BIT_MODE_3); - } else if (chan < 24) { - s->io_bits &= ~0xFF0000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 | - ME4000_DIO_CTRL_BIT_MODE_5); - } else if (chan < 32) { - s->io_bits &= ~0xFF000000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 | - ME4000_DIO_CTRL_BIT_MODE_7); - } else { - return -EINVAL; - } + /* + * Check for optoisolated ME-4000 version. + * If one the first port is a fixed output + * port and the second is a fixed input port. + */ + if (inl(dev->iobase + ME4000_DIO_DIR_REG)) { + s->io_bits |= 0x000000ff; + s->io_bits &= ~0x0000ff00; + tmp |= ME4000_DIO_CTRL_BIT_MODE_0; + tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | + ME4000_DIO_CTRL_BIT_MODE_3); } outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG); - return 1; + return insn->n; } /*============================================================================= @@ -1461,6 +1352,7 @@ static int me4000_cnt_insn_config(struct comedi_device *dev, unsigned int *data) { struct me4000_info *info = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int err; switch (data[0]) { @@ -1468,16 +1360,17 @@ static int me4000_cnt_insn_config(struct comedi_device *dev, if (insn->n != 1) return -EINVAL; - err = i8254_load(info->timer_regbase, 0, insn->chanspec, 0, - I8254_MODE0 | I8254_BINARY); + err = i8254_set_mode(info->timer_regbase, 0, chan, + I8254_MODE0 | I8254_BINARY); if (err) return err; + i8254_write(info->timer_regbase, 0, chan, 0); break; case GPCT_SET_OPERATION: if (insn->n != 2) return -EINVAL; - err = i8254_set_mode(info->timer_regbase, 0, insn->chanspec, + err = i8254_set_mode(info->timer_regbase, 0, chan, (data[1] << 1) | I8254_BINARY); if (err) return err; @@ -1544,10 +1437,9 @@ static int me4000_auto_attach(struct comedi_device *dev, dev->board_ptr = thisboard; dev->board_name = thisboard->name; - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = comedi_alloc_devpriv(dev, sizeof(*info)); if (!info) return -ENOMEM; - dev->private = info; result = comedi_pci_enable(dev); if (result) @@ -1565,6 +1457,13 @@ static int me4000_auto_attach(struct comedi_device *dev, me4000_reset(dev); + if (pcidev->irq > 0) { + result = request_irq(pcidev->irq, me4000_ai_isr, IRQF_SHARED, + dev->board_name, dev); + if (result == 0) + dev->irq = pcidev->irq; + } + result = comedi_alloc_subdevices(dev, 4); if (result) return result; @@ -1585,22 +1484,12 @@ static int me4000_auto_attach(struct comedi_device *dev, s->range_table = &me4000_ai_range; s->insn_read = me4000_ai_insn_read; - if (pcidev->irq > 0) { - if (request_irq(pcidev->irq, me4000_ai_isr, - IRQF_SHARED, dev->board_name, dev)) { - dev_warn(dev->class_dev, - "request_irq failed\n"); - } else { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = me4000_ai_cancel; - s->do_cmdtest = me4000_ai_do_cmd_test; - s->do_cmd = me4000_ai_do_cmd; - - dev->irq = pcidev->irq; - } - } else { - dev_warn(dev->class_dev, "No interrupt available\n"); + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->cancel = me4000_ai_cancel; + s->do_cmdtest = me4000_ai_do_cmd_test; + s->do_cmd = me4000_ai_do_cmd; } } else { s->type = COMEDI_SUBD_UNUSED; @@ -1695,7 +1584,7 @@ static int me4000_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &me4000_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { +static const struct pci_device_id me4000_pci_table[] = { { PCI_VDEVICE(MEILHAUS, 0x4650), BOARD_ME4650 }, { PCI_VDEVICE(MEILHAUS, 0x4660), BOARD_ME4660 }, { PCI_VDEVICE(MEILHAUS, 0x4661), BOARD_ME4660I }, diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 7533ece3670..0ff126b1fdf 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -30,6 +30,7 @@ * Analog Input, Analog Output, Digital I/O */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/sched.h> @@ -185,38 +186,30 @@ static int me_dio_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct me_private_data *dev_private = dev->private; - unsigned int mask = 1 << CR_CHAN(insn->chanspec); - unsigned int bits; - unsigned int port; + struct me_private_data *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; - if (mask & 0x0000ffff) { - bits = 0x0000ffff; - port = ENABLE_PORT_A; - } else { - bits = 0xffff0000; - port = ENABLE_PORT_B; - } + if (chan < 16) + mask = 0x0000ffff; + else + mask = 0xffff0000; - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - dev_private->control_2 &= ~port; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - dev_private->control_2 |= port; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - /* Update the port configuration */ - writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2); + if (s->io_bits & 0x0000ffff) + devpriv->control_2 |= ENABLE_PORT_A; + else + devpriv->control_2 &= ~ENABLE_PORT_A; + if (s->io_bits & 0xffff0000) + devpriv->control_2 |= ENABLE_PORT_B; + else + devpriv->control_2 &= ~ENABLE_PORT_B; + + writew(devpriv->control_2, devpriv->me_regbase + ME_CONTROL_2); return insn->n; } @@ -229,15 +222,11 @@ static int me_dio_insn_bits(struct comedi_device *dev, struct me_private_data *dev_private = dev->private; void __iomem *mmio_porta = dev_private->me_regbase + ME_DIO_PORT_A; void __iomem *mmio_portb = dev_private->me_regbase + ME_DIO_PORT_B; - unsigned int mask = data[0]; - unsigned int bits = data[1]; + unsigned int mask; unsigned int val; - mask &= s->io_bits; /* only update the COMEDI_OUTPUT channels */ + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - if (mask & 0x0000ffff) writew((s->state & 0xffff), mmio_porta); if (mask & 0xffff0000) @@ -259,6 +248,20 @@ static int me_dio_insn_bits(struct comedi_device *dev, return insn->n; } +static int me_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct me_private_data *dev_private = dev->private; + unsigned int status; + + status = readw(dev_private->me_regbase + ME_STATUS); + if ((status & 0x0004) == 0) + return 0; + return -EBUSY; +} + static int me_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -269,7 +272,7 @@ static int me_ai_insn_read(struct comedi_device *dev, unsigned int rang = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned short val; - int i; + int ret; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -301,19 +304,14 @@ static int me_ai_insn_read(struct comedi_device *dev, readw(dev_private->me_regbase + ME_ADC_START); /* wait for ADC fifo not empty flag */ - for (i = 100000; i > 0; i--) - if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004)) - break; + ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); + if (ret) + return ret; /* get value from ADC fifo */ - if (i) { - val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); - val = (val ^ 0x800) & 0x0fff; - data[0] = val; - } else { - dev_err(dev->class_dev, "Cannot get single value\n"); - return -EIO; - } + val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); + val = (val ^ 0x800) & 0x0fff; + data[0] = val; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -490,10 +488,9 @@ static int me_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - dev_private = kzalloc(sizeof(*dev_private), GFP_KERNEL); + dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); if (!dev_private) return -ENOMEM; - dev->private = dev_private; ret = comedi_pci_enable(dev); if (ret) @@ -553,10 +550,6 @@ static int me_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = me_dio_insn_bits; s->insn_config = me_dio_insn_config; - s->io_bits = 0; - - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); return 0; } @@ -589,7 +582,7 @@ static int me_daq_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &me_daq_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = { +static const struct pci_device_id me_daq_pci_table[] = { { PCI_VDEVICE(MEILHAUS, 0x2600), BOARD_ME2600 }, { PCI_VDEVICE(MEILHAUS, 0x2000), BOARD_ME2000 }, { 0 } diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c new file mode 100644 index 00000000000..a4f7d6f138d --- /dev/null +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -0,0 +1,351 @@ +/* + * comedi/drivers/mf6x4.c + * Driver for Humusoft MF634 and MF624 Data acquisition cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +/* + * Driver: mf6x4 + * Description: Humusoft MF634 and MF624 Data acquisition card driver + * Devices: Humusoft MF634, Humusoft MF624 + * Author: Rostislav Lisovy <lisovy@gmail.com> + * Status: works + * Updated: + * Configuration Options: none + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include "../comedidev.h" + +/* Registers present in BAR0 memory region */ +#define MF624_GPIOC_R 0x54 + +#define MF6X4_GPIOC_EOLC /* End Of Last Conversion */ (1 << 17) +#define MF6X4_GPIOC_LDAC /* Load DACs */ (1 << 23) +#define MF6X4_GPIOC_DACEN (1 << 26) + +/* BAR1 registers */ +#define MF6X4_DIN_R 0x10 +#define MF6X4_DIN_M 0xff +#define MF6X4_DOUT_R 0x10 +#define MF6X4_DOUT_M 0xff + +#define MF6X4_ADSTART_R 0x20 +#define MF6X4_ADDATA_R 0x00 +#define MF6X4_ADCTRL_R 0x00 +#define MF6X4_ADCTRL_M 0xff + +#define MF6X4_DA0_R 0x20 +#define MF6X4_DA1_R 0x22 +#define MF6X4_DA2_R 0x24 +#define MF6X4_DA3_R 0x26 +#define MF6X4_DA4_R 0x28 +#define MF6X4_DA5_R 0x2a +#define MF6X4_DA6_R 0x2c +#define MF6X4_DA7_R 0x2e +/* Map DAC cahnnel id to real HW-dependent offset value */ +#define MF6X4_DAC_R(x) (0x20 + ((x) * 2)) +#define MF6X4_DA_M 0x3fff + +/* BAR2 registers */ +#define MF634_GPIOC_R 0x68 + +enum mf6x4_boardid { + BOARD_MF634, + BOARD_MF624, +}; + +struct mf6x4_board { + const char *name; + unsigned int bar_nums[3]; /* We need to keep track of the + order of BARs used by the cards */ +}; + +static const struct mf6x4_board mf6x4_boards[] = { + [BOARD_MF634] = { + .name = "mf634", + .bar_nums = {0, 2, 3}, + }, + [BOARD_MF624] = { + .name = "mf624", + .bar_nums = {0, 2, 4}, + }, +}; + +struct mf6x4_private { + /* + * Documentation for both MF634 and MF624 describes registers + * present in BAR0, 1 and 2 regions. + * The real (i.e. in HW) BAR numbers are different for MF624 + * and MF634 yet we will call them 0, 1, 2 + */ + void __iomem *bar0_mem; + void __iomem *bar1_mem; + void __iomem *bar2_mem; + + /* + * This configuration register has the same function and fields + * for both cards however it lies in different BARs on different + * offsets -- this variable makes the access easier + */ + void __iomem *gpioc_R; + + /* DAC value cache -- used for insn_read function */ + int ao_readback[8]; +}; + +static int mf6x4_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + + data[1] = ioread16(devpriv->bar1_mem + MF6X4_DIN_R) & MF6X4_DIN_M; + + return insn->n; +} + +static int mf6x4_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + + if (comedi_dio_update_state(s, data)) + iowrite16(s->state & MF6X4_DOUT_M, + devpriv->bar1_mem + MF6X4_DOUT_R); + + data[1] = s->state; + + return insn->n; +} + +static int mf6x4_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct mf6x4_private *devpriv = dev->private; + unsigned int status; + + status = ioread32(devpriv->gpioc_R); + if (status & MF6X4_GPIOC_EOLC) + return 0; + return -EBUSY; +} + +static int mf6x4_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + int chan = CR_CHAN(insn->chanspec); + int ret; + int i; + int d; + + /* Set the ADC channel number in the scan list */ + iowrite16((1 << chan) & MF6X4_ADCTRL_M, + devpriv->bar1_mem + MF6X4_ADCTRL_R); + + for (i = 0; i < insn->n; i++) { + /* Trigger ADC conversion by reading ADSTART */ + ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R); + + ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0); + if (ret) + return ret; + + /* Read the actual value */ + d = ioread16(devpriv->bar1_mem + MF6X4_ADDATA_R); + d &= s->maxdata; + data[i] = d; + } + + iowrite16(0x0, devpriv->bar1_mem + MF6X4_ADCTRL_R); + + return insn->n; +} + +static int mf6x4_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + uint32_t gpioc; + int i; + + /* Enable instantaneous update of converters outputs + Enable DACs */ + gpioc = ioread32(devpriv->gpioc_R); + iowrite32((gpioc & ~MF6X4_GPIOC_LDAC) | MF6X4_GPIOC_DACEN, + devpriv->gpioc_R); + + for (i = 0; i < insn->n; i++) { + iowrite16(data[i] & MF6X4_DA_M, + devpriv->bar1_mem + MF6X4_DAC_R(chan)); + + devpriv->ao_readback[chan] = data[i]; + } + + return insn->n; +} + +static int mf6x4_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct mf6x4_board *board = NULL; + struct mf6x4_private *devpriv; + struct comedi_subdevice *s; + int ret; + + if (context < ARRAY_SIZE(mf6x4_boards)) + board = &mf6x4_boards[context]; + else + return -ENODEV; + + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + devpriv->bar0_mem = pci_ioremap_bar(pcidev, board->bar_nums[0]); + if (!devpriv->bar0_mem) + return -ENODEV; + + devpriv->bar1_mem = pci_ioremap_bar(pcidev, board->bar_nums[1]); + if (!devpriv->bar1_mem) + return -ENODEV; + + devpriv->bar2_mem = pci_ioremap_bar(pcidev, board->bar_nums[2]); + if (!devpriv->bar2_mem) + return -ENODEV; + + if (board == &mf6x4_boards[BOARD_MF634]) + devpriv->gpioc_R = devpriv->bar2_mem + MF634_GPIOC_R; + else + devpriv->gpioc_R = devpriv->bar0_mem + MF624_GPIOC_R; + + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* ADC */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = 0x3fff; /* 14 bits ADC */ + s->range_table = &range_bipolar10; + s->insn_read = mf6x4_ai_insn_read; + + /* DAC */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 0x3fff; /* 14 bits DAC */ + s->range_table = &range_bipolar10; + s->insn_write = mf6x4_ao_insn_write; + s->insn_read = mf6x4_ao_insn_read; + + /* DIN */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = mf6x4_di_insn_bits; + + /* DOUT */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = mf6x4_do_insn_bits; + + return 0; +} + +static void mf6x4_detach(struct comedi_device *dev) +{ + struct mf6x4_private *devpriv = dev->private; + + if (devpriv->bar0_mem) + iounmap(devpriv->bar0_mem); + if (devpriv->bar1_mem) + iounmap(devpriv->bar1_mem); + if (devpriv->bar2_mem) + iounmap(devpriv->bar2_mem); + + comedi_pci_disable(dev); +} + +static struct comedi_driver mf6x4_driver = { + .driver_name = "mf6x4", + .module = THIS_MODULE, + .auto_attach = mf6x4_auto_attach, + .detach = mf6x4_detach, +}; + +static int mf6x4_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &mf6x4_driver, id->driver_data); +} + +static const struct pci_device_id mf6x4_pci_table[] = { + { PCI_VDEVICE(HUMUSOFT, 0x0634), BOARD_MF634 }, + { PCI_VDEVICE(HUMUSOFT, 0x0624), BOARD_MF624 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, mf6x4_pci_table); + +static struct pci_driver mf6x4_pci_driver = { + .name = "mf6x4", + .id_table = mf6x4_pci_table, + .probe = mf6x4_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; + +module_comedi_pci_driver(mf6x4_driver, mf6x4_pci_driver); + +MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>"); +MODULE_DESCRIPTION("Comedi MF634 and MF624 DAQ cards driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index 12c34db61d6..19c029acbc9 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -46,6 +46,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -287,7 +288,6 @@ void mite_dma_arm(struct mite_channel *mite_chan) int chor; unsigned long flags; - MDPRINTK("mite_dma_arm ch%i\n", mite_chan->channel); /* * memory barrier is intended to insure any twiddling with the buffer * is done before writing to the mite to arm dma transfer @@ -307,8 +307,9 @@ EXPORT_SYMBOL_GPL(mite_dma_arm); /**************************************/ int mite_buf_change(struct mite_dma_descriptor_ring *ring, - struct comedi_async *async) + struct comedi_subdevice *s) { + struct comedi_async *async = s->async; unsigned int n_links; int i; @@ -328,14 +329,12 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring, n_links = async->prealloc_bufsz >> PAGE_SHIFT; - MDPRINTK("ring->hw_dev=%p, n_links=0x%04x\n", ring->hw_dev, n_links); - ring->descriptors = dma_alloc_coherent(ring->hw_dev, n_links * sizeof(struct mite_dma_descriptor), &ring->descriptors_dma_addr, GFP_KERNEL); if (!ring->descriptors) { - dev_err(async->subdevice->device->class_dev, + dev_err(s->device->class_dev, "mite: ring buffer allocation failed\n"); return -ENOMEM; } @@ -344,7 +343,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring, for (i = 0; i < n_links; i++) { ring->descriptors[i].count = cpu_to_le32(PAGE_SIZE); ring->descriptors[i].addr = - cpu_to_le32(async->buf_page_list[i].dma_addr); + cpu_to_le32(async->buf_map->page_list[i].dma_addr); ring->descriptors[i].next = cpu_to_le32(ring->descriptors_dma_addr + (i + 1) * @@ -367,8 +366,6 @@ void mite_prep_dma(struct mite_channel *mite_chan, unsigned int chor, chcr, mcr, dcr, lkcr; struct mite_struct *mite = mite_chan->mite; - MDPRINTK("mite_prep_dma ch%i\n", mite_chan->channel); - /* reset DMA and FIFO */ chor = CHOR_DMARESET | CHOR_FRESET; writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); @@ -447,8 +444,6 @@ void mite_prep_dma(struct mite_channel *mite_chan, /* starting address for link chaining */ writel(mite_chan->ring->descriptors_dma_addr, mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); - - MDPRINTK("exit mite_prep_dma\n"); } EXPORT_SYMBOL_GPL(mite_prep_dma); @@ -514,8 +509,6 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan) lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); tcr = readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel)); - MDPRINTK("mite_dma_tcr ch%i, lkar=0x%08x tcr=%d\n", mite_chan->channel, - lkar, tcr); return tcr; } @@ -533,20 +526,20 @@ void mite_dma_disarm(struct mite_channel *mite_chan) EXPORT_SYMBOL_GPL(mite_dma_disarm); int mite_sync_input_dma(struct mite_channel *mite_chan, - struct comedi_async *async) + struct comedi_subdevice *s) { + struct comedi_async *async = s->async; int count; unsigned int nbytes, old_alloc_count; - const unsigned bytes_per_scan = cfc_bytes_per_scan(async->subdevice); old_alloc_count = async->buf_write_alloc_count; /* write alloc as much as we can */ - comedi_buf_write_alloc(async, async->prealloc_bufsz); + comedi_buf_write_alloc(s, async->prealloc_bufsz); nbytes = mite_bytes_written_to_memory_lb(mite_chan); if ((int)(mite_bytes_written_to_memory_ub(mite_chan) - old_alloc_count) > 0) { - dev_warn(async->subdevice->device->class_dev, + dev_warn(s->device->class_dev, "mite: DMA overwrite of free area\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; @@ -558,41 +551,33 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, if (count <= 0) return 0; - comedi_buf_write_free(async, count); - - async->scan_progress += count; - if (async->scan_progress >= bytes_per_scan) { - async->scan_progress %= bytes_per_scan; - async->events |= COMEDI_CB_EOS; - } + comedi_buf_write_free(s, count); + cfc_inc_scan_progress(s, count); async->events |= COMEDI_CB_BLOCK; return 0; } EXPORT_SYMBOL_GPL(mite_sync_input_dma); int mite_sync_output_dma(struct mite_channel *mite_chan, - struct comedi_async *async) + struct comedi_subdevice *s) { - int count; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + u32 stop_count = cmd->stop_arg * cfc_bytes_per_scan(s); + unsigned int old_alloc_count = async->buf_read_alloc_count; u32 nbytes_ub, nbytes_lb; - unsigned int old_alloc_count; - u32 stop_count = - async->cmd.stop_arg * cfc_bytes_per_scan(async->subdevice); + int count; - old_alloc_count = async->buf_read_alloc_count; /* read alloc as much as we can */ - comedi_buf_read_alloc(async, async->prealloc_bufsz); + comedi_buf_read_alloc(s, async->prealloc_bufsz); nbytes_lb = mite_bytes_read_from_memory_lb(mite_chan); - if (async->cmd.stop_src == TRIG_COUNT && - (int)(nbytes_lb - stop_count) > 0) + if (cmd->stop_src == TRIG_COUNT && (int)(nbytes_lb - stop_count) > 0) nbytes_lb = stop_count; nbytes_ub = mite_bytes_read_from_memory_ub(mite_chan); - if (async->cmd.stop_src == TRIG_COUNT && - (int)(nbytes_ub - stop_count) > 0) + if (cmd->stop_src == TRIG_COUNT && (int)(nbytes_ub - stop_count) > 0) nbytes_ub = stop_count; if ((int)(nbytes_ub - old_alloc_count) > 0) { - dev_warn(async->subdevice->device->class_dev, - "mite: DMA underrun\n"); + dev_warn(s->device->class_dev, "mite: DMA underrun\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; } @@ -601,7 +586,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan, return 0; if (count) { - comedi_buf_read_free(async, count); + comedi_buf_read_free(s, count); async->events |= COMEDI_CB_BLOCK; } return 0; @@ -641,140 +626,6 @@ int mite_done(struct mite_channel *mite_chan) } EXPORT_SYMBOL_GPL(mite_done); -#ifdef DEBUG_MITE - -/* names of bits in mite registers */ - -static const char *const mite_CHOR_strings[] = { - "start", "cont", "stop", "abort", - "freset", "clrlc", "clrrb", "clrdone", - "clr_lpause", "set_lpause", "clr_send_tc", - "set_send_tc", "12", "13", "14", - "15", "16", "17", "18", - "19", "20", "21", "22", - "23", "24", "25", "26", - "27", "28", "29", "30", - "dmareset", -}; - -static const char *const mite_CHCR_strings[] = { - "continue", "ringbuff", "2", "3", - "4", "5", "6", "7", - "8", "9", "10", "11", - "12", "13", "bursten", "fifodis", - "clr_cont_rb_ie", "set_cont_rb_ie", "clr_lc_ie", "set_lc_ie", - "clr_drdy_ie", "set_drdy_ie", "clr_mrdy_ie", "set_mrdy_ie", - "clr_done_ie", "set_done_ie", "clr_sar_ie", "set_sar_ie", - "clr_linkp_ie", "set_linkp_ie", "clr_dma_ie", "set_dma_ie", -}; - -static const char *const mite_MCR_strings[] = { - "amdevice", "1", "2", "3", - "4", "5", "portio", "portvxi", - "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "11", - "12", "13", "blocken", "berhand", - "reqsintlim/reqs0", "reqs1", "reqs2", "rd32", - "rd512", "rl1", "rl2", "rl8", - "24", "25", "26", "27", - "28", "29", "30", "stopen", -}; - -static const char *const mite_DCR_strings[] = { - "amdevice", "1", "2", "3", - "4", "5", "portio", "portvxi", - "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "aseqxp2", - "aseqxp8", "13", "blocken", "berhand", - "reqsintlim", "reqs1", "reqs2", "rd32", - "rd512", "rl1", "rl2", "rl8", - "23", "24", "25", "27", - "28", "wsdevc", "wsdevs", "rwdevpack", -}; - -static const char *const mite_LKCR_strings[] = { - "amdevice", "1", "2", "3", - "4", "5", "portio", "portvxi", - "psizebyte", "psizehalf (byte & half = word)", "asequp", "aseqdown", - "12", "13", "14", "berhand", - "16", "17", "18", "rd32", - "rd512", "rl1", "rl2", "rl8", - "24", "25", "26", "27", - "28", "29", "30", "chngend", -}; - -static const char *const mite_CHSR_strings[] = { - "d.err0", "d.err1", "m.err0", "m.err1", - "l.err0", "l.err1", "drq0", "drq1", - "end", "xferr", "operr0", "operr1", - "stops", "habort", "sabort", "error", - "16", "conts_rb", "18", "linkc", - "20", "drdy", "22", "mrdy", - "24", "done", "26", "sars", - "28", "lpauses", "30", "int", -}; - -static void mite_decode(const char *const *bit_str, unsigned int bits) -{ - int i; - - for (i = 31; i >= 0; i--) { - if (bits & (1 << i)) - pr_debug(" %s\n", bit_str[i]); - } -} - -void mite_dump_regs(struct mite_channel *mite_chan) -{ - void __iomem *mite_io_addr = mite_chan->mite->mite_io_addr; - unsigned int offset; - unsigned int value; - int channel = mite_chan->channel; - - pr_debug("mite_dump_regs ch%i\n", channel); - pr_debug("mite address is =%p\n", mite_io_addr); - - offset = MITE_CHOR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[CHOR] at 0x%08x =0x%08x\n", offset, value); - mite_decode(mite_CHOR_strings, value); - offset = MITE_CHCR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[CHCR] at 0x%08x =0x%08x\n", offset, value); - mite_decode(mite_CHCR_strings, value); - offset = MITE_TCR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[TCR] at 0x%08x =0x%08x\n", offset, value); - offset = MITE_MCR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[MCR] at 0x%08x =0x%08x\n", offset, value); - mite_decode(mite_MCR_strings, value); - offset = MITE_MAR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[MAR] at 0x%08x =0x%08x\n", offset, value); - offset = MITE_DCR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[DCR] at 0x%08x =0x%08x\n", offset, value); - mite_decode(mite_DCR_strings, value); - offset = MITE_DAR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[DAR] at 0x%08x =0x%08x\n", offset, value); - offset = MITE_LKCR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[LKCR] at 0x%08x =0x%08x\n", offset, value); - mite_decode(mite_LKCR_strings, value); - offset = MITE_LKAR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[LKAR] at 0x%08x =0x%08x\n", offset, value); - offset = MITE_CHSR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[CHSR] at 0x%08x =0x%08x\n", offset, value); - mite_decode(mite_CHSR_strings, value); - offset = MITE_FCR(channel); - value = readl(mite_io_addr + offset); - pr_debug("mite status[FCR] at 0x%08x =0x%08x\n", offset, value); -} -EXPORT_SYMBOL_GPL(mite_dump_regs); -#endif - static int __init mite_module_init(void) { return 0; diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index d4487e888e6..e6e58e989b7 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -21,23 +21,17 @@ #include <linux/pci.h> #include <linux/log2.h> +#include <linux/slab.h> #include "../comedidev.h" -/* #define DEBUG_MITE */ #define PCIMIO_COMPAT -#ifdef DEBUG_MITE -#define MDPRINTK(format, args...) pr_debug(format , ## args) -#else -#define MDPRINTK(format, args...) do { } while (0) -#endif - #define MAX_MITE_DMA_CHANNELS 8 struct mite_dma_descriptor { - u32 count; - u32 addr; - u32 next; + __le32 count; + __le32 addr; + __le32 next; u32 dar; }; @@ -112,9 +106,9 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan); void mite_dma_arm(struct mite_channel *mite_chan); void mite_dma_disarm(struct mite_channel *mite_chan); int mite_sync_input_dma(struct mite_channel *mite_chan, - struct comedi_async *async); + struct comedi_subdevice *s); int mite_sync_output_dma(struct mite_channel *mite_chan, - struct comedi_async *async); + struct comedi_subdevice *s); u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan); u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan); u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan); @@ -126,12 +120,7 @@ int mite_done(struct mite_channel *mite_chan); void mite_prep_dma(struct mite_channel *mite_chan, unsigned int num_device_bits, unsigned int num_memory_bits); int mite_buf_change(struct mite_dma_descriptor_ring *ring, - struct comedi_async *async); - -#ifdef DEBUG_MITE -void mite_print_chsr(unsigned int chsr); -void mite_dump_regs(struct mite_channel *mite_chan); -#endif + struct comedi_subdevice *s); static inline int CHAN_OFFSET(int channel) { diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index 713842ad6ff..f770400a0e8 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -51,9 +51,9 @@ Configuration Options: 1 -10.1V .. +10.1V */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> /* Consecutive I/O port addresses */ @@ -142,8 +142,18 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { } }; -/* Timeout 200ms */ -#define TIMEOUT 200 +static int mpc624_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + MPC624_ADC); + if ((status & MPC624_ADBUSY) == 0) + return 0; + return -EBUSY; +} static int mpc624_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -152,18 +162,13 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, struct mpc624_private *devpriv = dev->private; int n, i; unsigned long int data_in, data_out; - unsigned char ucPort; + int ret; /* * WARNING: * We always write 0 to GNSWA bit, so the channel range is +-/10.1Vdc */ outb(insn->chanspec, dev->iobase + MPC624_GNMUXCH); -/* printk("Channel %d:\n", insn->chanspec); */ - if (!insn->n) { - printk(KERN_INFO "MPC624: Warning, no data to acquire\n"); - return 0; - } for (n = 0; n < insn->n; n++) { /* Trigger the conversion */ @@ -175,18 +180,10 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, udelay(1); /* Wait for the conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - ucPort = inb(dev->iobase + MPC624_ADC); - if (ucPort & MPC624_ADBUSY) - udelay(1000); - else - break; - } - if (i == TIMEOUT) { - printk(KERN_ERR "MPC624: timeout (%dms)\n", TIMEOUT); - data[n] = 0; - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0); + if (ret) + return ret; + /* Start reading data */ data_in = 0; data_out = devpriv->ulConvertionRate; @@ -245,11 +242,11 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, */ if (data_in & MPC624_EOC_BIT) - printk(KERN_INFO "MPC624:EOC bit is set (data_in=%lu)!", - data_in); + dev_dbg(dev->class_dev, + "EOC bit is set (data_in=%lu)!", data_in); if (data_in & MPC624_DMY_BIT) - printk(KERN_INFO "MPC624:DMY bit is set (data_in=%lu)!", - data_in); + dev_dbg(dev->class_dev, + "DMY bit is set (data_in=%lu)!", data_in); if (data_in & MPC624_SGN_BIT) { /* Volatge is positive */ /* * comedi operates on unsigned numbers, so mask off EOC @@ -286,10 +283,9 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; switch (it->options[1]) { case 0: @@ -349,7 +345,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->insn_read = mpc624_ai_rinsn; - return 1; + return 0; } static struct comedi_driver mpc624_driver = { diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 5ecd1b1666f..b74b9e9bfd4 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -24,11 +24,10 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3) */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - #define MULTIQ3_SIZE 16 /* @@ -82,34 +81,44 @@ struct multiq3_private { unsigned int ao_readback[2]; }; +static int multiq3_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + MULTIQ3_STATUS); + if (status & context) + return 0; + return -EBUSY; +} + static int multiq3_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, n; + int n; int chan; unsigned int hi, lo; + int ret; chan = CR_CHAN(insn->chanspec); outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3), dev->iobase + MULTIQ3_CONTROL); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC); + if (ret) + return ret; for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + MULTIQ3_AD_CS); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + - MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC_I) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC_I); + if (ret) + return ret; hi = inb(dev->iobase + MULTIQ3_AD_CS); lo = inb(dev->iobase + MULTIQ3_AD_CS); @@ -164,11 +173,11 @@ static int multiq3_di_insn_bits(struct comedi_device *dev, static int multiq3_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT); + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT); data[1] = s->state; @@ -232,10 +241,9 @@ static int multiq3_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; s = &dev->subdevices[0]; /* ai subdevice */ diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 903c2ef5dd9..c8b1fa793a3 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -1,80 +1,75 @@ /* - comedi/drivers/ni_6527.c - driver for National Instruments PCI-6527 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ni_6527 -Description: National Instruments 6527 -Author: ds -Status: works -Devices: [National Instruments] PCI-6527 (ni6527), PXI-6527 -Updated: Sat, 25 Jan 2003 13:24:40 -0800 - - -*/ + * ni_6527.c + * Comedi driver for National Instruments PCI-6527 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* - Manuals (available from ftp://ftp.natinst.com/support/manuals) - - 370106b.pdf 6527 Register Level Programmer Manual - + * Driver: ni_6527 + * Description: National Instruments 6527 + * Devices: (National Instruments) PCI-6527 [pci-6527] + * (National Instruments) PXI-6527 [pxi-6527] + * Author: David A. Schleef <ds@schleef.org> + * Updated: Sat, 25 Jan 2003 13:24:40 -0800 + * Status: works + * + * Configuration Options: not applicable, uses PCI auto config */ -#define DEBUG 1 -#define DEBUG_FLAGS - +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> #include "../comedidev.h" #include "comedi_fc.h" -#include "mite.h" - -#define DRIVER_NAME "ni_6527" - -#define NI6527_DIO_SIZE 4096 -#define NI6527_MITE_SIZE 4096 - -#define Port_Register(x) (0x00+(x)) -#define ID_Register 0x06 -#define Clear_Register 0x07 -#define ClrEdge 0x08 -#define ClrOverflow 0x04 -#define ClrFilter 0x02 -#define ClrInterval 0x01 - -#define Filter_Interval(x) (0x08+(x)) -#define Filter_Enable(x) (0x0c+(x)) - -#define Change_Status 0x14 -#define MasterInterruptStatus 0x04 -#define Overflow 0x02 -#define EdgeStatus 0x01 - -#define Master_Interrupt_Control 0x15 -#define FallingEdgeIntEnable 0x10 -#define RisingEdgeIntEnable 0x08 -#define MasterInterruptEnable 0x04 -#define OverflowIntEnable 0x02 -#define EdgeIntEnable 0x01 - -#define Rising_Edge_Detection_Enable(x) (0x018+(x)) -#define Falling_Edge_Detection_Enable(x) (0x020+(x)) +/* + * PCI BAR1 - Register memory map + * + * Manuals (available from ftp://ftp.natinst.com/support/manuals) + * 370106b.pdf 6527 Register Level Programmer Manual + */ +#define NI6527_DI_REG(x) (0x00 + (x)) +#define NI6527_DO_REG(x) (0x03 + (x)) +#define NI6527_ID_REG 0x06 +#define NI6527_CLR_REG 0x07 +#define NI6527_CLR_EDGE (1 << 3) +#define NI6527_CLR_OVERFLOW (1 << 2) +#define NI6527_CLR_FILT (1 << 1) +#define NI6527_CLR_INTERVAL (1 << 0) +#define NI6527_CLR_IRQS (NI6527_CLR_EDGE | NI6527_CLR_OVERFLOW) +#define NI6527_CLR_RESET_FILT (NI6527_CLR_FILT | NI6527_CLR_INTERVAL) +#define NI6527_FILT_INTERVAL_REG(x) (0x08 + (x)) +#define NI6527_FILT_ENA_REG(x) (0x0c + (x)) +#define NI6527_STATUS_REG 0x14 +#define NI6527_STATUS_IRQ (1 << 2) +#define NI6527_STATUS_OVERFLOW (1 << 1) +#define NI6527_STATUS_EDGE (1 << 0) +#define NI6527_CTRL_REG 0x15 +#define NI6527_CTRL_FALLING (1 << 4) +#define NI6527_CTRL_RISING (1 << 3) +#define NI6527_CTRL_IRQ (1 << 2) +#define NI6527_CTRL_OVERFLOW (1 << 1) +#define NI6527_CTRL_EDGE (1 << 0) +#define NI6527_CTRL_DISABLE_IRQS 0 +#define NI6527_CTRL_ENABLE_IRQS (NI6527_CTRL_FALLING | \ + NI6527_CTRL_RISING | \ + NI6527_CTRL_IRQ | NI6527_CTRL_EDGE) +#define NI6527_RISING_EDGE_REG(x) (0x18 + (x)) +#define NI6527_FALLING_EDGE_REG(x) (0x20 + (x)) enum ni6527_boardid { BOARD_PCI6527, @@ -95,96 +90,113 @@ static const struct ni6527_board ni6527_boards[] = { }; struct ni6527_private { - struct mite_struct *mite; + void __iomem *mmio_base; unsigned int filter_interval; unsigned int filter_enable; }; +static void ni6527_set_filter_interval(struct comedi_device *dev, + unsigned int val) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + if (val != devpriv->filter_interval) { + writeb(val & 0xff, mmio + NI6527_FILT_INTERVAL_REG(0)); + writeb((val >> 8) & 0xff, mmio + NI6527_FILT_INTERVAL_REG(1)); + writeb((val >> 16) & 0x0f, mmio + NI6527_FILT_INTERVAL_REG(2)); + + writeb(NI6527_CLR_INTERVAL, mmio + NI6527_CLR_REG); + + devpriv->filter_interval = val; + } +} + +static void ni6527_set_filter_enable(struct comedi_device *dev, + unsigned int val) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + writeb(val & 0xff, mmio + NI6527_FILT_ENA_REG(0)); + writeb((val >> 8) & 0xff, mmio + NI6527_FILT_ENA_REG(1)); + writeb((val >> 16) & 0xff, mmio + NI6527_FILT_ENA_REG(2)); +} + static int ni6527_di_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni6527_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int interval; - if (insn->n != 2) - return -EINVAL; - - if (data[0] != INSN_CONFIG_FILTER) - return -EINVAL; - - if (data[1]) { + switch (data[0]) { + case INSN_CONFIG_FILTER: + /* + * The deglitch filter interval is specified in nanoseconds. + * The hardware supports intervals in 200ns increments. Round + * the user values up and return the actual interval. + */ interval = (data[1] + 100) / 200; data[1] = interval * 200; - if (interval != devpriv->filter_interval) { - writeb(interval & 0xff, - devpriv->mite->daq_io_addr + Filter_Interval(0)); - writeb((interval >> 8) & 0xff, - devpriv->mite->daq_io_addr + Filter_Interval(1)); - writeb((interval >> 16) & 0x0f, - devpriv->mite->daq_io_addr + Filter_Interval(2)); - - writeb(ClrInterval, - devpriv->mite->daq_io_addr + Clear_Register); - - devpriv->filter_interval = interval; + if (interval) { + ni6527_set_filter_interval(dev, interval); + devpriv->filter_enable |= 1 << chan; + } else { + devpriv->filter_enable &= ~(1 << chan); } - - devpriv->filter_enable |= 1 << chan; - } else { - devpriv->filter_enable &= ~(1 << chan); + ni6527_set_filter_enable(dev, devpriv->filter_enable); + break; + default: + return -EINVAL; } - writeb(devpriv->filter_enable, - devpriv->mite->daq_io_addr + Filter_Enable(0)); - writeb(devpriv->filter_enable >> 8, - devpriv->mite->daq_io_addr + Filter_Enable(1)); - writeb(devpriv->filter_enable >> 16, - devpriv->mite->daq_io_addr + Filter_Enable(2)); - - return 2; + return insn->n; } static int ni6527_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + unsigned int val; + + val = readb(mmio + NI6527_DI_REG(0)); + val |= (readb(mmio + NI6527_DI_REG(1)) << 8); + val |= (readb(mmio + NI6527_DI_REG(2)) << 16); - data[1] = readb(devpriv->mite->daq_io_addr + Port_Register(0)); - data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(1)) << 8; - data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(2)) << 16; + data[1] = val; return insn->n; } static int ni6527_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni6527_private *devpriv = dev->private; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - /* The open relay state on the board cooresponds to 1, - * but in Comedi, it is represented by 0. */ - if (data[0] & 0x0000ff) { - writeb((s->state ^ 0xff), - devpriv->mite->daq_io_addr + Port_Register(3)); - } - if (data[0] & 0x00ff00) { - writeb((s->state >> 8) ^ 0xff, - devpriv->mite->daq_io_addr + Port_Register(4)); - } - if (data[0] & 0xff0000) { - writeb((s->state >> 16) ^ 0xff, - devpriv->mite->daq_io_addr + Port_Register(5)); - } + void __iomem *mmio = devpriv->mmio_base; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* Outputs are inverted */ + unsigned int val = s->state ^ 0xffffff; + + if (mask & 0x0000ff) + writeb(val & 0xff, mmio + NI6527_DO_REG(0)); + if (mask & 0x00ff00) + writeb((val >> 8) & 0xff, mmio + NI6527_DO_REG(1)); + if (mask & 0xff0000) + writeb((val >> 16) & 0xff, mmio + NI6527_DO_REG(2)); } + data[1] = s->state; return insn->n; @@ -194,21 +206,22 @@ static irqreturn_t ni6527_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct ni6527_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[2]; + struct comedi_subdevice *s = dev->read_subdev; + void __iomem *mmio = devpriv->mmio_base; unsigned int status; - status = readb(devpriv->mite->daq_io_addr + Change_Status); - if ((status & MasterInterruptStatus) == 0) - return IRQ_NONE; - if ((status & EdgeStatus) == 0) + status = readb(mmio + NI6527_STATUS_REG); + if (!(status & NI6527_STATUS_IRQ)) return IRQ_NONE; - writeb(ClrEdge | ClrOverflow, - devpriv->mite->daq_io_addr + Clear_Register); + if (status & NI6527_STATUS_EDGE) { + comedi_buf_put(s, 0); + s->async->events |= COMEDI_CB_EOS; + comedi_event(dev, s); + } + + writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); - comedi_buf_put(s->async, 0); - s->async->events |= COMEDI_CB_EOS; - comedi_event(dev, s); return IRQ_HANDLED; } @@ -240,7 +253,7 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, 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, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -258,13 +271,10 @@ static int ni6527_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct ni6527_private *devpriv = dev->private; - /* struct comedi_cmd *cmd = &s->async->cmd; */ + void __iomem *mmio = devpriv->mmio_base; - writeb(ClrEdge | ClrOverflow, - devpriv->mite->daq_io_addr + Clear_Register); - writeb(FallingEdgeIntEnable | RisingEdgeIntEnable | - MasterInterruptEnable | EdgeIntEnable, - devpriv->mite->daq_io_addr + Master_Interrupt_Control); + writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_ENABLE_IRQS, mmio + NI6527_CTRL_REG); return 0; } @@ -273,8 +283,9 @@ static int ni6527_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; - writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); + writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); return 0; } @@ -287,32 +298,54 @@ static int ni6527_intr_insn_bits(struct comedi_device *dev, return insn->n; } +static void ni6527_set_edge_detection(struct comedi_device *dev, + unsigned int rising, + unsigned int falling) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + /* enable rising-edge detection channels */ + writeb(rising & 0xff, mmio + NI6527_RISING_EDGE_REG(0)); + writeb((rising >> 8) & 0xff, mmio + NI6527_RISING_EDGE_REG(1)); + writeb((rising >> 16) & 0xff, mmio + NI6527_RISING_EDGE_REG(2)); + + /* enable falling-edge detection channels */ + writeb(falling & 0xff, mmio + NI6527_FALLING_EDGE_REG(0)); + writeb((falling >> 8) & 0xff, mmio + NI6527_FALLING_EDGE_REG(1)); + writeb((falling >> 16) & 0xff, mmio + NI6527_FALLING_EDGE_REG(2)); +} + static int ni6527_intr_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) +{ + switch (data[0]) { + case INSN_CONFIG_CHANGE_NOTIFY: + /* check_insn_config_length() does not check this instruction */ + if (insn->n != 3) + return -EINVAL; + ni6527_set_edge_detection(dev, data[1], data[2]); + break; + default: + return -EINVAL; + } + + return insn->n; +} + +static void ni6527_reset(struct comedi_device *dev) { struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; - if (insn->n < 1) - return -EINVAL; - if (data[0] != INSN_CONFIG_CHANGE_NOTIFY) - return -EINVAL; + /* disable deglitch filters on all channels */ + ni6527_set_filter_enable(dev, 0); - writeb(data[1], - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0)); - writeb(data[1] >> 8, - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(1)); - writeb(data[1] >> 16, - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(2)); - - writeb(data[2], - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0)); - writeb(data[2] >> 8, - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(1)); - writeb(data[2] >> 16, - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(2)); - - return 2; + writeb(NI6527_CLR_IRQS | NI6527_CLR_RESET_FILT, + mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); } static int ni6527_auto_attach(struct comedi_device *dev, @@ -331,76 +364,70 @@ static int ni6527_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + ret = comedi_pci_enable(dev); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) + devpriv->mmio_base = pci_ioremap_bar(pcidev, 1); + if (!devpriv->mmio_base) return -ENOMEM; - dev->private = devpriv; - devpriv->mite = mite_alloc(pcidev); - if (!devpriv->mite) - return -ENOMEM; + /* make sure this is actually a 6527 device */ + if (readb(devpriv->mmio_base + NI6527_ID_REG) != 0x27) + return -ENODEV; - ret = mite_setup(devpriv->mite); - if (ret < 0) { - dev_err(dev->class_dev, "error setting up mite\n"); - return ret; - } + ni6527_reset(dev); - dev_info(dev->class_dev, "board: %s, ID=0x%02x\n", dev->board_name, - readb(devpriv->mite->daq_io_addr + ID_Register)); + ret = request_irq(pcidev->irq, ni6527_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; + /* Digital Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 24; - s->range_table = &range_digital; - s->maxdata = 1; - s->insn_config = ni6527_di_insn_config; - s->insn_bits = ni6527_di_insn_bits; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = ni6527_di_insn_config; + s->insn_bits = ni6527_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 24; - s->range_table = &range_unknown; /* FIXME: actually conductance */ - s->maxdata = 1; - s->insn_bits = ni6527_do_insn_bits; - + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ni6527_do_insn_bits; + + /* Edge detection interrupt subdevice */ s = &dev->subdevices[2]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->range_table = &range_unknown; - s->maxdata = 1; - s->do_cmdtest = ni6527_intr_cmdtest; - s->do_cmd = ni6527_intr_cmd; - s->cancel = ni6527_intr_cancel; - s->insn_bits = ni6527_intr_insn_bits; - s->insn_config = ni6527_intr_insn_config; - - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0)); - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(1)); - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(2)); - - writeb(ClrEdge | ClrOverflow | ClrFilter | ClrInterval, - devpriv->mite->daq_io_addr + Clear_Register); - writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); - - ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt, - IRQF_SHARED, DRIVER_NAME, dev); - if (ret < 0) - dev_warn(dev->class_dev, "irq not available\n"); - else - dev->irq = mite_irq(devpriv->mite); + if (dev->irq) { + dev->read_subdev = s; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = ni6527_intr_insn_config; + s->insn_bits = ni6527_intr_insn_bits; + s->len_chanlist = 1; + s->do_cmdtest = ni6527_intr_cmdtest; + s->do_cmd = ni6527_intr_cmd; + s->cancel = ni6527_intr_cancel; + } else { + s->type = COMEDI_SUBD_UNUSED; + } return 0; } @@ -409,23 +436,18 @@ static void ni6527_detach(struct comedi_device *dev) { struct ni6527_private *devpriv = dev->private; - if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) - writeb(0x00, - devpriv->mite->daq_io_addr + Master_Interrupt_Control); + if (devpriv && devpriv->mmio_base) + ni6527_reset(dev); if (dev->irq) free_irq(dev->irq, dev); - if (devpriv && devpriv->mite) { - mite_unsetup(devpriv->mite); - mite_free(devpriv->mite); - } comedi_pci_disable(dev); } static struct comedi_driver ni6527_driver = { - .driver_name = DRIVER_NAME, - .module = THIS_MODULE, - .auto_attach = ni6527_auto_attach, - .detach = ni6527_detach, + .driver_name = "ni_6527", + .module = THIS_MODULE, + .auto_attach = ni6527_auto_attach, + .detach = ni6527_detach, }; static int ni6527_pci_probe(struct pci_dev *dev, @@ -434,7 +456,7 @@ static int ni6527_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni6527_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = { +static const struct pci_device_id ni6527_pci_table[] = { { PCI_VDEVICE(NI, 0x2b10), BOARD_PXI6527 }, { PCI_VDEVICE(NI, 0x2b20), BOARD_PCI6527 }, { 0 } @@ -442,7 +464,7 @@ static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = { MODULE_DEVICE_TABLE(pci, ni6527_pci_table); static struct pci_driver ni6527_pci_driver = { - .name = DRIVER_NAME, + .name = "ni_6527", .id_table = ni6527_pci_table, .probe = ni6527_pci_probe, .remove = comedi_pci_auto_unconfig, @@ -450,5 +472,5 @@ static struct pci_driver ni6527_pci_driver = { module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for National Instruments PCI-6527"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 42a78de4731..9a139d6b8ef 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -43,12 +43,9 @@ except maybe the 6514. */ -#define DEBUG 1 -#define DEBUG_FLAGS - +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include "../comedidev.h" @@ -369,28 +366,23 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev, { const struct ni_65xx_board *board = comedi_board(dev); struct ni_65xx_private *devpriv = dev->private; - unsigned base_bitfield_channel; - const unsigned max_ports_per_bitfield = 5; + int base_bitfield_channel; unsigned read_bits = 0; - unsigned j; + int last_port_offset = ni_65xx_port_by_channel(s->n_chan - 1); + int port_offset; base_bitfield_channel = CR_CHAN(insn->chanspec); - for (j = 0; j < max_ports_per_bitfield; ++j) { - const unsigned port_offset = - ni_65xx_port_by_channel(base_bitfield_channel) + j; - const unsigned port = - sprivate(s)->base_port + port_offset; - unsigned base_port_channel; + for (port_offset = ni_65xx_port_by_channel(base_bitfield_channel); + port_offset <= last_port_offset; port_offset++) { + unsigned port = sprivate(s)->base_port + port_offset; + int base_port_channel = port_offset * ni_65xx_channels_per_port; unsigned port_mask, port_data, port_read_bits; - int bitshift; - if (port >= ni_65xx_total_num_ports(board)) + int bitshift = base_port_channel - base_bitfield_channel; + + if (bitshift >= 32) break; - base_port_channel = port_offset * ni_65xx_channels_per_port; port_mask = data[0]; port_data = data[1]; - bitshift = base_port_channel - base_bitfield_channel; - if (bitshift >= 32 || bitshift <= -32) - break; if (bitshift > 0) { port_mask >>= bitshift; port_data >>= bitshift; @@ -435,7 +427,7 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct ni_65xx_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[2]; + struct comedi_subdevice *s = dev->read_subdev; unsigned int status; status = readb(devpriv->mite->daq_io_addr + Change_Status); @@ -447,7 +439,7 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d) writeb(ClrEdge | ClrOverflow, devpriv->mite->daq_io_addr + Clear_Register); - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); return IRQ_HANDLED; @@ -481,7 +473,7 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev, 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, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -499,7 +491,6 @@ static int ni_65xx_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct ni_65xx_private *devpriv = dev->private; - /* struct comedi_cmd *cmd = &s->async->cmd; */ writeb(ClrEdge | ClrOverflow, devpriv->mite->daq_io_addr + Clear_Register); @@ -591,10 +582,9 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->mite = mite_alloc(pcidev); if (!devpriv->mite) @@ -680,6 +670,7 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, s->n_chan = 1; s->range_table = &range_unknown; s->maxdata = 1; + s->len_chanlist = 1; s->do_cmdtest = ni_65xx_intr_cmdtest; s->do_cmd = ni_65xx_intr_cmd; s->cancel = ni_65xx_intr_cancel; @@ -747,7 +738,7 @@ static int ni_65xx_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_65xx_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(ni_65xx_pci_table) = { +static const struct pci_device_id ni_65xx_pci_table[] = { { PCI_VDEVICE(NI, 0x1710), BOARD_PXI6509 }, { PCI_VDEVICE(NI, 0x7085), BOARD_PCI6509 }, { PCI_VDEVICE(NI, 0x7086), BOARD_PXI6528 }, diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index a9e000461ec..634cde83a02 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -34,11 +34,13 @@ * DAQ 6601/6602 User Manual (NI 322137B-01) */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" #include "ni_tio.h" @@ -54,112 +56,112 @@ for 4 */ #define MAX_DMA_CHANNEL 4 /* See Register-Level Programmer Manual page 3.1 */ -enum NI_660x_Register { - G0InterruptAcknowledge, - G0StatusRegister, - G1InterruptAcknowledge, - G1StatusRegister, - G01StatusRegister, - G0CommandRegister, - STCDIOParallelInput, - G1CommandRegister, - G0HWSaveRegister, - G1HWSaveRegister, - STCDIOOutput, - STCDIOControl, - G0SWSaveRegister, - G1SWSaveRegister, - G0ModeRegister, - G01JointStatus1Register, - G1ModeRegister, - STCDIOSerialInput, - G0LoadARegister, - G01JointStatus2Register, - G0LoadBRegister, - G1LoadARegister, - G1LoadBRegister, - G0InputSelectRegister, - G1InputSelectRegister, - G0AutoincrementRegister, - G1AutoincrementRegister, - G01JointResetRegister, - G0InterruptEnable, - G1InterruptEnable, - G0CountingModeRegister, - G1CountingModeRegister, - G0SecondGateRegister, - G1SecondGateRegister, - G0DMAConfigRegister, - G0DMAStatusRegister, - G1DMAConfigRegister, - G1DMAStatusRegister, - G2InterruptAcknowledge, - G2StatusRegister, - G3InterruptAcknowledge, - G3StatusRegister, - G23StatusRegister, - G2CommandRegister, - G3CommandRegister, - G2HWSaveRegister, - G3HWSaveRegister, - G2SWSaveRegister, - G3SWSaveRegister, - G2ModeRegister, - G23JointStatus1Register, - G3ModeRegister, - G2LoadARegister, - G23JointStatus2Register, - G2LoadBRegister, - G3LoadARegister, - G3LoadBRegister, - G2InputSelectRegister, - G3InputSelectRegister, - G2AutoincrementRegister, - G3AutoincrementRegister, - G23JointResetRegister, - G2InterruptEnable, - G3InterruptEnable, - G2CountingModeRegister, - G3CountingModeRegister, - G3SecondGateRegister, - G2SecondGateRegister, - G2DMAConfigRegister, - G2DMAStatusRegister, - G3DMAConfigRegister, - G3DMAStatusRegister, - DIO32Input, - DIO32Output, - ClockConfigRegister, - GlobalInterruptStatusRegister, - DMAConfigRegister, - GlobalInterruptConfigRegister, - IOConfigReg0_1, - IOConfigReg2_3, - IOConfigReg4_5, - IOConfigReg6_7, - IOConfigReg8_9, - IOConfigReg10_11, - IOConfigReg12_13, - IOConfigReg14_15, - IOConfigReg16_17, - IOConfigReg18_19, - IOConfigReg20_21, - IOConfigReg22_23, - IOConfigReg24_25, - IOConfigReg26_27, - IOConfigReg28_29, - IOConfigReg30_31, - IOConfigReg32_33, - IOConfigReg34_35, - IOConfigReg36_37, - IOConfigReg38_39, - NumRegisters, +enum ni_660x_register { + NI660X_G0_INT_ACK, + NI660X_G0_STATUS, + NI660X_G1_INT_ACK, + NI660X_G1_STATUS, + NI660X_G01_STATUS, + NI660X_G0_CMD, + NI660X_STC_DIO_PARALLEL_INPUT, + NI660X_G1_CMD, + NI660X_G0_HW_SAVE, + NI660X_G1_HW_SAVE, + NI660X_STC_DIO_OUTPUT, + NI660X_STC_DIO_CONTROL, + NI660X_G0_SW_SAVE, + NI660X_G1_SW_SAVE, + NI660X_G0_MODE, + NI660X_G01_STATUS1, + NI660X_G1_MODE, + NI660X_STC_DIO_SERIAL_INPUT, + NI660X_G0_LOADA, + NI660X_G01_STATUS2, + NI660X_G0_LOADB, + NI660X_G1_LOADA, + NI660X_G1_LOADB, + NI660X_G0_INPUT_SEL, + NI660X_G1_INPUT_SEL, + NI660X_G0_AUTO_INC, + NI660X_G1_AUTO_INC, + NI660X_G01_RESET, + NI660X_G0_INT_ENA, + NI660X_G1_INT_ENA, + NI660X_G0_CNT_MODE, + NI660X_G1_CNT_MODE, + NI660X_G0_GATE2, + NI660X_G1_GATE2, + NI660X_G0_DMA_CFG, + NI660X_G0_DMA_STATUS, + NI660X_G1_DMA_CFG, + NI660X_G1_DMA_STATUS, + NI660X_G2_INT_ACK, + NI660X_G2_STATUS, + NI660X_G3_INT_ACK, + NI660X_G3_STATUS, + NI660X_G23_STATUS, + NI660X_G2_CMD, + NI660X_G3_CMD, + NI660X_G2_HW_SAVE, + NI660X_G3_HW_SAVE, + NI660X_G2_SW_SAVE, + NI660X_G3_SW_SAVE, + NI660X_G2_MODE, + NI660X_G23_STATUS1, + NI660X_G3_MODE, + NI660X_G2_LOADA, + NI660X_G23_STATUS2, + NI660X_G2_LOADB, + NI660X_G3_LOADA, + NI660X_G3_LOADB, + NI660X_G2_INPUT_SEL, + NI660X_G3_INPUT_SEL, + NI660X_G2_AUTO_INC, + NI660X_G3_AUTO_INC, + NI660X_G23_RESET, + NI660X_G2_INT_ENA, + NI660X_G3_INT_ENA, + NI660X_G2_CNT_MODE, + NI660X_G3_CNT_MODE, + NI660X_G3_GATE2, + NI660X_G2_GATE2, + NI660X_G2_DMA_CFG, + NI660X_G2_DMA_STATUS, + NI660X_G3_DMA_CFG, + NI660X_G3_DMA_STATUS, + NI660X_DIO32_INPUT, + NI660X_DIO32_OUTPUT, + NI660X_CLK_CFG, + NI660X_GLOBAL_INT_STATUS, + NI660X_DMA_CFG, + NI660X_GLOBAL_INT_CFG, + NI660X_IO_CFG_0_1, + NI660X_IO_CFG_2_3, + NI660X_IO_CFG_4_5, + NI660X_IO_CFG_6_7, + NI660X_IO_CFG_8_9, + NI660X_IO_CFG_10_11, + NI660X_IO_CFG_12_13, + NI660X_IO_CFG_14_15, + NI660X_IO_CFG_16_17, + NI660X_IO_CFG_18_19, + NI660X_IO_CFG_20_21, + NI660X_IO_CFG_22_23, + NI660X_IO_CFG_24_25, + NI660X_IO_CFG_26_27, + NI660X_IO_CFG_28_29, + NI660X_IO_CFG_30_31, + NI660X_IO_CFG_32_33, + NI660X_IO_CFG_34_35, + NI660X_IO_CFG_36_37, + NI660X_IO_CFG_38_39, + NI660X_NUM_REGS, }; static inline unsigned IOConfigReg(unsigned pfi_channel) { - unsigned reg = IOConfigReg0_1 + pfi_channel / 2; - BUG_ON(reg > IOConfigReg38_39); + unsigned reg = NI660X_IO_CFG_0_1 + pfi_channel / 2; + BUG_ON(reg > NI660X_IO_CFG_38_39); return reg; } @@ -199,7 +201,7 @@ struct NI_660xRegisterData { enum ni_660x_register_width size; /* 1 byte, 2 bytes, or 4 bytes */ }; -static const struct NI_660xRegisterData registerData[NumRegisters] = { +static const struct NI_660xRegisterData registerData[NI660X_NUM_REGS] = { {"G0 Interrupt Acknowledge", 0x004, NI_660x_WRITE, DATA_2B}, {"G0 Status Register", 0x004, NI_660x_READ, DATA_2B}, {"G1 Interrupt Acknowledge", 0x006, NI_660x_WRITE, DATA_2B}, @@ -346,11 +348,6 @@ static inline unsigned dma_select_mask(unsigned dma_channel) enum dma_selection { dma_selection_none = 0x1f, }; -static inline unsigned dma_selection_counter(unsigned counter_index) -{ - BUG_ON(counter_index >= counters_per_chip); - return counter_index; -} static inline unsigned dma_select_bits(unsigned dma_channel, unsigned selection) { @@ -443,229 +440,158 @@ static inline unsigned ni_660x_num_counters(struct comedi_device *dev) return board->n_chips * counters_per_chip; } -static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) +static enum ni_660x_register ni_gpct_to_660x_register(enum ni_gpct_register reg) { - enum NI_660x_Register ni_660x_register; switch (reg) { - case NITIO_G0_Autoincrement_Reg: - ni_660x_register = G0AutoincrementRegister; - break; - case NITIO_G1_Autoincrement_Reg: - ni_660x_register = G1AutoincrementRegister; - break; - case NITIO_G2_Autoincrement_Reg: - ni_660x_register = G2AutoincrementRegister; - break; - case NITIO_G3_Autoincrement_Reg: - ni_660x_register = G3AutoincrementRegister; - break; - case NITIO_G0_Command_Reg: - ni_660x_register = G0CommandRegister; - break; - case NITIO_G1_Command_Reg: - ni_660x_register = G1CommandRegister; - break; - case NITIO_G2_Command_Reg: - ni_660x_register = G2CommandRegister; - break; - case NITIO_G3_Command_Reg: - ni_660x_register = G3CommandRegister; - break; - case NITIO_G0_HW_Save_Reg: - ni_660x_register = G0HWSaveRegister; - break; - case NITIO_G1_HW_Save_Reg: - ni_660x_register = G1HWSaveRegister; - break; - case NITIO_G2_HW_Save_Reg: - ni_660x_register = G2HWSaveRegister; - break; - case NITIO_G3_HW_Save_Reg: - ni_660x_register = G3HWSaveRegister; - break; - case NITIO_G0_SW_Save_Reg: - ni_660x_register = G0SWSaveRegister; - break; - case NITIO_G1_SW_Save_Reg: - ni_660x_register = G1SWSaveRegister; - break; - case NITIO_G2_SW_Save_Reg: - ni_660x_register = G2SWSaveRegister; - break; - case NITIO_G3_SW_Save_Reg: - ni_660x_register = G3SWSaveRegister; - break; - case NITIO_G0_Mode_Reg: - ni_660x_register = G0ModeRegister; - break; - case NITIO_G1_Mode_Reg: - ni_660x_register = G1ModeRegister; - break; - case NITIO_G2_Mode_Reg: - ni_660x_register = G2ModeRegister; - break; - case NITIO_G3_Mode_Reg: - ni_660x_register = G3ModeRegister; - break; - case NITIO_G0_LoadA_Reg: - ni_660x_register = G0LoadARegister; - break; - case NITIO_G1_LoadA_Reg: - ni_660x_register = G1LoadARegister; - break; - case NITIO_G2_LoadA_Reg: - ni_660x_register = G2LoadARegister; - break; - case NITIO_G3_LoadA_Reg: - ni_660x_register = G3LoadARegister; - break; - case NITIO_G0_LoadB_Reg: - ni_660x_register = G0LoadBRegister; - break; - case NITIO_G1_LoadB_Reg: - ni_660x_register = G1LoadBRegister; - break; - case NITIO_G2_LoadB_Reg: - ni_660x_register = G2LoadBRegister; - break; - case NITIO_G3_LoadB_Reg: - ni_660x_register = G3LoadBRegister; - break; - case NITIO_G0_Input_Select_Reg: - ni_660x_register = G0InputSelectRegister; - break; - case NITIO_G1_Input_Select_Reg: - ni_660x_register = G1InputSelectRegister; - break; - case NITIO_G2_Input_Select_Reg: - ni_660x_register = G2InputSelectRegister; - break; - case NITIO_G3_Input_Select_Reg: - ni_660x_register = G3InputSelectRegister; - break; - case NITIO_G01_Status_Reg: - ni_660x_register = G01StatusRegister; - break; - case NITIO_G23_Status_Reg: - ni_660x_register = G23StatusRegister; - break; - case NITIO_G01_Joint_Reset_Reg: - ni_660x_register = G01JointResetRegister; - break; - case NITIO_G23_Joint_Reset_Reg: - ni_660x_register = G23JointResetRegister; - break; - case NITIO_G01_Joint_Status1_Reg: - ni_660x_register = G01JointStatus1Register; - break; - case NITIO_G23_Joint_Status1_Reg: - ni_660x_register = G23JointStatus1Register; - break; - case NITIO_G01_Joint_Status2_Reg: - ni_660x_register = G01JointStatus2Register; - break; - case NITIO_G23_Joint_Status2_Reg: - ni_660x_register = G23JointStatus2Register; - break; - case NITIO_G0_Counting_Mode_Reg: - ni_660x_register = G0CountingModeRegister; - break; - case NITIO_G1_Counting_Mode_Reg: - ni_660x_register = G1CountingModeRegister; - break; - case NITIO_G2_Counting_Mode_Reg: - ni_660x_register = G2CountingModeRegister; - break; - case NITIO_G3_Counting_Mode_Reg: - ni_660x_register = G3CountingModeRegister; - break; - case NITIO_G0_Second_Gate_Reg: - ni_660x_register = G0SecondGateRegister; - break; - case NITIO_G1_Second_Gate_Reg: - ni_660x_register = G1SecondGateRegister; - break; - case NITIO_G2_Second_Gate_Reg: - ni_660x_register = G2SecondGateRegister; - break; - case NITIO_G3_Second_Gate_Reg: - ni_660x_register = G3SecondGateRegister; - break; - case NITIO_G0_DMA_Config_Reg: - ni_660x_register = G0DMAConfigRegister; - break; - case NITIO_G0_DMA_Status_Reg: - ni_660x_register = G0DMAStatusRegister; - break; - case NITIO_G1_DMA_Config_Reg: - ni_660x_register = G1DMAConfigRegister; - break; - case NITIO_G1_DMA_Status_Reg: - ni_660x_register = G1DMAStatusRegister; - break; - case NITIO_G2_DMA_Config_Reg: - ni_660x_register = G2DMAConfigRegister; - break; - case NITIO_G2_DMA_Status_Reg: - ni_660x_register = G2DMAStatusRegister; - break; - case NITIO_G3_DMA_Config_Reg: - ni_660x_register = G3DMAConfigRegister; - break; - case NITIO_G3_DMA_Status_Reg: - ni_660x_register = G3DMAStatusRegister; - break; - case NITIO_G0_Interrupt_Acknowledge_Reg: - ni_660x_register = G0InterruptAcknowledge; - break; - case NITIO_G1_Interrupt_Acknowledge_Reg: - ni_660x_register = G1InterruptAcknowledge; - break; - case NITIO_G2_Interrupt_Acknowledge_Reg: - ni_660x_register = G2InterruptAcknowledge; - break; - case NITIO_G3_Interrupt_Acknowledge_Reg: - ni_660x_register = G3InterruptAcknowledge; - break; - case NITIO_G0_Status_Reg: - ni_660x_register = G0StatusRegister; - break; - case NITIO_G1_Status_Reg: - ni_660x_register = G1StatusRegister; - break; - case NITIO_G2_Status_Reg: - ni_660x_register = G2StatusRegister; - break; - case NITIO_G3_Status_Reg: - ni_660x_register = G3StatusRegister; - break; - case NITIO_G0_Interrupt_Enable_Reg: - ni_660x_register = G0InterruptEnable; - break; - case NITIO_G1_Interrupt_Enable_Reg: - ni_660x_register = G1InterruptEnable; - break; - case NITIO_G2_Interrupt_Enable_Reg: - ni_660x_register = G2InterruptEnable; - break; - case NITIO_G3_Interrupt_Enable_Reg: - ni_660x_register = G3InterruptEnable; - break; + case NITIO_G0_AUTO_INC: + return NI660X_G0_AUTO_INC; + case NITIO_G1_AUTO_INC: + return NI660X_G1_AUTO_INC; + case NITIO_G2_AUTO_INC: + return NI660X_G2_AUTO_INC; + case NITIO_G3_AUTO_INC: + return NI660X_G3_AUTO_INC; + case NITIO_G0_CMD: + return NI660X_G0_CMD; + case NITIO_G1_CMD: + return NI660X_G1_CMD; + case NITIO_G2_CMD: + return NI660X_G2_CMD; + case NITIO_G3_CMD: + return NI660X_G3_CMD; + case NITIO_G0_HW_SAVE: + return NI660X_G0_HW_SAVE; + case NITIO_G1_HW_SAVE: + return NI660X_G1_HW_SAVE; + case NITIO_G2_HW_SAVE: + return NI660X_G2_HW_SAVE; + case NITIO_G3_HW_SAVE: + return NI660X_G3_HW_SAVE; + case NITIO_G0_SW_SAVE: + return NI660X_G0_SW_SAVE; + case NITIO_G1_SW_SAVE: + return NI660X_G1_SW_SAVE; + case NITIO_G2_SW_SAVE: + return NI660X_G2_SW_SAVE; + case NITIO_G3_SW_SAVE: + return NI660X_G3_SW_SAVE; + case NITIO_G0_MODE: + return NI660X_G0_MODE; + case NITIO_G1_MODE: + return NI660X_G1_MODE; + case NITIO_G2_MODE: + return NI660X_G2_MODE; + case NITIO_G3_MODE: + return NI660X_G3_MODE; + case NITIO_G0_LOADA: + return NI660X_G0_LOADA; + case NITIO_G1_LOADA: + return NI660X_G1_LOADA; + case NITIO_G2_LOADA: + return NI660X_G2_LOADA; + case NITIO_G3_LOADA: + return NI660X_G3_LOADA; + case NITIO_G0_LOADB: + return NI660X_G0_LOADB; + case NITIO_G1_LOADB: + return NI660X_G1_LOADB; + case NITIO_G2_LOADB: + return NI660X_G2_LOADB; + case NITIO_G3_LOADB: + return NI660X_G3_LOADB; + case NITIO_G0_INPUT_SEL: + return NI660X_G0_INPUT_SEL; + case NITIO_G1_INPUT_SEL: + return NI660X_G1_INPUT_SEL; + case NITIO_G2_INPUT_SEL: + return NI660X_G2_INPUT_SEL; + case NITIO_G3_INPUT_SEL: + return NI660X_G3_INPUT_SEL; + case NITIO_G01_STATUS: + return NI660X_G01_STATUS; + case NITIO_G23_STATUS: + return NI660X_G23_STATUS; + case NITIO_G01_RESET: + return NI660X_G01_RESET; + case NITIO_G23_RESET: + return NI660X_G23_RESET; + case NITIO_G01_STATUS1: + return NI660X_G01_STATUS1; + case NITIO_G23_STATUS1: + return NI660X_G23_STATUS1; + case NITIO_G01_STATUS2: + return NI660X_G01_STATUS2; + case NITIO_G23_STATUS2: + return NI660X_G23_STATUS2; + case NITIO_G0_CNT_MODE: + return NI660X_G0_CNT_MODE; + case NITIO_G1_CNT_MODE: + return NI660X_G1_CNT_MODE; + case NITIO_G2_CNT_MODE: + return NI660X_G2_CNT_MODE; + case NITIO_G3_CNT_MODE: + return NI660X_G3_CNT_MODE; + case NITIO_G0_GATE2: + return NI660X_G0_GATE2; + case NITIO_G1_GATE2: + return NI660X_G1_GATE2; + case NITIO_G2_GATE2: + return NI660X_G2_GATE2; + case NITIO_G3_GATE2: + return NI660X_G3_GATE2; + case NITIO_G0_DMA_CFG: + return NI660X_G0_DMA_CFG; + case NITIO_G0_DMA_STATUS: + return NI660X_G0_DMA_STATUS; + case NITIO_G1_DMA_CFG: + return NI660X_G1_DMA_CFG; + case NITIO_G1_DMA_STATUS: + return NI660X_G1_DMA_STATUS; + case NITIO_G2_DMA_CFG: + return NI660X_G2_DMA_CFG; + case NITIO_G2_DMA_STATUS: + return NI660X_G2_DMA_STATUS; + case NITIO_G3_DMA_CFG: + return NI660X_G3_DMA_CFG; + case NITIO_G3_DMA_STATUS: + return NI660X_G3_DMA_STATUS; + case NITIO_G0_INT_ACK: + return NI660X_G0_INT_ACK; + case NITIO_G1_INT_ACK: + return NI660X_G1_INT_ACK; + case NITIO_G2_INT_ACK: + return NI660X_G2_INT_ACK; + case NITIO_G3_INT_ACK: + return NI660X_G3_INT_ACK; + case NITIO_G0_STATUS: + return NI660X_G0_STATUS; + case NITIO_G1_STATUS: + return NI660X_G1_STATUS; + case NITIO_G2_STATUS: + return NI660X_G2_STATUS; + case NITIO_G3_STATUS: + return NI660X_G3_STATUS; + case NITIO_G0_INT_ENA: + return NI660X_G0_INT_ENA; + case NITIO_G1_INT_ENA: + return NI660X_G1_INT_ENA; + case NITIO_G2_INT_ENA: + return NI660X_G2_INT_ENA; + case NITIO_G3_INT_ENA: + return NI660X_G3_INT_ENA; default: BUG(); return 0; - break; } - return ni_660x_register; } static inline void ni_660x_write_register(struct comedi_device *dev, - unsigned chip_index, unsigned bits, - enum NI_660x_Register reg) + unsigned chip, unsigned bits, + enum ni_660x_register reg) { struct ni_660x_private *devpriv = dev->private; void __iomem *write_address = - devpriv->mite->daq_io_addr + GPCT_OFFSET[chip_index] + + devpriv->mite->daq_io_addr + GPCT_OFFSET[chip] + registerData[reg].offset; switch (registerData[reg].size) { @@ -682,12 +608,12 @@ static inline void ni_660x_write_register(struct comedi_device *dev, } static inline unsigned ni_660x_read_register(struct comedi_device *dev, - unsigned chip_index, - enum NI_660x_Register reg) + unsigned chip, + enum ni_660x_register reg) { struct ni_660x_private *devpriv = dev->private; void __iomem *read_address = - devpriv->mite->daq_io_addr + GPCT_OFFSET[chip_index] + + devpriv->mite->daq_io_addr + GPCT_OFFSET[chip] + registerData[reg].offset; switch (registerData[reg].size) { @@ -708,18 +634,20 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) { struct comedi_device *dev = counter->counter_dev->dev; - enum NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); - ni_660x_write_register(dev, counter->chip_index, bits, - ni_660x_register); + enum ni_660x_register ni_660x_register = ni_gpct_to_660x_register(reg); + unsigned chip = counter->chip_index; + + ni_660x_write_register(dev, chip, bits, ni_660x_register); } static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg) { struct comedi_device *dev = counter->counter_dev->dev; - enum NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); - return ni_660x_read_register(dev, counter->chip_index, - ni_660x_register); + enum ni_660x_register ni_660x_register = ni_gpct_to_660x_register(reg); + unsigned chip = counter->chip_index; + + return ni_660x_read_register(dev, chip, ni_660x_register); } static inline struct mite_dma_descriptor_ring *mite_ring(struct ni_660x_private @@ -727,7 +655,9 @@ static inline struct mite_dma_descriptor_ring *mite_ring(struct ni_660x_private struct ni_gpct *counter) { - return priv->mite_rings[counter->chip_index][counter->counter_index]; + unsigned chip = counter->chip_index; + + return priv->mite_rings[chip][counter->counter_index]; } static inline void ni_660x_set_dma_channel(struct comedi_device *dev, @@ -735,18 +665,17 @@ static inline void ni_660x_set_dma_channel(struct comedi_device *dev, struct ni_gpct *counter) { struct ni_660x_private *devpriv = dev->private; + unsigned chip = counter->chip_index; unsigned long flags; spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); - devpriv->dma_configuration_soft_copies[counter->chip_index] &= - ~dma_select_mask(mite_channel); - devpriv->dma_configuration_soft_copies[counter->chip_index] |= - dma_select_bits(mite_channel, - dma_selection_counter(counter->counter_index)); - ni_660x_write_register(dev, counter->chip_index, - devpriv->dma_configuration_soft_copies - [counter->chip_index] | - dma_reset_bit(mite_channel), DMAConfigRegister); + devpriv->dma_configuration_soft_copies[chip] &= + ~dma_select_mask(mite_channel); + devpriv->dma_configuration_soft_copies[chip] |= + dma_select_bits(mite_channel, counter->counter_index); + ni_660x_write_register(dev, chip, + devpriv->dma_configuration_soft_copies[chip] | + dma_reset_bit(mite_channel), NI660X_DMA_CFG); mmiowb(); spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); } @@ -756,16 +685,17 @@ static inline void ni_660x_unset_dma_channel(struct comedi_device *dev, struct ni_gpct *counter) { struct ni_660x_private *devpriv = dev->private; + unsigned chip = counter->chip_index; unsigned long flags; spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); - devpriv->dma_configuration_soft_copies[counter->chip_index] &= + devpriv->dma_configuration_soft_copies[chip] &= ~dma_select_mask(mite_channel); - devpriv->dma_configuration_soft_copies[counter->chip_index] |= + devpriv->dma_configuration_soft_copies[chip] |= dma_select_bits(mite_channel, dma_selection_none); - ni_660x_write_register(dev, counter->chip_index, - devpriv->dma_configuration_soft_copies - [counter->chip_index], DMAConfigRegister); + ni_660x_write_register(dev, chip, + devpriv->dma_configuration_soft_copies[chip], + NI660X_DMA_CFG); mmiowb(); spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); } @@ -814,11 +744,9 @@ static void ni_660x_release_mite_channel(struct comedi_device *dev, static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_gpct *counter = s->private; int retval; - struct ni_gpct *counter = subdev_to_counter(s); -/* const struct comedi_cmd *cmd = &s->async->cmd; */ - retval = ni_660x_request_mite_channel(dev, counter, COMEDI_INPUT); if (retval) { comedi_error(dev, @@ -826,22 +754,13 @@ static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return retval; } ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL); - retval = ni_tio_cmd(counter, s->async); - - return retval; -} - -static int ni_660x_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - struct ni_gpct *counter = subdev_to_counter(s); - return ni_tio_cmdtest(counter, cmd); + return ni_tio_cmd(dev, s); } static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct ni_gpct *counter = subdev_to_counter(s); + struct ni_gpct *counter = s->private; int retval; retval = ni_tio_cancel(counter); @@ -849,30 +768,29 @@ static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return retval; } -static void set_tio_counterswap(struct comedi_device *dev, int chipset) +static void set_tio_counterswap(struct comedi_device *dev, int chip) { - /* See P. 3.5 of the Register-Level Programming manual. The - CounterSwap bit has to be set on the second chip, otherwise - it will try to use the same pins as the first chip. + unsigned bits = 0; + + /* + * See P. 3.5 of the Register-Level Programming manual. + * The CounterSwap bit has to be set on the second chip, + * otherwise it will try to use the same pins as the + * first chip. */ - if (chipset) - ni_660x_write_register(dev, chipset, CounterSwap, - ClockConfigRegister); - else - ni_660x_write_register(dev, chipset, 0, ClockConfigRegister); + if (chip) + bits = CounterSwap; + + ni_660x_write_register(dev, chip, bits, NI660X_CLK_CFG); } static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { - ni_tio_handle_interrupt(subdev_to_counter(s), s); - if (s->async->events) { - if (s->async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_660x_cancel(dev, s); - } - comedi_event(dev, s); - } + struct ni_gpct *counter = s->private; + + ni_tio_handle_interrupt(counter, s); + cfc_handle_events(dev, s); } static irqreturn_t ni_660x_interrupt(int irq, void *d) @@ -900,13 +818,14 @@ static int ni_660x_input_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct ni_660x_private *devpriv = dev->private; + struct ni_gpct *counter = s->private; unsigned long flags; /* lock to avoid race with comedi_poll */ spin_lock_irqsave(&devpriv->interrupt_lock, flags); - mite_sync_input_dma(subdev_to_counter(s)->mite_chan, s->async); + mite_sync_input_dma(counter->mite_chan, s); spin_unlock_irqrestore(&devpriv->interrupt_lock, flags); - return comedi_buf_read_n_available(s->async); + return comedi_buf_read_n_available(s); } static int ni_660x_buf_change(struct comedi_device *dev, @@ -914,10 +833,10 @@ static int ni_660x_buf_change(struct comedi_device *dev, unsigned long new_size) { struct ni_660x_private *devpriv = dev->private; + struct ni_gpct *counter = s->private; int ret; - ret = mite_buf_change(mite_ring(devpriv, subdev_to_counter(s)), - s->async); + ret = mite_buf_change(mite_ring(devpriv, counter), s); if (ret < 0) return ret; @@ -929,10 +848,9 @@ static int ni_660x_allocate_private(struct comedi_device *dev) struct ni_660x_private *devpriv; unsigned i; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; spin_lock_init(&devpriv->mite_channel_lock); spin_lock_init(&devpriv->interrupt_lock); @@ -974,13 +892,6 @@ static void ni_660x_free_mite_rings(struct comedi_device *dev) } } -static int -ni_660x_GPCT_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return ni_tio_rinsn(subdev_to_counter(s), insn, data); -} - static void init_tio_chip(struct comedi_device *dev, int chipset) { struct ni_660x_private *devpriv = dev->private; @@ -994,25 +905,11 @@ static void init_tio_chip(struct comedi_device *dev, int chipset) } ni_660x_write_register(dev, chipset, devpriv->dma_configuration_soft_copies[chipset], - DMAConfigRegister); + NI660X_DMA_CFG); for (i = 0; i < NUM_PFI_CHANNELS; ++i) ni_660x_write_register(dev, chipset, 0, IOConfigReg(i)); } -static int -ni_660x_GPCT_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return ni_tio_insn_config(subdev_to_counter(s), insn, data); -} - -static int ni_660x_GPCT_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return ni_tio_winsn(subdev_to_counter(s), insn, data); -} - static int ni_660x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1024,13 +921,13 @@ static int ni_660x_dio_insn_bits(struct comedi_device *dev, s->state &= ~(data[0] << base_bitfield_channel); s->state |= (data[0] & data[1]) << base_bitfield_channel; /* Write out the new digital output lines */ - ni_660x_write_register(dev, 0, s->state, DIO32Output); + ni_660x_write_register(dev, 0, s->state, NI660X_DIO32_OUTPUT); } /* on return, data[1] contains the value of the digital * input and output lines. */ - data[1] = - (ni_660x_read_register(dev, 0, - DIO32Input) >> base_bitfield_channel); + data[1] = (ni_660x_read_register(dev, 0, NI660X_DIO32_INPUT) >> + base_bitfield_channel); + return insn->n; } @@ -1213,10 +1110,9 @@ static int ni_660x_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = ni_660x_dio_insn_bits; s->insn_config = ni_660x_dio_insn_config; - s->io_bits = 0; /* all bits default to input */ /* we use the ioconfig registers to control dio direction, so zero output enables in stc dio control reg */ - ni_660x_write_register(dev, 0, 0, STCDIOControl); + ni_660x_write_register(dev, 0, 0, NI660X_STC_DIO_CONTROL); devpriv->counter_dev = ni_gpct_device_construct(dev, &ni_gpct_write_register, @@ -1235,12 +1131,12 @@ static int ni_660x_auto_attach(struct comedi_device *dev, SDF_CMD_READ /* | SDF_CMD_WRITE */ ; s->n_chan = 3; s->maxdata = 0xffffffff; - s->insn_read = ni_660x_GPCT_rinsn; - s->insn_write = ni_660x_GPCT_winsn; - s->insn_config = ni_660x_GPCT_insn_config; + s->insn_read = ni_tio_insn_read; + s->insn_write = ni_tio_insn_write; + s->insn_config = ni_tio_insn_config; s->do_cmd = &ni_660x_cmd; s->len_chanlist = 1; - s->do_cmdtest = &ni_660x_cmdtest; + s->do_cmdtest = ni_tio_cmdtest; s->cancel = &ni_660x_cancel; s->poll = &ni_660x_input_poll; s->async_dma_dir = DMA_BIDIRECTIONAL; @@ -1285,8 +1181,8 @@ static int ni_660x_auto_attach(struct comedi_device *dev, if (board->n_chips > 1) global_interrupt_config_bits |= Cascade_Int_Enable_Bit; ni_660x_write_register(dev, 0, global_interrupt_config_bits, - GlobalInterruptConfigRegister); - dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name); + NI660X_GLOBAL_INT_CFG); + return 0; } @@ -1321,7 +1217,7 @@ static int ni_660x_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_660x_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(ni_660x_pci_table) = { +static const struct pci_device_id ni_660x_pci_table[] = { { PCI_VDEVICE(NI, 0x1310), BOARD_PCI6602 }, { PCI_VDEVICE(NI, 0x1360), BOARD_PXI6602 }, { PCI_VDEVICE(NI, 0x2c60), BOARD_PCI6601 }, diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 1a185b9c529..1002ceacfdc 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -36,9 +36,9 @@ Commands are not supported. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include "../comedidev.h" @@ -136,20 +136,15 @@ static int ni_670x_ao_rinsn(struct comedi_device *dev, static int ni_670x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni_670x_private *devpriv = dev->private; void __iomem *io_addr = devpriv->mite->daq_io_addr + DIO_PORT0_DATA_OFFSET; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) writel(s->state, io_addr); - } data[1] = readl(io_addr); @@ -158,27 +153,16 @@ static int ni_670x_dio_insn_bits(struct comedi_device *dev, static int ni_670x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni_670x_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } writel(s->io_bits, devpriv->mite->daq_io_addr + DIO_PORT0_DIR_OFFSET); return insn->n; @@ -205,10 +189,9 @@ static int ni_670x_auto_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->mite = mite_alloc(pcidev); if (!devpriv->mite) @@ -263,9 +246,6 @@ static int ni_670x_auto_attach(struct comedi_device *dev, /* Config of ao registers */ writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET); - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } @@ -299,7 +279,7 @@ static int ni_670x_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_670x_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = { +static const struct pci_device_id ni_670x_pci_table[] = { { PCI_VDEVICE(NI, 0x1290), BOARD_PCI6704 }, { PCI_VDEVICE(NI, 0x1920), BOARD_PXI6704 }, { PCI_VDEVICE(NI, 0x2c90), BOARD_PCI6703 }, diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 7ea5aa32e9d..5bd19494dbf 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -58,12 +58,14 @@ TRIG_WAKE_EOS */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/slab.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/io.h> + #include <asm/dma.h> #include "8253.h" @@ -72,9 +74,6 @@ TRIG_WAKE_EOS #define A2150_SIZE 28 #define A2150_DMA_BUFFER_SIZE 0xff00 /* size in bytes of dma buffer */ -/* #define A2150_DEBUG enable debugging code */ -#undef A2150_DEBUG /* disable debugging code */ - /* Registers and bits */ #define CONFIG_REG 0x0 #define CHANNEL_BITS(x) ((x) & 0x7) @@ -125,10 +124,9 @@ struct a2150_board { /* analog input range */ static const struct comedi_lrange range_a2150 = { - 1, - { - RANGE(-2.828, 2.828), - } + 1, { + BIP_RANGE(2.828) + } }; /* enum must match board indices */ @@ -152,7 +150,7 @@ struct a2150_private { volatile unsigned int count; /* number of data points left to be taken */ unsigned int dma; /* dma channel */ - s16 *dma_buffer; /* dma buffer */ + uint16_t *dma_buffer; /* dma buffer */ unsigned int dma_transfer_size; /* size in bytes of dma transfers */ int irq_dma_bits; /* irq/dma register bits */ int config_bits; /* config register bits */ @@ -165,19 +163,6 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, static int a2150_set_chanlist(struct comedi_device *dev, unsigned int start_channel, unsigned int num_channels); -#ifdef A2150_DEBUG - -static void ni_dump_regs(struct comedi_device *dev) -{ - struct a2150_private *devpriv = dev->private; - - printk("config bits 0x%x\n", devpriv->config_bits); - printk("irq dma bits 0x%x\n", devpriv->irq_dma_bits); - printk("status bits 0x%x\n", inw(dev->iobase + STATUS_REG)); -} - -#endif - /* interrupt service routine */ static irqreturn_t a2150_interrupt(int irq, void *d) { @@ -190,7 +175,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) struct comedi_async *async; struct comedi_cmd *cmd; unsigned int max_points, num_points, residue, leftover; - short dpnt; + unsigned short dpnt; static const int sample_size = sizeof(devpriv->dma_buffer[0]); if (!dev->attached) { @@ -199,7 +184,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) } /* initialize async here to make sure s is not NULL */ async = s->async; - async->events = 0; cmd = &async->cmd; status = inw(dev->iobase + STATUS_REG); @@ -211,15 +195,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d) if (status & OVFL_BIT) { comedi_error(dev, "fifo overflow"); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); } if ((status & DMA_TC_BIT) == 0) { comedi_error(dev, "caught non-dma interrupt? Aborting."); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -264,7 +247,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) cfc_write_to_buffer(s, dpnt); if (cmd->stop_src == TRIG_COUNT) { if (--devpriv->count == 0) { /* end of acquisition */ - a2150_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -280,7 +262,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); /* clear interrupt */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); @@ -305,14 +287,54 @@ static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int a2150_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + if (cmd->chanlist_len == 2 && (chan0 == 1 || chan0 == 3)) { + dev_dbg(dev->class_dev, + "length 2 chanlist must be channels 0,1 or channels 2,3\n"); + return -EINVAL; + } + + if (cmd->chanlist_len == 3) { + dev_dbg(dev->class_dev, + "chanlist must have 1,2 or 4 channels\n"); + return -EINVAL; + } + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (chan == 2) + aref0 = aref; + if (aref != aref0) { + dev_dbg(dev->class_dev, + "channels 0/1 and 2/3 must have the same analog reference\n"); + return -EINVAL; + } + } + + return 0; +} + static int a2150_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct a2150_board *thisboard = comedi_board(dev); int err = 0; - int tmp; - int startChan; - int i; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -357,42 +379,17 @@ static int a2150_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + a2150_get_timing(dev, &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - startChan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != (startChan + i)) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - } - if (cmd->chanlist_len == 2 && CR_CHAN(cmd->chanlist[0]) == 1) { - comedi_error(dev, - "length 2 chanlist must be channels 0,1 or channels 2,3"); - err++; - } - if (cmd->chanlist_len == 3) { - comedi_error(dev, - "chanlist must have 1,2 or 4 channels"); - err++; - } - if (CR_AREF(cmd->chanlist[0]) != CR_AREF(cmd->chanlist[1]) || - CR_AREF(cmd->chanlist[2]) != CR_AREF(cmd->chanlist[3])) { - comedi_error(dev, - "channels 0/1 and 2/3 must have the same analog reference"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= a2150_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -405,15 +402,11 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct a2150_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned long timer_base = dev->iobase + I8253_BASE_REG; unsigned long lock_flags; unsigned int old_config_bits = devpriv->config_bits; unsigned int trigger_bits; - if (!dev->irq || !devpriv->dma) { - comedi_error(dev, - " irq and dma required, cannot do hardware conversions"); - return -1; - } if (cmd->flags & TRIG_RT) { comedi_error(dev, " dma incompatible with hard real-time interrupt (TRIG_RT), aborting"); @@ -477,7 +470,8 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); /* may need to wait 72 sampling periods if timing was changed */ - i8254_load(dev->iobase + I8253_BASE_REG, 0, 2, 72, 0); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_write(timer_base, 0, 2, 72); /* setup start triggering */ trigger_bits = 0; @@ -504,20 +498,29 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* start acquisition for soft trigger */ if (cmd->start_src == TRIG_NOW) outw(0, dev->iobase + FIFO_START_REG); -#ifdef A2150_DEBUG - ni_dump_regs(dev); -#endif return 0; } +static int a2150_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STATUS_REG); + if (status & FNE_BIT) + return 0; + return -EBUSY; +} + static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct a2150_private *devpriv = dev->private; - unsigned int i, n; - static const int timeout = 100000; - static const int filter_delay = 36; + unsigned int n; + int ret; /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); @@ -547,37 +550,21 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, * there is a 35.6 sample delay for data to get through the * antialias filter */ - for (n = 0; n < filter_delay; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + for (n = 0; n < 36; n++) { + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + inw(dev->iobase + FIFO_DATA_REG); } /* read data */ for (n = 0; n < insn->n; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } -#ifdef A2150_DEBUG - ni_dump_regs(dev); -#endif + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + data[n] = inw(dev->iobase + FIFO_DATA_REG); -#ifdef A2150_DEBUG - printk(" data is %i\n", data[n]); -#endif data[n] ^= 0x8000; } @@ -682,13 +669,12 @@ static int a2150_set_chanlist(struct comedi_device *dev, devpriv->config_bits |= CHANNEL_BITS(0x4 | start_channel); break; case 2: - if (start_channel == 0) { + if (start_channel == 0) devpriv->config_bits |= CHANNEL_BITS(0x2); - } else if (start_channel == 2) { + else if (start_channel == 2) devpriv->config_bits |= CHANNEL_BITS(0x3); - } else { + else return -1; - } break; case 4: devpriv->config_bits |= CHANNEL_BITS(0x1); @@ -710,7 +696,7 @@ static int a2150_probe(struct comedi_device *dev) static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct a2150_board *thisboard = comedi_board(dev); + const struct a2150_board *thisboard; struct a2150_private *devpriv; struct comedi_subdevice *s; unsigned int irq = it->options[1]; @@ -719,55 +705,43 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) int i; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_request_region(dev, it->options[0], A2150_SIZE); if (ret) return ret; - /* grab our IRQ */ - if (irq) { - /* check that irq is supported */ - if (irq < 3 || irq == 8 || irq == 13 || irq > 15) { - printk(" invalid irq line %u\n", irq); - return -EINVAL; - } - if (request_irq(irq, a2150_interrupt, 0, - dev->driver->driver_name, dev)) { - printk("unable to allocate irq %u\n", irq); - return -EINVAL; + dev->board_ptr = a2150_boards + a2150_probe(dev); + thisboard = comedi_board(dev); + dev->board_name = thisboard->name; + + if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) || + irq == 14 || irq == 15) { + ret = request_irq(irq, a2150_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); + dev->irq = irq; } - devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); - dev->irq = irq; } - /* initialize dma */ - if (dma) { - if (dma == 4 || dma > 7) { - printk(" invalid dma channel %u\n", dma); - return -EINVAL; - } - if (request_dma(dma, dev->driver->driver_name)) { - printk(" failed to allocate dma channel %u\n", dma); - return -EINVAL; - } - devpriv->dma = dma; - devpriv->dma_buffer = - kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); - if (devpriv->dma_buffer == NULL) - return -ENOMEM; - disable_dma(dma); - set_dma_mode(dma, DMA_MODE_READ); + if (dev->irq && dma <= 7 && dma != 4) { + ret = request_dma(dma, dev->board_name); + if (ret == 0) { + devpriv->dma = dma; + devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE, + GFP_KERNEL | GFP_DMA); + if (!devpriv->dma_buffer) + return -ENOMEM; - devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); - } + disable_dma(dma); + set_dma_mode(dma, DMA_MODE_READ); - dev->board_ptr = a2150_boards + a2150_probe(dev); - thisboard = comedi_board(dev); - dev->board_name = thisboard->name; + devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); + } + } ret = comedi_alloc_subdevices(dev, 1); if (ret) @@ -775,17 +749,20 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* analog input subdevice */ s = &dev->subdevices[0]; - dev->read_subdev = s; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER; s->n_chan = 4; - s->len_chanlist = 4; s->maxdata = 0xffff; s->range_table = &range_a2150; - s->do_cmd = a2150_ai_cmd; - s->do_cmdtest = a2150_ai_cmdtest; s->insn_read = a2150_ai_rinsn; - s->cancel = a2150_cancel; + if (dev->irq && devpriv->dma) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmd = a2150_ai_cmd; + s->do_cmdtest = a2150_ai_cmdtest; + s->cancel = a2150_cancel; + } /* need to do this for software counting of completed conversions, to * prevent hardware count from stopping acquisition */ diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index e080053c697..c93b47bcca5 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -1,330 +1,339 @@ /* - comedi/drivers/ni_at_ao.c - Driver for NI AT-AO-6/10 boards - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000,2002 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ni_at_ao -Description: National Instruments AT-AO-6/10 -Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10) -Status: should work -Author: ds -Updated: Sun Dec 26 12:26:28 EST 2004 - -Configuration options: - [0] - I/O port base address - [1] - IRQ (unused) - [2] - DMA (unused) - [3] - analog output range, set by jumpers on hardware (0 for -10 to 10V - bipolar, 1 for 0V to 10V unipolar) - -*/ -/* - * Register-level programming information can be found in NI - * document 320379.pdf. + * ni_at_ao.c + * Driver for NI AT-AO-6/10 boards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000,2002 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -#include "../comedidev.h" +/* + * Driver: ni_at_ao + * Description: National Instruments AT-AO-6/10 + * Devices: (National Instruments) AT-AO-6 [at-ao-6] + * (National Instruments) AT-AO-10 [at-ao-10] + * Status: should work + * Author: David A. Schleef <ds@schleef.org> + * Updated: Sun Dec 26 12:26:28 EST 2004 + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ (unused) + * [2] - DMA (unused) + * [3] - analog output range, set by jumpers on hardware + * 0 for -10 to 10V bipolar + * 1 for 0V to 10V unipolar + */ -#include <linux/ioport.h> +#include <linux/module.h> -/* board egisters */ -/* registers with _2_ are accessed when GRP2WR is set in CFG1 */ +#include "../comedidev.h" -#define ATAO_SIZE 0x20 - -#define ATAO_2_DMATCCLR 0x00 /* W 16 */ -#define ATAO_DIN 0x00 /* R 16 */ -#define ATAO_DOUT 0x00 /* W 16 */ - -#define ATAO_CFG2 0x02 /* W 16 */ -#define CALLD1 0x8000 -#define CALLD0 0x4000 -#define FFRTEN 0x2000 -#define DAC2S8 0x1000 -#define DAC2S6 0x0800 -#define DAC2S4 0x0400 -#define DAC2S2 0x0200 -#define DAC2S0 0x0100 -#define LDAC8 0x0080 -#define LDAC6 0x0040 -#define LDAC4 0x0020 -#define LDAC2 0x0010 -#define LDAC0 0x0008 -#define PROMEN 0x0004 -#define SCLK 0x0002 -#define SDATA 0x0001 - -#define ATAO_2_INT1CLR 0x02 /* W 16 */ - -#define ATAO_CFG3 0x04 /* W 16 */ -#define DMAMODE 0x0040 -#define CLKOUT 0x0020 -#define RCLKEN 0x0010 -#define DOUTEN2 0x0008 -#define DOUTEN1 0x0004 -#define EN2_5V 0x0002 -#define SCANEN 0x0001 - -#define ATAO_2_INT2CLR 0x04 /* W 16 */ - -#define ATAO_82C53_BASE 0x06 /* RW 8 */ - -#define ATAO_82C53_CNTR1 0x06 /* RW 8 */ -#define ATAO_82C53_CNTR2 0x07 /* RW 8 */ -#define ATAO_82C53_CNTR3 0x08 /* RW 8 */ -#define ATAO_82C53_CNTRCMD 0x09 /* W 8 */ -#define CNTRSEL1 0x80 -#define CNTRSEL0 0x40 -#define RWSEL1 0x20 -#define RWSEL0 0x10 -#define MODESEL2 0x08 -#define MODESEL1 0x04 -#define MODESEL0 0x02 -#define BCDSEL 0x01 - /* read-back command */ -#define COUNT 0x20 -#define STATUS 0x10 -#define CNTR3 0x08 -#define CNTR2 0x04 -#define CNTR1 0x02 - /* status */ -#define OUT 0x80 -#define _NULL 0x40 -#define RW1 0x20 -#define RW0 0x10 -#define MODE2 0x08 -#define MODE1 0x04 -#define MODE0 0x02 -#define BCD 0x01 - -#define ATAO_2_RTSISHFT 0x06 /* W 8 */ -#define RSI 0x01 - -#define ATAO_2_RTSISTRB 0x07 /* W 8 */ - -#define ATAO_CFG1 0x0a /* W 16 */ -#define EXTINT2EN 0x8000 -#define EXTINT1EN 0x4000 -#define CNTINT2EN 0x2000 -#define CNTINT1EN 0x1000 -#define TCINTEN 0x0800 -#define CNT1SRC 0x0400 -#define CNT2SRC 0x0200 -#define FIFOEN 0x0100 -#define GRP2WR 0x0080 -#define EXTUPDEN 0x0040 -#define DMARQ 0x0020 -#define DMAEN 0x0010 -#define CH_mask 0x000f -#define ATAO_STATUS 0x0a /* R 16 */ -#define FH 0x0040 -#define FE 0x0020 -#define FF 0x0010 -#define INT2 0x0008 -#define INT1 0x0004 -#define TCINT 0x0002 -#define PROMOUT 0x0001 - -#define ATAO_FIFO_WRITE 0x0c /* W 16 */ -#define ATAO_FIFO_CLEAR 0x0c /* R 16 */ -#define ATAO_DACn(x) (0x0c + 2*(x)) /* W */ +#include "8253.h" /* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. + * Register map + * + * Register-level programming information can be found in NI + * document 320379.pdf. */ +#define ATAO_DIO_REG 0x00 +#define ATAO_CFG2_REG 0x02 +#define ATAO_CFG2_CALLD_NOP (0 << 14) +#define ATAO_CFG2_CALLD(x) ((((x) >> 3) + 1) << 14) +#define ATAO_CFG2_FFRTEN (1 << 13) +#define ATAO_CFG2_DACS(x) (1 << (((x) / 2) + 8)) +#define ATAO_CFG2_LDAC(x) (1 << (((x) / 2) + 3)) +#define ATAO_CFG2_PROMEN (1 << 2) +#define ATAO_CFG2_SCLK (1 << 1) +#define ATAO_CFG2_SDATA (1 << 0) +#define ATAO_CFG3_REG 0x04 +#define ATAO_CFG3_DMAMODE (1 << 6) +#define ATAO_CFG3_CLKOUT (1 << 5) +#define ATAO_CFG3_RCLKEN (1 << 4) +#define ATAO_CFG3_DOUTEN2 (1 << 3) +#define ATAO_CFG3_DOUTEN1 (1 << 2) +#define ATAO_CFG3_EN2_5V (1 << 1) +#define ATAO_CFG3_SCANEN (1 << 0) +#define ATAO_82C53_BASE 0x06 +#define ATAO_CFG1_REG 0x0a +#define ATAO_CFG1_EXTINT2EN (1 << 15) +#define ATAO_CFG1_EXTINT1EN (1 << 14) +#define ATAO_CFG1_CNTINT2EN (1 << 13) +#define ATAO_CFG1_CNTINT1EN (1 << 12) +#define ATAO_CFG1_TCINTEN (1 << 11) +#define ATAO_CFG1_CNT1SRC (1 << 10) +#define ATAO_CFG1_CNT2SRC (1 << 9) +#define ATAO_CFG1_FIFOEN (1 << 8) +#define ATAO_CFG1_GRP2WR (1 << 7) +#define ATAO_CFG1_EXTUPDEN (1 << 6) +#define ATAO_CFG1_DMARQ (1 << 5) +#define ATAO_CFG1_DMAEN (1 << 4) +#define ATAO_CFG1_CH(x) (((x) & 0xf) << 0) +#define ATAO_STATUS_REG 0x0a +#define ATAO_STATUS_FH (1 << 6) +#define ATAO_STATUS_FE (1 << 5) +#define ATAO_STATUS_FF (1 << 4) +#define ATAO_STATUS_INT2 (1 << 3) +#define ATAO_STATUS_INT1 (1 << 2) +#define ATAO_STATUS_TCINT (1 << 1) +#define ATAO_STATUS_PROMOUT (1 << 0) +#define ATAO_FIFO_WRITE_REG 0x0c +#define ATAO_FIFO_CLEAR_REG 0x0c +#define ATAO_AO_REG(x) (0x0c + ((x) * 2)) + +/* registers with _2_ are accessed when GRP2WR is set in CFG1 */ +#define ATAO_2_DMATCCLR_REG 0x00 +#define ATAO_2_INT1CLR_REG 0x02 +#define ATAO_2_INT2CLR_REG 0x04 +#define ATAO_2_RTSISHFT_REG 0x06 +#define ATAO_2_RTSISHFT_RSI (1 << 0) +#define ATAO_2_RTSISTRB_REG 0x07 + struct atao_board { const char *name; int n_ao_chans; }; -struct atao_private { +static const struct atao_board atao_boards[] = { + { + .name = "at-ao-6", + .n_ao_chans = 6, + }, { + .name = "at-ao-10", + .n_ao_chans = 10, + }, +}; +struct atao_private { unsigned short cfg1; - unsigned short cfg2; unsigned short cfg3; /* Used for AO readback */ unsigned int ao_readback[10]; + + /* Used for caldac readback */ + unsigned char caldac[21]; }; -static void atao_reset(struct comedi_device *dev) +static void atao_select_reg_group(struct comedi_device *dev, int group) { struct atao_private *devpriv = dev->private; - /* This is the reset sequence described in the manual */ - - devpriv->cfg1 = 0; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - - outb(RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); - outb(0x03, dev->iobase + ATAO_82C53_CNTR1); - outb(CNTRSEL0 | RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); - - devpriv->cfg2 = 0; - outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); - - devpriv->cfg3 = 0; - outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); - - inw(dev->iobase + ATAO_FIFO_CLEAR); - - devpriv->cfg1 |= GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - - outw(0, dev->iobase + ATAO_2_INT1CLR); - outw(0, dev->iobase + ATAO_2_INT2CLR); - outw(0, dev->iobase + ATAO_2_DMATCCLR); - - devpriv->cfg1 &= ~GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); + if (group) + devpriv->cfg1 |= ATAO_CFG1_GRP2WR; + else + devpriv->cfg1 &= ~ATAO_CFG1_GRP2WR; + outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); } -static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int atao_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; int i; - int chan = CR_CHAN(insn->chanspec); - short bits; + + if (chan == 0) + atao_select_reg_group(dev, 1); for (i = 0; i < insn->n; i++) { - bits = data[i] - 0x800; - if (chan == 0) { - devpriv->cfg1 |= GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - } - outw(bits, dev->iobase + ATAO_DACn(chan)); - if (chan == 0) { - devpriv->cfg1 &= ~GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - } - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + devpriv->ao_readback[chan] = val; + + /* munge offset binary (unsigned) to two's complement */ + val = comedi_offset_munge(s, val); + outw(val, dev->iobase + ATAO_AO_REG(chan)); } - return i; + if (chan == 0) + atao_select_reg_group(dev, 0); + + return insn->n; } -static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int atao_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; - return i; + return insn->n; } static int atao_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outw(s->state, dev->iobase + ATAO_DOUT); - } + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + ATAO_DIO_REG); - data[1] = inw(dev->iobase + ATAO_DIN); + data[1] = inw(dev->iobase + ATAO_DIO_REG); return insn->n; } static int atao_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct atao_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - unsigned int mask, bit; - - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - - mask = (chan < 4) ? 0x0f : 0xf0; - bit = (chan < 4) ? DOUTEN1 : DOUTEN2; - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - devpriv->cfg3 |= bit; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - devpriv->cfg3 &= ~bit; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + if (s->io_bits & 0x0f) + devpriv->cfg3 |= ATAO_CFG3_DOUTEN1; + else + devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN1; + if (s->io_bits & 0xf0) + devpriv->cfg3 |= ATAO_CFG3_DOUTEN2; + else + devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN2; - outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); + outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG); - return 1; + return insn->n; } /* - * Figure 2-1 in the manual shows 3 chips labeled DAC8800, which - * are 8-channel 8-bit DACs. These are most likely the calibration - * DACs. It is not explicitly stated in the manual how to access - * the caldacs, but we can guess. + * There are three DAC8800 TrimDACs on the board. These are 8-channel, + * 8-bit DACs that are used to calibrate the Analog Output channels. + * The factory default calibration values are stored in the EEPROM. + * The TrimDACs, and EEPROM addresses, are mapped as: + * + * Channel EEPROM Description + * ----------------- ------ ----------------------------------- + * 0 - DAC0 Chan 0 0x30 AO Channel 0 Offset + * 1 - DAC0 Chan 1 0x31 AO Channel 0 Gain + * 2 - DAC0 Chan 2 0x32 AO Channel 1 Offset + * 3 - DAC0 Chan 3 0x33 AO Channel 1 Gain + * 4 - DAC0 Chan 4 0x34 AO Channel 2 Offset + * 5 - DAC0 Chan 5 0x35 AO Channel 2 Gain + * 6 - DAC0 Chan 6 0x36 AO Channel 3 Offset + * 7 - DAC0 Chan 7 0x37 AO Channel 3 Gain + * 8 - DAC1 Chan 0 0x38 AO Channel 4 Offset + * 9 - DAC1 Chan 1 0x39 AO Channel 4 Gain + * 10 - DAC1 Chan 2 0x3a AO Channel 5 Offset + * 11 - DAC1 Chan 3 0x3b AO Channel 5 Gain + * 12 - DAC1 Chan 4 0x3c 2.5V Offset + * 13 - DAC1 Chan 5 0x3d AO Channel 6 Offset (at-ao-10 only) + * 14 - DAC1 Chan 6 0x3e AO Channel 6 Gain (at-ao-10 only) + * 15 - DAC1 Chan 7 0x3f AO Channel 7 Offset (at-ao-10 only) + * 16 - DAC2 Chan 0 0x40 AO Channel 7 Gain (at-ao-10 only) + * 17 - DAC2 Chan 1 0x41 AO Channel 8 Offset (at-ao-10 only) + * 18 - DAC2 Chan 2 0x42 AO Channel 8 Gain (at-ao-10 only) + * 19 - DAC2 Chan 3 0x43 AO Channel 9 Offset (at-ao-10 only) + * 20 - DAC2 Chan 4 0x44 AO Channel 9 Gain (at-ao-10 only) + * DAC2 Chan 5 0x45 Reserved + * DAC2 Chan 6 0x46 Reserved + * DAC2 Chan 7 0x47 Reserved */ +static int atao_calib_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int bitstring; + unsigned int val; + int bit; + + if (insn->n == 0) + return 0; + + devpriv->caldac[chan] = data[insn->n - 1] & s->maxdata; + + /* write the channel and last data value to the caldac */ + bitstring = ((chan & 0x7) << 8) | devpriv->caldac[chan]; + + /* clock the bitstring to the caldac; MSB -> LSB */ + for (bit = 1 << 10; bit; bit >>= 1) { + val = (bit & bitstring) ? ATAO_CFG2_SDATA : 0; + + outw(val, dev->iobase + ATAO_CFG2_REG); + outw(val | ATAO_CFG2_SCLK, dev->iobase + ATAO_CFG2_REG); + } + + /* strobe the caldac to load the value */ + outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG); + outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); + + return insn->n; +} + static int atao_calib_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; + for (i = 0; i < insn->n; i++) - data[i] = 0; /* XXX */ + data[i] = devpriv->caldac[chan]; + return insn->n; } -static int atao_calib_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void atao_reset(struct comedi_device *dev) { struct atao_private *devpriv = dev->private; - unsigned int bitstring, bit; - unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long timer_base = dev->iobase + ATAO_82C53_BASE; - bitstring = ((chan & 0x7) << 8) | (data[insn->n - 1] & 0xff); + /* This is the reset sequence described in the manual */ - for (bit = 1 << (11 - 1); bit; bit >>= 1) { - outw(devpriv->cfg2 | ((bit & bitstring) ? SDATA : 0), - dev->iobase + ATAO_CFG2); - outw(devpriv->cfg2 | SCLK | ((bit & bitstring) ? SDATA : 0), - dev->iobase + ATAO_CFG2); - } - /* strobe the appropriate caldac */ - outw(devpriv->cfg2 | (((chan >> 3) + 1) << 14), - dev->iobase + ATAO_CFG2); - outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); + devpriv->cfg1 = 0; + outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); - return insn->n; + /* Put outputs of counter 1 and counter 2 in a high state */ + i8254_set_mode(timer_base, 0, 0, I8254_MODE4 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE4 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x0003); + + outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); + + devpriv->cfg3 = 0; + outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG); + + inw(dev->iobase + ATAO_FIFO_CLEAR_REG); + + atao_select_reg_group(dev, 1); + outw(0, dev->iobase + ATAO_2_INT1CLR_REG); + outw(0, dev->iobase + ATAO_2_INT2CLR_REG); + outw(0, dev->iobase + ATAO_2_DMATCCLR_REG); + atao_select_reg_group(dev, 0); } static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -332,78 +341,58 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) const struct atao_board *board = comedi_board(dev); struct atao_private *devpriv; struct comedi_subdevice *s; - int ao_unipolar; int ret; - ao_unipolar = it->options[3]; - - ret = comedi_request_region(dev, it->options[0], ATAO_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x20); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; + /* Analog Output subdevice */ s = &dev->subdevices[0]; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_ao_chans; - s->maxdata = (1 << 12) - 1; - if (ao_unipolar) - s->range_table = &range_unipolar10; - else - s->range_table = &range_bipolar10; - s->insn_write = &atao_ao_winsn; - s->insn_read = &atao_ao_rinsn; - + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_ao_chans; + s->maxdata = 0x0fff; + s->range_table = it->options[3] ? &range_unipolar10 : &range_bipolar10; + s->insn_write = atao_ao_insn_write; + s->insn_read = atao_ao_insn_read; + + /* Digital I/O subdevice */ s = &dev->subdevices[1]; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = atao_dio_insn_bits; - s->insn_config = atao_dio_insn_config; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = atao_dio_insn_bits; + s->insn_config = atao_dio_insn_config; - s = &dev->subdevices[2]; /* caldac subdevice */ - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 21; - s->maxdata = 0xff; - s->insn_read = atao_calib_insn_read; - s->insn_write = atao_calib_insn_write; - + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = (board->n_ao_chans * 2) + 1; + s->maxdata = 0xff; + s->insn_read = atao_calib_insn_read; + s->insn_write = atao_calib_insn_write; + + /* EEPROM subdevice */ s = &dev->subdevices[3]; - /* eeprom subdevice */ - /* s->type=COMEDI_SUBD_EEPROM; */ - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; atao_reset(dev); - printk(KERN_INFO "\n"); - return 0; } -static const struct atao_board atao_boards[] = { - { - .name = "ai-ao-6", - .n_ao_chans = 6, - }, { - .name = "ai-ao-10", - .n_ao_chans = 10, - }, -}; - static struct comedi_driver ni_at_ao_driver = { .driver_name = "ni_at_ao", .module = THIS_MODULE, @@ -416,5 +405,5 @@ static struct comedi_driver ni_at_ao_driver = { module_comedi_driver(ni_at_ao_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for NI AT-AO-6/10 boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index 713edd55a91..d03935257b9 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -89,17 +89,15 @@ are not supported. */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/delay.h> #include <linux/isapnp.h> #include "ni_stc.h" #include "8255.h" -#undef DEBUG - #define ATMIO 1 #undef PCIMIO @@ -437,19 +435,6 @@ static int ni_atmio_attach(struct comedi_device *dev, if (ret) return ret; -#ifdef DEBUG - /* board existence sanity check */ - { - int i; - - printk(" board fingerprint:"); - for (i = 0; i < 16; i += 2) { - printk(" %04x %02x", inw(dev->iobase + i), - inb(dev->iobase + i + 1)); - } - } -#endif - /* get board type */ board = ni_getboardtype(dev); diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index da7396f9429..6ad27f50c6e 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -30,11 +30,10 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) * */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - #include "comedi_fc.h" #include "8255.h" @@ -97,7 +96,6 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) #define CLOCK_100_HZ 0x8F25 /* Other miscellaneous defines */ #define ATMIO16D_SIZE 32 /* bus address range */ -#define ATMIO16D_TIMEOUT 10 struct atmio16_board_t { @@ -106,40 +104,31 @@ struct atmio16_board_t { }; /* range structs */ -static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, { - BIP_RANGE - (10), - BIP_RANGE - (1), - BIP_RANGE - (0.1), - BIP_RANGE - (0.02) - } +static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) + } }; -static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { 4, { - BIP_RANGE - (5), - BIP_RANGE - (0.5), - BIP_RANGE - (0.05), - BIP_RANGE - (0.01) - } +static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { + 4, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_atmio16d_ai_unipolar = { 4, { - UNI_RANGE - (10), - UNI_RANGE - (1), - UNI_RANGE - (0.1), - UNI_RANGE - (0.02) - } +static const struct comedi_lrange range_atmio16d_ai_unipolar = { + 4, { + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) + } }; /* private data struct */ @@ -230,9 +219,9 @@ static void reset_atmio16d(struct comedi_device *dev) static irqreturn_t atmio16d_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; - comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG)); + comedi_buf_put(s, inw(dev->iobase + AD_FIFO_REG)); comedi_event(dev, s); return IRQ_HANDLED; @@ -458,16 +447,32 @@ static int atmio16d_ai_cancel(struct comedi_device *dev, return 0; } -/* Mode 0 is used to get a single conversion on demand */ +static int atmio16d_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STAT_REG); + if (status & STAT_AD_CONVAVAIL) + return 0; + if (status & STAT_AD_OVERFLOW) { + outw(0, dev->iobase + AD_CLEAR_REG); + return -EOVERFLOW; + } + return -EBUSY; +} + static int atmio16d_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct atmio16d_private *devpriv = dev->private; - int i, t; + int i; int chan; int gain; - int status; + int ret; chan = CR_CHAN(insn->chanspec); gain = CR_RANGE(insn->chanspec); @@ -483,31 +488,17 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { /* start the conversion */ outw(0, dev->iobase + START_CONVERT_REG); + /* wait for it to finish */ - for (t = 0; t < ATMIO16D_TIMEOUT; t++) { - /* check conversion status */ - status = inw(dev->iobase + STAT_REG); - if (status & STAT_AD_CONVAVAIL) { - /* read the data now */ - data[i] = inw(dev->iobase + AD_FIFO_REG); - /* change to two's complement if need be */ - if (devpriv->adc_coding == adc_2comp) - data[i] ^= 0x800; - break; - } - if (status & STAT_AD_OVERFLOW) { - printk(KERN_INFO "atmio16d: a/d FIFO overflow\n"); - outw(0, dev->iobase + AD_CLEAR_REG); - - return -ETIME; - } - } - /* end waiting, now check if it timed out */ - if (t == ATMIO16D_TIMEOUT) { - printk(KERN_INFO "atmio16d: timeout\n"); + ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0); + if (ret) + return ret; - return -ETIME; - } + /* read the data now */ + data[i] = inw(dev->iobase + AD_FIFO_REG); + /* change to two's complement if need be */ + if (devpriv->adc_coding == adc_2comp) + data[i] ^= 0x800; } return i; @@ -559,13 +550,12 @@ static int atmio16d_ao_insn_write(struct comedi_device *dev, static int atmio16d_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] | data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + MIO_16_DIG_OUT_REG); - } + data[1] = inw(dev->iobase + MIO_16_DIG_IN_REG); return insn->n; @@ -577,15 +567,19 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev, unsigned int *data) { struct atmio16d_private *devpriv = dev->private; - int i; - int mask; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - for (i = 0; i < insn->n; i++) { - mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0; - s->io_bits &= ~mask; - if (data[i]) - s->io_bits |= mask; - } devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0 | COMREG2_DOUTEN1); if (s->io_bits & 0x0f) devpriv->com_reg_2_state |= COMREG2_DOUTEN0; @@ -593,7 +587,7 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev, devpriv->com_reg_2_state |= COMREG2_DOUTEN1; outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2); - return i; + return insn->n; } /* @@ -634,7 +628,6 @@ static int atmio16d_attach(struct comedi_device *dev, const struct atmio16_board_t *board = comedi_board(dev); struct atmio16d_private *devpriv; struct comedi_subdevice *s; - unsigned int irq; int ret; ret = comedi_request_region(dev, it->options[0], ATMIO16D_SIZE); @@ -645,27 +638,18 @@ static int atmio16d_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* reset the atmio16d hardware */ reset_atmio16d(dev); - /* check if our interrupt is available and get it */ - irq = it->options[1]; - if (irq) { - - ret = request_irq(irq, atmio16d_interrupt, 0, "atmio16d", dev); - if (ret < 0) { - printk(KERN_INFO "failed to allocate irq %u\n", irq); - return ret; - } - dev->irq = irq; - printk(KERN_INFO "( irq = %u )\n", irq); - } else { - printk(KERN_INFO "( no irq )"); + if (it->options[1]) { + ret = request_irq(it->options[1], atmio16d_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } /* set device options */ @@ -681,16 +665,11 @@ static int atmio16d_attach(struct comedi_device *dev, /* setup sub-devices */ s = &dev->subdevices[0]; - dev->read_subdev = s; /* ai subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = (devpriv->adc_mux ? 16 : 8); - s->len_chanlist = 16; s->insn_read = atmio16d_ai_insn_read; - s->do_cmdtest = atmio16d_ai_cmdtest; - s->do_cmd = atmio16d_ai_cmd; - s->cancel = atmio16d_ai_cancel; s->maxdata = 0xfff; /* 4095 decimal */ switch (devpriv->adc_range) { case adc_bipolar10: @@ -703,6 +682,14 @@ static int atmio16d_attach(struct comedi_device *dev, s->range_table = &range_atmio16d_ai_unipolar; break; } + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 16; + s->do_cmdtest = atmio16d_ai_cmdtest; + s->do_cmd = atmio16d_ai_cmd; + s->cancel = atmio16d_ai_cancel; + } /* ao subdevice */ s = &dev->subdevices[1]; @@ -742,10 +729,13 @@ static int atmio16d_attach(struct comedi_device *dev, /* 8255 subdevice */ s = &dev->subdevices[3]; - if (board->has_8255) - subdev_8255_init(dev, s, NULL, dev->iobase); - else + if (board->has_8255) { + ret = subdev_8255_init(dev, s, NULL, dev->iobase); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* don't yet know how to deal with counter/timers */ #if 0 @@ -755,7 +745,6 @@ static int atmio16d_attach(struct comedi_device *dev, s->n_chan = 0; s->maxdata = 0 #endif - printk("\n"); return 0; } diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 3c50e31ecc6..728bf7f14f7 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -45,9 +45,9 @@ 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/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include "../comedidev.h" @@ -72,56 +72,75 @@ Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf static int daq700_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + unsigned int mask; + unsigned int val; - if (data[0] & 0xff) + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) outb(s->state & 0xff, dev->iobase + DIO_W); } - data[1] = s->state & 0xff; - data[1] |= inb(dev->iobase + DIO_R) << 8; + val = s->state & 0xff; + val |= inb(dev->iobase + DIO_R) << 8; + + data[1] = val; return insn->n; } static int daq700_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int chan = 1 << CR_CHAN(insn->chanspec); - - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - break; - case INSN_CONFIG_DIO_OUTPUT: - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT; - break; - default: - return -EINVAL; - } + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + + /* The DIO channels are not configurable, fix the io_bits */ + s->io_bits = 0x00ff; return insn->n; } +static int daq700_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + STA_R2); + if ((status & 0x03)) + return -EOVERFLOW; + status = inb(dev->iobase + STA_R1); + if ((status & 0x02)) + return -ENODATA; + if ((status & 0x11) == 0x01) + return 0; + return -EBUSY; +} + static int daq700_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, chan; + int n, chan; int d; - unsigned int status; - enum { TIMEOUT = 100 }; + int ret; chan = CR_CHAN(insn->chanspec); /* write channel to multiplexer */ /* set mask scan bit high to disable scanning */ outb(chan | 0x80, dev->iobase + CMD_R1); + /* mux needs 2us to really settle [Fred Brooks]. */ + udelay(2); /* convert n samples */ for (n = 0; n < insn->n; n++) { @@ -130,30 +149,12 @@ static int daq700_ai_rinsn(struct comedi_device *dev, outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */ /* mode 1 out0 H, L to H, start conversion */ outb(0x32, dev->iobase + CMO_R); + /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inb(dev->iobase + STA_R2); - if ((status & 0x03) != 0) { - dev_info(dev->class_dev, - "Overflow/run Error\n"); - return -EOVERFLOW; - } - status = inb(dev->iobase + STA_R1); - if ((status & 0x02) != 0) { - dev_info(dev->class_dev, "Data Error\n"); - return -ENODATA; - } - if ((status & 0x11) == 0x01) { - /* ADC conversion complete */ - break; - } - udelay(1); - } - if (i == TIMEOUT) { - dev_info(dev->class_dev, - "timeout during ADC conversion\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0); + if (ret) + return ret; + /* read data */ d = inw(dev->iobase + ADFIFO_R); /* mangle the data as necessary */ @@ -216,7 +217,6 @@ static int daq700_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->insn_bits = daq700_dio_insn_bits; s->insn_config = daq700_dio_insn_config; - s->state = 0; s->io_bits = 0x00ff; /* DAQCard-700 ai */ @@ -230,11 +230,6 @@ static int daq700_auto_attach(struct comedi_device *dev, s->insn_read = daq700_ai_rinsn; daq700_ai_config(dev, s); - dev_info(dev->class_dev, "%s: %s, io 0x%lx\n", - dev->driver->driver_name, - dev->board_name, - dev->iobase); - return 0; } diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index d3d4eb9356a..925e82c65b2 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -3,8 +3,8 @@ Driver for National Instruments PCMCIA DAQ-Card DIO-24 Copyright (C) 2002 Daniel Vecino Castel <dvecino@able.es> - PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13 - from the pcmcia package. + PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 + 2001/08/24 12:13:13 from the pcmcia package. The initial developer of the pcmcia dummy_cs.c code is David A. Hinds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. @@ -31,6 +31,7 @@ This is just a wrapper around the 8255.o driver to properly handle the PCMCIA interface. */ +#include <linux/module.h> #include "../comedidev.h" #include <pcmcia/cistpl.h> diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index f161e70b3a0..3e3f940fa57 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -57,6 +57,7 @@ * 320502b (lab-pc+) */ +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/io.h> @@ -64,83 +65,14 @@ #include "../comedidev.h" -#include <asm/dma.h> - #include "8253.h" #include "8255.h" #include "comedi_fc.h" #include "ni_labpc.h" - -/* - * Register map (all registers are 8-bit) - */ -#define STAT1_REG 0x00 /* R: Status 1 reg */ -#define STAT1_DAVAIL (1 << 0) -#define STAT1_OVERRUN (1 << 1) -#define STAT1_OVERFLOW (1 << 2) -#define STAT1_CNTINT (1 << 3) -#define STAT1_GATA0 (1 << 5) -#define STAT1_EXTGATA0 (1 << 6) -#define CMD1_REG 0x00 /* W: Command 1 reg */ -#define CMD1_MA(x) (((x) & 0x7) << 0) -#define CMD1_TWOSCMP (1 << 3) -#define CMD1_GAIN(x) (((x) & 0x7) << 4) -#define CMD1_SCANEN (1 << 7) -#define CMD2_REG 0x01 /* W: Command 2 reg */ -#define CMD2_PRETRIG (1 << 0) -#define CMD2_HWTRIG (1 << 1) -#define CMD2_SWTRIG (1 << 2) -#define CMD2_TBSEL (1 << 3) -#define CMD2_2SDAC0 (1 << 4) -#define CMD2_2SDAC1 (1 << 5) -#define CMD2_LDAC(x) (1 << (6 + (x))) -#define CMD3_REG 0x02 /* W: Command 3 reg */ -#define CMD3_DMAEN (1 << 0) -#define CMD3_DIOINTEN (1 << 1) -#define CMD3_DMATCINTEN (1 << 2) -#define CMD3_CNTINTEN (1 << 3) -#define CMD3_ERRINTEN (1 << 4) -#define CMD3_FIFOINTEN (1 << 5) -#define ADC_START_CONVERT_REG 0x03 /* W: Start Convert reg */ -#define DAC_LSB_REG(x) (0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */ -#define DAC_MSB_REG(x) (0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */ -#define ADC_FIFO_CLEAR_REG 0x08 /* W: A/D FIFO Clear reg */ -#define ADC_FIFO_REG 0x0a /* R: A/D FIFO reg */ -#define DMATC_CLEAR_REG 0x0a /* W: DMA Interrupt Clear reg */ -#define TIMER_CLEAR_REG 0x0c /* W: Timer Interrupt Clear reg */ -#define CMD6_REG 0x0e /* W: Command 6 reg */ -#define CMD6_NRSE (1 << 0) -#define CMD6_ADCUNI (1 << 1) -#define CMD6_DACUNI(x) (1 << (2 + (x))) -#define CMD6_HFINTEN (1 << 5) -#define CMD6_DQINTEN (1 << 6) -#define CMD6_SCANUP (1 << 7) -#define CMD4_REG 0x0f /* W: Command 3 reg */ -#define CMD4_INTSCAN (1 << 0) -#define CMD4_EOIRCV (1 << 1) -#define CMD4_ECLKDRV (1 << 2) -#define CMD4_SEDIFF (1 << 3) -#define CMD4_ECLKRCV (1 << 4) -#define DIO_BASE_REG 0x10 /* R/W: 8255 DIO base reg */ -#define COUNTER_A_BASE_REG 0x14 /* R/W: 8253 Counter A base reg */ -#define COUNTER_B_BASE_REG 0x18 /* R/W: 8253 Counter B base reg */ -#define CMD5_REG 0x1c /* W: Command 5 reg */ -#define CMD5_WRTPRT (1 << 2) -#define CMD5_DITHEREN (1 << 3) -#define CMD5_CALDACLD (1 << 4) -#define CMD5_SCLK (1 << 5) -#define CMD5_SDATA (1 << 6) -#define CMD5_EEPROMCS (1 << 7) -#define STAT2_REG 0x1d /* R: Status 2 reg */ -#define STAT2_PROMOUT (1 << 0) -#define STAT2_OUTA1 (1 << 1) -#define STAT2_FIFONHF (1 << 2) -#define INTERVAL_COUNT_REG 0x1e /* W: Interval Counter Data reg */ -#define INTERVAL_STROBE_REG 0x1f /* W: Interval Counter Strobe reg */ +#include "ni_labpc_regs.h" +#include "ni_labpc_isadma.h" #define LABPC_SIZE 0x20 /* size of ISA io region */ -#define LABPC_TIMER_BASE 500 /* 2 MHz master clock */ -#define LABPC_ADC_TIMEOUT 1000 enum scan_mode { MODE_SINGLE_CHAN, @@ -239,43 +171,39 @@ static const struct labpc_boardinfo labpc_boards[] = { }; #endif -/* size in bytes of dma buffer */ -static const int dma_buffer_size = 0xff00; -/* 2 bytes per sample */ -static const int sample_size = 2; - -static int labpc_counter_load(struct comedi_device *dev, - unsigned long base_address, - unsigned int counter_number, - unsigned int count, unsigned int mode) +static void labpc_counter_load(struct comedi_device *dev, + unsigned long base_address, + unsigned int counter_number, + unsigned int count, + unsigned int mode) { const struct labpc_boardinfo *board = comedi_board(dev); - if (board->has_mmio) - return i8254_mm_load((void __iomem *)base_address, 0, - counter_number, count, mode); - else - return i8254_load(base_address, 0, counter_number, count, mode); + if (board->has_mmio) { + void __iomem *mmio_base = (void __iomem *)base_address; + + i8254_mm_set_mode(mmio_base, 0, counter_number, mode); + i8254_mm_write(mmio_base, 0, counter_number, count); + } else { + i8254_set_mode(base_address, 0, counter_number, mode); + i8254_write(base_address, 0, counter_number, count); + } } -static int labpc_counter_set_mode(struct comedi_device *dev, - unsigned long base_address, - unsigned int counter_number, - unsigned int mode) +static void labpc_counter_set_mode(struct comedi_device *dev, + unsigned long base_address, + unsigned int counter_number, + unsigned int mode) { const struct labpc_boardinfo *board = comedi_board(dev); - if (board->has_mmio) - return i8254_mm_set_mode((void __iomem *)base_address, 0, - counter_number, mode); - else - return i8254_set_mode(base_address, 0, counter_number, mode); -} + if (board->has_mmio) { + void __iomem *mmio_base = (void __iomem *)base_address; -static bool labpc_range_is_unipolar(struct comedi_subdevice *s, - unsigned int range) -{ - return s->range_table->range[range].min >= 0; + i8254_mm_set_mode(mmio_base, 0, counter_number, mode); + } else { + i8254_set_mode(base_address, 0, counter_number, mode); + } } static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) @@ -343,7 +271,7 @@ static void labpc_setup_cmd6_reg(struct comedi_device *dev, devpriv->cmd6 &= ~CMD6_NRSE; /* bipolar or unipolar range? */ - if (labpc_range_is_unipolar(s, range)) + if (comedi_range_is_unipolar(s, range)) devpriv->cmd6 |= CMD6_ADCUNI; else devpriv->cmd6 &= ~CMD6_ADCUNI; @@ -386,19 +314,17 @@ static void labpc_clear_adc_fifo(struct comedi_device *dev) labpc_read_adc_fifo(dev); } -static int labpc_ai_wait_for_data(struct comedi_device *dev, - int timeout) +static int labpc_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { struct labpc_private *devpriv = dev->private; - int i; - for (i = 0; i < timeout; i++) { - devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); - if (devpriv->stat1 & STAT1_DAVAIL) - return 0; - udelay(1); - } - return -ETIME; + devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); + if (devpriv->stat1 & STAT1_DAVAIL) + return 0; + return -EBUSY; } static int labpc_ai_insn_read(struct comedi_device *dev, @@ -430,10 +356,8 @@ static int labpc_ai_insn_read(struct comedi_device *dev, devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG); /* initialize pacer counter to prevent any problems */ - ret = labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, - 0, I8254_MODE2); - if (ret) - return ret; + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, I8254_MODE2); labpc_clear_adc_fifo(dev); @@ -441,7 +365,7 @@ static int labpc_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG); - ret = labpc_ai_wait_for_data(dev, LABPC_ADC_TIMEOUT); + ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0); if (ret) return ret; @@ -451,32 +375,6 @@ static int labpc_ai_insn_read(struct comedi_device *dev, return insn->n; } -#ifdef CONFIG_ISA_DMA_API -/* utility function that suggests a dma transfer size in bytes */ -static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd) -{ - unsigned int size; - unsigned int freq; - - if (cmd->convert_src == TRIG_TIMER) - freq = 1000000000 / cmd->convert_arg; - /* return some default value */ - else - freq = 0xffffffff; - - /* make buffer fill in no more than 1/3 second */ - size = (freq / 3) * sample_size; - - /* set a minimum and maximum size allowed */ - if (size > dma_buffer_size) - size = dma_buffer_size - dma_buffer_size % sample_size; - else if (size < sample_size) - size = sample_size; - - return size; -} -#endif - static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd, enum scan_mode mode) { @@ -562,13 +460,13 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, * clock speed on convert and scan counters) */ devpriv->divisor_b0 = (scan_period - 1) / - (LABPC_TIMER_BASE * max_counter_value) + 1; + (I8254_OSC_BASE_2MHZ * max_counter_value) + 1; if (devpriv->divisor_b0 < min_counter_value) devpriv->divisor_b0 = min_counter_value; if (devpriv->divisor_b0 > max_counter_value) devpriv->divisor_b0 = max_counter_value; - base_period = LABPC_TIMER_BASE * devpriv->divisor_b0; + base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0; /* set a0 for conversion frequency and b1 for scan frequency */ switch (cmd->flags & TRIG_ROUND_MASK) { @@ -613,22 +511,20 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, * calculate cascaded counter values * that give desired scan timing */ - i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE, - &(devpriv->divisor_b1), - &(devpriv->divisor_b0), - &scan_period, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor_b1, + &devpriv->divisor_b0, + &scan_period, cmd->flags); labpc_set_ai_scan_period(cmd, mode, scan_period); } else if (convert_period) { /* * calculate cascaded counter values * that give desired conversion timing */ - i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE, - &(devpriv->divisor_a0), - &(devpriv->divisor_b0), - &convert_period, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor_a0, + &devpriv->divisor_b0, + &convert_period, cmd->flags); labpc_set_ai_convert_period(cmd, mode, convert_period); } } @@ -655,72 +551,60 @@ static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) return 0; } -static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, - const struct comedi_cmd *cmd, - enum scan_mode mode) +static int labpc_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - int channel, range, aref, i; - - if (cmd->chanlist == NULL) - return 0; + enum scan_mode mode = labpc_ai_scan_mode(cmd); + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; if (mode == MODE_SINGLE_CHAN) return 0; - if (mode == MODE_SINGLE_CHAN_INTERVAL) { - if (cmd->chanlist_len > 0xff) { - comedi_error(dev, - "ni_labpc: chanlist too long for single channel interval mode\n"); - return 1; - } - } - - channel = CR_CHAN(cmd->chanlist[0]); - range = CR_RANGE(cmd->chanlist[0]); - aref = CR_AREF(cmd->chanlist[0]); - for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); switch (mode) { + case MODE_SINGLE_CHAN: + break; case MODE_SINGLE_CHAN_INTERVAL: - if (CR_CHAN(cmd->chanlist[i]) != channel) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; + if (chan != chan0) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; } break; case MODE_MULT_CHAN_UP: - if (CR_CHAN(cmd->chanlist[i]) != i) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; + if (chan != i) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; } break; case MODE_MULT_CHAN_DOWN: - if (CR_CHAN(cmd->chanlist[i]) != - cmd->chanlist_len - i - 1) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; + if (chan != (cmd->chanlist_len - i - 1)) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; } break; - default: - dev_err(dev->class_dev, - "ni_labpc: bug! in chanlist check\n"); - return 1; - break; } - if (CR_RANGE(cmd->chanlist[i]) != range) { - comedi_error(dev, - "entries in chanlist must all have the same range\n"); - return 1; + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same range\n"); + return -EINVAL; } - if (CR_AREF(cmd->chanlist[i]) != aref) { - comedi_error(dev, - "entries in chanlist must all have the same reference\n"); - return 1; + if (aref != aref0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same reference\n"); + return -EINVAL; } } @@ -770,8 +654,14 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg == TRIG_NOW) + switch (cmd->start_src) { + case TRIG_NOW: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* start_arg value is ignored */ + break; + } if (!cmd->chanlist_len) err |= -EINVAL; @@ -820,7 +710,11 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - if (labpc_ai_chanlist_invalid(dev, cmd, mode)) + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= labpc_ai_check_chanlist(dev, s, cmd); + + if (err) return 5; return 0; @@ -841,7 +735,6 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) unsigned int aref = CR_AREF(chanspec); enum transfer_type xfer; unsigned long flags; - int ret; /* make sure board is disabled before setting up acquisition */ labpc_cancel(dev, s); @@ -856,38 +749,28 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * load counter a1 with count of 3 * (pc+ manual says this is minimum allowed) using mode 0 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, - 1, 3, I8254_MODE0); + labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, + 1, 3, I8254_MODE0); } else { /* just put counter a1 in mode 0 to set its output low */ - ret = labpc_counter_set_mode(dev, - dev->iobase + COUNTER_A_BASE_REG, - 1, I8254_MODE0); - } - if (ret) { - comedi_error(dev, "error loading counter a1"); - return ret; + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 1, I8254_MODE0); } -#ifdef CONFIG_ISA_DMA_API - /* figure out what method we will use to transfer data */ - if (devpriv->dma_chan && /* need a dma channel allocated */ - /* - * dma unsafe at RT priority, - * and too much setup time for TRIG_WAKE_EOS for - */ - (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0) { + /* figure out what method we will use to transfer data */ + if (labpc_have_dma_chan(dev) && + /* dma unsafe at RT priority, + * and too much setup time for TRIG_WAKE_EOS */ + (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0) xfer = isa_dma_transfer; - /* pc-plus has no fifo-half full interrupt */ - } else -#endif - if (board->is_labpc1200 && - /* wake-end-of-scan should interrupt on fifo not empty */ - (cmd->flags & TRIG_WAKE_EOS) == 0 && - /* make sure we are taking more than just a few points */ - (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) { + else if (/* pc-plus has no fifo-half full interrupt */ + board->is_labpc1200 && + /* wake-end-of-scan should interrupt on fifo not empty */ + (cmd->flags & TRIG_WAKE_EOS) == 0 && + /* make sure we are taking more than just a few points */ + (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) xfer = fifo_half_full_transfer; - } else + else xfer = fifo_not_empty_transfer; devpriv->current_transfer = xfer; @@ -916,76 +799,37 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* set up pacing */ labpc_adc_timing(dev, cmd, mode); /* load counter b0 in mode 3 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, - 0, devpriv->divisor_b0, I8254_MODE3); - if (ret < 0) { - comedi_error(dev, "error loading counter b0"); - return -1; - } + labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, + 0, devpriv->divisor_b0, I8254_MODE3); } /* set up conversion pacing */ if (labpc_ai_convert_period(cmd, mode)) { /* load counter a0 in mode 2 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, - 0, devpriv->divisor_a0, I8254_MODE2); + labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, devpriv->divisor_a0, I8254_MODE2); } else { /* initialize pacer counter to prevent any problems */ - ret = labpc_counter_set_mode(dev, - dev->iobase + COUNTER_A_BASE_REG, - 0, I8254_MODE2); - } - if (ret) { - comedi_error(dev, "error loading counter a0"); - return ret; + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, I8254_MODE2); } /* set up scan pacing */ if (labpc_ai_scan_period(cmd, mode)) { /* load counter b1 in mode 2 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, - 1, devpriv->divisor_b1, I8254_MODE2); - if (ret < 0) { - comedi_error(dev, "error loading counter b1"); - return -1; - } + labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, + 1, devpriv->divisor_b1, I8254_MODE2); } labpc_clear_adc_fifo(dev); -#ifdef CONFIG_ISA_DMA_API - /* set up dma transfer */ - if (xfer == isa_dma_transfer) { - unsigned long irq_flags; - - irq_flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma_chan); - set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); - /* set appropriate size of transfer */ - devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd); - if (cmd->stop_src == TRIG_COUNT && - devpriv->count * sample_size < devpriv->dma_transfer_size) { - devpriv->dma_transfer_size = - devpriv->count * sample_size; - } - set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_chan); - release_dma_lock(irq_flags); - /* enable board's dma */ - devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN); - } else - devpriv->cmd3 &= ~(CMD3_DMAEN | CMD3_DMATCINTEN); -#endif + if (xfer == isa_dma_transfer) + labpc_setup_dma(dev, s); /* enable error interrupts */ devpriv->cmd3 |= CMD3_ERRINTEN; /* enable fifo not empty interrupt? */ if (xfer == fifo_not_empty_transfer) devpriv->cmd3 |= CMD3_FIFOINTEN; - else - devpriv->cmd3 &= ~CMD3_FIFOINTEN; devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG); /* setup any external triggering/pacing (cmd4 register) */ @@ -1026,80 +870,13 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -#ifdef CONFIG_ISA_DMA_API -static void labpc_drain_dma(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - int status; - unsigned long flags; - unsigned int max_points, num_points, residue, leftover; - int i; - - status = devpriv->stat1; - - flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma_chan); - - /* figure out how many points to read */ - max_points = devpriv->dma_transfer_size / sample_size; - /* residue is the number of points left to be done on the dma - * transfer. It should always be zero at this point unless - * the stop_src is set to external triggering. - */ - residue = get_dma_residue(devpriv->dma_chan) / sample_size; - num_points = max_points - residue; - if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT) - num_points = devpriv->count; - - /* figure out how many points will be stored next time */ - leftover = 0; - if (async->cmd.stop_src != TRIG_COUNT) { - leftover = devpriv->dma_transfer_size / sample_size; - } else if (devpriv->count > num_points) { - leftover = devpriv->count - num_points; - if (leftover > max_points) - leftover = max_points; - } - - /* write data to comedi buffer */ - for (i = 0; i < num_points; i++) - cfc_write_to_buffer(s, devpriv->dma_buffer[i]); - - if (async->cmd.stop_src == TRIG_COUNT) - devpriv->count -= num_points; - - /* set address and count for next transfer */ - set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); - set_dma_count(devpriv->dma_chan, leftover * sample_size); - release_dma_lock(flags); - - async->events |= COMEDI_CB_BLOCK; -} - -static void handle_isa_dma(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - - labpc_drain_dma(dev); - - enable_dma(devpriv->dma_chan); - - /* clear dma tc interrupt */ - devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG); -} -#endif - /* read all available samples from ai fifo */ static int labpc_drain_fifo(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - short data; struct comedi_async *async = dev->read_subdev->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned short data; const int timeout = 10000; unsigned int i; @@ -1108,7 +885,7 @@ static int labpc_drain_fifo(struct comedi_device *dev) for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout; i++) { /* quit if we have all the data we want */ - if (async->cmd.stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) { if (devpriv->count == 0) break; devpriv->count--; @@ -1130,12 +907,10 @@ static int labpc_drain_fifo(struct comedi_device *dev) * when acquisition is terminated by stop_src == TRIG_EXT). */ static void labpc_drain_dregs(struct comedi_device *dev) { -#ifdef CONFIG_ISA_DMA_API struct labpc_private *devpriv = dev->private; if (devpriv->current_transfer == isa_dma_transfer) labpc_drain_dma(dev); -#endif labpc_drain_fifo(dev); } @@ -1157,7 +932,6 @@ static irqreturn_t labpc_interrupt(int irq, void *d) async = s->async; cmd = &async->cmd; - async->events = 0; /* read board status */ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); @@ -1175,23 +949,14 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overrun"); return IRQ_HANDLED; } -#ifdef CONFIG_ISA_DMA_API - if (devpriv->current_transfer == isa_dma_transfer) { - /* - * if a dma terminal count of external stop trigger - * has occurred - */ - if (devpriv->stat1 & STAT1_GATA0 || - (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1)) { - handle_isa_dma(dev); - } - } else -#endif + if (devpriv->current_transfer == isa_dma_transfer) + labpc_handle_dma_status(dev); + else labpc_drain_fifo(dev); if (devpriv->stat1 & STAT1_CNTINT) { @@ -1204,7 +969,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overflow"); return IRQ_HANDLED; } @@ -1212,20 +977,17 @@ static irqreturn_t labpc_interrupt(int irq, void *d) if (cmd->stop_src == TRIG_EXT) { if (devpriv->stat2 & STAT2_OUTA1) { labpc_drain_dregs(dev); - labpc_cancel(dev, s); async->events |= COMEDI_CB_EOA; } } /* TRIG_COUNT end of acquisition */ if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->count == 0) { - labpc_cancel(dev, s); + if (devpriv->count == 0) async->events |= COMEDI_CB_EOA; - } } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -1253,7 +1015,7 @@ static int labpc_ao_insn_write(struct comedi_device *dev, /* set range */ if (board->is_labpc1200) { range = CR_RANGE(insn->chanspec); - if (labpc_range_is_unipolar(s, range)) + if (comedi_range_is_unipolar(s, range)) devpriv->cmd6 |= CMD6_DACUNI(channel); else devpriv->cmd6 &= ~CMD6_DACUNI(channel); @@ -1697,10 +1459,9 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) unsigned int dma_chan = it->options[2]; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_request_region(dev, it->options[0], LABPC_SIZE); if (ret) @@ -1710,29 +1471,8 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; -#ifdef CONFIG_ISA_DMA_API - if (dev->irq && (dma_chan == 1 || dma_chan == 3)) { - devpriv->dma_buffer = kmalloc(dma_buffer_size, - GFP_KERNEL | GFP_DMA); - if (devpriv->dma_buffer) { - ret = request_dma(dma_chan, dev->board_name); - if (ret == 0) { - unsigned long dma_flags; - - devpriv->dma_chan = dma_chan; - devpriv->dma_addr = - virt_to_bus(devpriv->dma_buffer); - - dma_flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); - release_dma_lock(dma_flags); - } else { - kfree(devpriv->dma_buffer); - } - } - } -#endif + if (dev->irq) + labpc_init_dma_chan(dev, dma_chan); return 0; } @@ -1741,11 +1481,9 @@ static void labpc_detach(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - if (devpriv) { - kfree(devpriv->dma_buffer); - if (devpriv->dma_chan) - free_dma(devpriv->dma_chan); - } + if (devpriv) + labpc_free_dma_chan(dev); + comedi_legacy_detach(dev); } diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index ce67f4bbb1f..0a8b3223f74 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -53,10 +53,10 @@ NI manuals: */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/slab.h> #include "8253.h" #include "8255.h" @@ -96,10 +96,9 @@ static int labpc_auto_attach(struct comedi_device *dev, if (!link->irq) return -EINVAL; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; return labpc_common_attach(dev, link->irq, IRQF_SHARED); } diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c new file mode 100644 index 00000000000..d9f25fdbb72 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c @@ -0,0 +1,227 @@ +/* + * comedi/drivers/ni_labpc_isadma.c + * ISA DMA support for National Instruments Lab-PC series boards and + * compatibles. + * + * Extracted from ni_labpc.c: + * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include "../comedidev.h" + +#include <asm/dma.h> + +#include "comedi_fc.h" +#include "ni_labpc.h" +#include "ni_labpc_regs.h" +#include "ni_labpc_isadma.h" + +/* size in bytes of dma buffer */ +static const int dma_buffer_size = 0xff00; +/* 2 bytes per sample */ +static const int sample_size = 2; + +/* utility function that suggests a dma transfer size in bytes */ +static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd) +{ + unsigned int size; + unsigned int freq; + + if (cmd->convert_src == TRIG_TIMER) + freq = 1000000000 / cmd->convert_arg; + else + /* return some default value */ + freq = 0xffffffff; + + /* make buffer fill in no more than 1/3 second */ + size = (freq / 3) * sample_size; + + /* set a minimum and maximum size allowed */ + if (size > dma_buffer_size) + size = dma_buffer_size - dma_buffer_size % sample_size; + else if (size < sample_size) + size = sample_size; + + return size; +} + +void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct labpc_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long irq_flags; + + irq_flags = claim_dma_lock(); + disable_dma(devpriv->dma_chan); + /* clear flip-flop to make sure 2-byte registers for + * count and address get set correctly */ + clear_dma_ff(devpriv->dma_chan); + set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); + /* set appropriate size of transfer */ + devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd); + if (cmd->stop_src == TRIG_COUNT && + devpriv->count * sample_size < devpriv->dma_transfer_size) + devpriv->dma_transfer_size = devpriv->count * sample_size; + set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); + enable_dma(devpriv->dma_chan); + release_dma_lock(irq_flags); + /* set CMD3 bits for caller to enable DMA and interrupt */ + devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN); +} +EXPORT_SYMBOL_GPL(labpc_setup_dma); + +void labpc_drain_dma(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + int status; + unsigned long flags; + unsigned int max_points, num_points, residue, leftover; + int i; + + status = devpriv->stat1; + + flags = claim_dma_lock(); + disable_dma(devpriv->dma_chan); + /* clear flip-flop to make sure 2-byte registers for + * count and address get set correctly */ + clear_dma_ff(devpriv->dma_chan); + + /* figure out how many points to read */ + max_points = devpriv->dma_transfer_size / sample_size; + /* residue is the number of points left to be done on the dma + * transfer. It should always be zero at this point unless + * the stop_src is set to external triggering. + */ + residue = get_dma_residue(devpriv->dma_chan) / sample_size; + num_points = max_points - residue; + if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_points) + num_points = devpriv->count; + + /* figure out how many points will be stored next time */ + leftover = 0; + if (cmd->stop_src != TRIG_COUNT) { + leftover = devpriv->dma_transfer_size / sample_size; + } else if (devpriv->count > num_points) { + leftover = devpriv->count - num_points; + if (leftover > max_points) + leftover = max_points; + } + + /* write data to comedi buffer */ + for (i = 0; i < num_points; i++) + cfc_write_to_buffer(s, devpriv->dma_buffer[i]); + + if (cmd->stop_src == TRIG_COUNT) + devpriv->count -= num_points; + + /* set address and count for next transfer */ + set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); + set_dma_count(devpriv->dma_chan, leftover * sample_size); + release_dma_lock(flags); + + async->events |= COMEDI_CB_BLOCK; +} +EXPORT_SYMBOL_GPL(labpc_drain_dma); + +static void handle_isa_dma(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + labpc_drain_dma(dev); + + enable_dma(devpriv->dma_chan); + + /* clear dma tc interrupt */ + devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG); +} + +void labpc_handle_dma_status(struct comedi_device *dev) +{ + const struct labpc_boardinfo *board = comedi_board(dev); + struct labpc_private *devpriv = dev->private; + + /* + * if a dma terminal count of external stop trigger + * has occurred + */ + if (devpriv->stat1 & STAT1_GATA0 || + (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1)) + handle_isa_dma(dev); +} +EXPORT_SYMBOL_GPL(labpc_handle_dma_status); + +int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan) +{ + struct labpc_private *devpriv = dev->private; + void *dma_buffer; + unsigned long dma_flags; + int ret; + + if (dma_chan != 1 && dma_chan != 3) + return -EINVAL; + + dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); + if (!dma_buffer) + return -ENOMEM; + + ret = request_dma(dma_chan, dev->board_name); + if (ret) { + kfree(dma_buffer); + return ret; + } + + devpriv->dma_buffer = dma_buffer; + devpriv->dma_chan = dma_chan; + devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer); + + dma_flags = claim_dma_lock(); + disable_dma(devpriv->dma_chan); + set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); + release_dma_lock(dma_flags); + + return 0; +} +EXPORT_SYMBOL_GPL(labpc_init_dma_chan); + +void labpc_free_dma_chan(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + kfree(devpriv->dma_buffer); + devpriv->dma_buffer = NULL; + if (devpriv->dma_chan) { + free_dma(devpriv->dma_chan); + devpriv->dma_chan = 0; + } +} +EXPORT_SYMBOL_GPL(labpc_free_dma_chan); + +static int __init ni_labpc_isadma_init_module(void) +{ + return 0; +} +module_init(ni_labpc_isadma_init_module); + +static void __exit ni_labpc_isadma_cleanup_module(void) +{ +} +module_exit(ni_labpc_isadma_cleanup_module); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi NI Lab-PC ISA DMA support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/staging/comedi/drivers/ni_labpc_isadma.h new file mode 100644 index 00000000000..771af4bd5a7 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.h @@ -0,0 +1,57 @@ +/* + * ni_labpc ISA DMA support. +*/ + +#ifndef _NI_LABPC_ISADMA_H +#define _NI_LABPC_ISADMA_H + +#define NI_LABPC_HAVE_ISA_DMA IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA) + +#if NI_LABPC_HAVE_ISA_DMA + +static inline bool labpc_have_dma_chan(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + return (bool)devpriv->dma_chan; +} + +int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan); +void labpc_free_dma_chan(struct comedi_device *dev); +void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s); +void labpc_drain_dma(struct comedi_device *dev); +void labpc_handle_dma_status(struct comedi_device *dev); + +#else + +static inline bool labpc_have_dma_chan(struct comedi_device *dev) +{ + return false; +} + +static inline int labpc_init_dma_chan(struct comedi_device *dev, + unsigned int dma_chan) +{ + return -ENOTSUPP; +} + +static inline void labpc_free_dma_chan(struct comedi_device *dev) +{ +} + +static inline void labpc_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ +} + +static inline void labpc_drain_dma(struct comedi_device *dev) +{ +} + +static inline void labpc_handle_dma_status(struct comedi_device *dev) +{ +} + +#endif + +#endif /* _NI_LABPC_ISADMA_H */ diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c index 6c79237b2b5..73959706829 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_pci.c +++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c @@ -29,8 +29,8 @@ * 340914a (pci-1200) */ +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include <linux/pci.h> #include "../comedidev.h" @@ -72,10 +72,9 @@ static int labpc_pci_auto_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->mite = mite_alloc(pcidev); if (!devpriv->mite) @@ -108,7 +107,7 @@ static struct comedi_driver labpc_pci_comedi_driver = { .detach = labpc_pci_detach, }; -static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = { +static const struct pci_device_id labpc_pci_table[] = { { PCI_VDEVICE(NI, 0x161), BOARD_NI_PCI1200 }, { 0 } }; diff --git a/drivers/staging/comedi/drivers/ni_labpc_regs.h b/drivers/staging/comedi/drivers/ni_labpc_regs.h new file mode 100644 index 00000000000..2a274a3e4e7 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_regs.h @@ -0,0 +1,75 @@ +/* + * ni_labpc register definitions. +*/ + +#ifndef _NI_LABPC_REGS_H +#define _NI_LABPC_REGS_H + +/* + * Register map (all registers are 8-bit) + */ +#define STAT1_REG 0x00 /* R: Status 1 reg */ +#define STAT1_DAVAIL (1 << 0) +#define STAT1_OVERRUN (1 << 1) +#define STAT1_OVERFLOW (1 << 2) +#define STAT1_CNTINT (1 << 3) +#define STAT1_GATA0 (1 << 5) +#define STAT1_EXTGATA0 (1 << 6) +#define CMD1_REG 0x00 /* W: Command 1 reg */ +#define CMD1_MA(x) (((x) & 0x7) << 0) +#define CMD1_TWOSCMP (1 << 3) +#define CMD1_GAIN(x) (((x) & 0x7) << 4) +#define CMD1_SCANEN (1 << 7) +#define CMD2_REG 0x01 /* W: Command 2 reg */ +#define CMD2_PRETRIG (1 << 0) +#define CMD2_HWTRIG (1 << 1) +#define CMD2_SWTRIG (1 << 2) +#define CMD2_TBSEL (1 << 3) +#define CMD2_2SDAC0 (1 << 4) +#define CMD2_2SDAC1 (1 << 5) +#define CMD2_LDAC(x) (1 << (6 + (x))) +#define CMD3_REG 0x02 /* W: Command 3 reg */ +#define CMD3_DMAEN (1 << 0) +#define CMD3_DIOINTEN (1 << 1) +#define CMD3_DMATCINTEN (1 << 2) +#define CMD3_CNTINTEN (1 << 3) +#define CMD3_ERRINTEN (1 << 4) +#define CMD3_FIFOINTEN (1 << 5) +#define ADC_START_CONVERT_REG 0x03 /* W: Start Convert reg */ +#define DAC_LSB_REG(x) (0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */ +#define DAC_MSB_REG(x) (0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */ +#define ADC_FIFO_CLEAR_REG 0x08 /* W: A/D FIFO Clear reg */ +#define ADC_FIFO_REG 0x0a /* R: A/D FIFO reg */ +#define DMATC_CLEAR_REG 0x0a /* W: DMA Interrupt Clear reg */ +#define TIMER_CLEAR_REG 0x0c /* W: Timer Interrupt Clear reg */ +#define CMD6_REG 0x0e /* W: Command 6 reg */ +#define CMD6_NRSE (1 << 0) +#define CMD6_ADCUNI (1 << 1) +#define CMD6_DACUNI(x) (1 << (2 + (x))) +#define CMD6_HFINTEN (1 << 5) +#define CMD6_DQINTEN (1 << 6) +#define CMD6_SCANUP (1 << 7) +#define CMD4_REG 0x0f /* W: Command 3 reg */ +#define CMD4_INTSCAN (1 << 0) +#define CMD4_EOIRCV (1 << 1) +#define CMD4_ECLKDRV (1 << 2) +#define CMD4_SEDIFF (1 << 3) +#define CMD4_ECLKRCV (1 << 4) +#define DIO_BASE_REG 0x10 /* R/W: 8255 DIO base reg */ +#define COUNTER_A_BASE_REG 0x14 /* R/W: 8253 Counter A base reg */ +#define COUNTER_B_BASE_REG 0x18 /* R/W: 8253 Counter B base reg */ +#define CMD5_REG 0x1c /* W: Command 5 reg */ +#define CMD5_WRTPRT (1 << 2) +#define CMD5_DITHEREN (1 << 3) +#define CMD5_CALDACLD (1 << 4) +#define CMD5_SCLK (1 << 5) +#define CMD5_SDATA (1 << 6) +#define CMD5_EEPROMCS (1 << 7) +#define STAT2_REG 0x1d /* R: Status 2 reg */ +#define STAT2_PROMOUT (1 << 0) +#define STAT2_OUTA1 (1 << 1) +#define STAT2_FIFONHF (1 << 2) +#define INTERVAL_COUNT_REG 0x1e /* W: Interval Counter Data reg */ +#define INTERVAL_STROBE_REG 0x1f /* W: Interval Counter Strobe reg */ + +#endif /* _NI_LABPC_REGS_H */ diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 3e9f544e67f..7ffdcc07ef9 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -52,20 +52,13 @@ fully tested as yet. Terry Barnaby, BEAM Ltd. */ -/* #define DEBUG_INTERRUPT */ -/* #define DEBUG_STATUS_A */ -/* #define DEBUG_STATUS_B */ - #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/delay.h> #include "8255.h" #include "mite.h" #include "comedi_fc.h" -#ifndef MDPRINTK -#define MDPRINTK(format, args...) -#endif - /* A timeout count */ #define NI_TIMEOUT 1000 static const unsigned old_RTSI_clock_channel = 7; @@ -85,111 +78,109 @@ static const short ni_gainlkup[][16] = { [ai_gain_6143] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }; -static const struct comedi_lrange range_ni_E_ai = { 16, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1, 1), - RANGE(-0.5, 0.5), - RANGE(-0.25, 0.25), - RANGE(-0.1, 0.1), - RANGE(-0.05, 0.05), - RANGE(0, 20), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2), - RANGE(0, 1), - RANGE(0, 0.5), - RANGE(0, 0.2), - RANGE(0, 0.1), - } +static const struct comedi_lrange range_ni_E_ai = { + 16, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.25), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + UNI_RANGE(20), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ai_limited = { 8, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-1, 1), - RANGE(-0.1, - 0.1), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 1), - RANGE(0, 0.1), - } +static const struct comedi_lrange range_ni_E_ai_limited = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(1), + UNI_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ai_limited14 = { 14, { - RANGE(-10, - 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-0.5, - 0.5), - RANGE(-0.2, - 0.2), - RANGE(-0.1, - 0.1), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2), - RANGE(0, 1), - RANGE(0, - 0.5), - RANGE(0, - 0.2), - RANGE(0, - 0.1), - } +static const struct comedi_lrange range_ni_E_ai_limited14 = { + 14, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2), + BIP_RANGE(0.1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ai_bipolar4 = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-0.5, - 0.5), - RANGE(-0.05, - 0.05), - } +static const struct comedi_lrange range_ni_E_ai_bipolar4 = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05) + } }; -static const struct comedi_lrange range_ni_E_ai_611x = { 8, { - RANGE(-50, 50), - RANGE(-20, 20), - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-0.5, 0.5), - RANGE(-0.2, 0.2), - } +static const struct comedi_lrange range_ni_E_ai_611x = { + 8, { + BIP_RANGE(50), + BIP_RANGE(20), + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2) + } }; -static const struct comedi_lrange range_ni_M_ai_622x = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-1, 1), - RANGE(-0.2, 0.2), - } +static const struct comedi_lrange range_ni_M_ai_622x = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.2) + } }; -static const struct comedi_lrange range_ni_M_ai_628x = { 7, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-0.5, 0.5), - RANGE(-0.2, 0.2), - RANGE(-0.1, 0.1), - } +static const struct comedi_lrange range_ni_M_ai_628x = { + 7, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2), + BIP_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ao_ext = { 4, { - RANGE(-10, 10), - RANGE(0, 10), - RANGE_ext(-1, 1), - RANGE_ext(0, 1), - } +static const struct comedi_lrange range_ni_E_ao_ext = { + 4, { + BIP_RANGE(10), + UNI_RANGE(10), + RANGE_ext(-1, 1), + RANGE_ext(0, 1) + } }; static const struct comedi_lrange *const ni_range_lkup[] = { @@ -265,18 +256,6 @@ static int ni_rtsi_insn_config(struct comedi_device *dev, static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_read_eeprom(struct comedi_device *dev, int addr); -#ifdef DEBUG_STATUS_A -static void ni_mio_print_status_a(int status); -#else -#define ni_mio_print_status_a(a) -#endif -#ifdef DEBUG_STATUS_B -static void ni_mio_print_status_b(int status); -#else -#define ni_mio_print_status_b(a) -#endif - -static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s); #ifndef PCIDMA static void ni_handle_fifo_half_full(struct comedi_device *dev); static int ni_ao_fifo_half_empty(struct comedi_device *dev, @@ -292,26 +271,12 @@ static void shutdown_ai_command(struct comedi_device *dev); static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s); - static int ni_8255_callback(int dir, int port, int data, unsigned long arg); -static int ni_gpct_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ni_gpct_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ni_gpct_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); #ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int ni_gpct_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); +static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s); #endif -static int ni_gpct_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index); @@ -321,10 +286,6 @@ static int cs5529_do_conversion(struct comedi_device *dev, static int cs5529_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -#ifdef NI_CS5529_DEBUG -static unsigned int cs5529_config_read(struct comedi_device *dev, - unsigned int reg_select_bits); -#endif static void cs5529_config_write(struct comedi_device *dev, unsigned int value, unsigned int reg_select_bits); @@ -486,11 +447,10 @@ static inline void ni_set_gpct_dma_channel(struct comedi_device *dev, { unsigned bitfield; - if (mite_channel >= 0) { + if (mite_channel >= 0) bitfield = GPCT_DMA_Select_Bits(gpct_index, mite_channel); - } else { + else bitfield = 0; - } ni_set_bitfield(dev, G0_G1_Select, GPCT_DMA_Select_Mask(gpct_index), bitfield); } @@ -723,12 +683,22 @@ static void ni_clear_ai_fifo(struct comedi_device *dev) { const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; + static const int timeout = 10000; + int i; if (board->reg_type == ni_reg_6143) { /* Flush the 6143 data FIFO */ ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */ ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */ - while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */ + /* Wait for complete */ + for (i = 0; i < timeout; i++) { + if (!(ni_readl(AIFIFO_Status_6143) & 0x10)) + break; + udelay(1); + } + if (i == timeout) { + comedi_error(dev, "FIFO flush timeout."); + } } else { devpriv->stc_writew(dev, 1, ADC_FIFO_Clear); if (board->reg_type == ni_reg_625x) { @@ -894,7 +864,7 @@ static void ni_sync_ai_dma(struct comedi_device *dev) spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ai_mite_chan) - mite_sync_input_dma(devpriv->ai_mite_chan, s->async); + mite_sync_input_dma(devpriv->ai_mite_chan, s); spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } @@ -906,9 +876,8 @@ static void mite_handle_b_linkc(struct mite_struct *mite, unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); - if (devpriv->ao_mite_chan) { - mite_sync_output_dma(devpriv->ao_mite_chan, s->async); - } + if (devpriv->ao_mite_chan) + mite_sync_output_dma(devpriv->ao_mite_chan, s); spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } @@ -956,9 +925,8 @@ static void ni_handle_eos(struct comedi_device *dev, struct comedi_subdevice *s) #endif } /* handle special case of single scan using AI_End_On_End_Of_Scan */ - if ((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) { + if ((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) shutdown_ai_command(dev); - } } static void shutdown_ai_command(struct comedi_device *dev) @@ -975,32 +943,6 @@ static void shutdown_ai_command(struct comedi_device *dev) s->async->events |= COMEDI_CB_EOA; } -static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | - COMEDI_CB_EOA)) { - switch (s->index) { - case NI_AI_SUBDEV: - ni_ai_reset(dev, s); - break; - case NI_AO_SUBDEV: - ni_ao_reset(dev, s); - break; - case NI_GPCT0_SUBDEV: - case NI_GPCT1_SUBDEV: - ni_gpct_cancel(dev, s); - break; - case NI_DIO_SUBDEV: - ni_cdio_cancel(dev, s); - break; - default: - break; - } - } - comedi_event(dev, s); -} - static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index) { @@ -1012,8 +954,7 @@ static void handle_gpct_interrupt(struct comedi_device *dev, ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index], s); - if (s->async->events) - ni_event(dev, s); + cfc_handle_events(dev, s); #endif } @@ -1022,19 +963,15 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) struct ni_private *devpriv = dev->private; unsigned short ack = 0; - if (a_status & AI_SC_TC_St) { + if (a_status & AI_SC_TC_St) ack |= AI_SC_TC_Interrupt_Ack; - } - if (a_status & AI_START1_St) { + if (a_status & AI_START1_St) ack |= AI_START1_Interrupt_Ack; - } - if (a_status & AI_START_St) { + if (a_status & AI_START_St) ack |= AI_START_Interrupt_Ack; - } - if (a_status & AI_STOP_St) { + if (a_status & AI_STOP_St) /* not sure why we used to ack the START here also, instead of doing it independently. Frank Hess 2007-07-06 */ - ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack */ ; - } + ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack */; if (ack) devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register); } @@ -1049,16 +986,9 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (s->type == COMEDI_SUBD_UNUSED) return; -#ifdef DEBUG_INTERRUPT - printk - ("ni_mio_common: interrupt: a_status=%04x ai_mite_status=%08x\n", - status, ai_mite_status); - ni_mio_print_status_a(status); -#endif #ifdef PCIDMA - if (ai_mite_status & CHSR_LINKC) { + if (ai_mite_status & CHSR_LINKC) ni_sync_ai_dma(dev); - } if (ai_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | @@ -1066,7 +996,6 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, printk ("unknown mite interrupt, ack! (ai_mite_status=%08x)\n", ai_mite_status); - /* mite_print_chsr(ai_mite_status); */ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; /* disable_irq(dev->irq); */ } @@ -1083,7 +1012,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (comedi_is_subdevice_running(s)) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - ni_event(dev, s); + cfc_handle_events(dev, s); } return; } @@ -1091,7 +1020,6 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, AI_SC_TC_Error_St)) { printk("ni_mio_common: ai error a_status=%04x\n", status); - ni_mio_print_status_a(status); shutdown_ai_command(dev); @@ -1099,17 +1027,12 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (status & (AI_Overrun_St | AI_Overflow_St)) s->async->events |= COMEDI_CB_OVERFLOW; - ni_event(dev, s); - + cfc_handle_events(dev, s); return; } if (status & AI_SC_TC_St) { -#ifdef DEBUG_INTERRUPT - printk("ni_mio_common: SC_TC interrupt\n"); -#endif - if (!devpriv->ai_continuous) { + if (!devpriv->ai_continuous) shutdown_ai_command(dev); - } } } #ifndef PCIDMA @@ -1128,20 +1051,10 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, } #endif /* !PCIDMA */ - if ((status & AI_STOP_St)) { + if ((status & AI_STOP_St)) ni_handle_eos(dev, s); - } - - ni_event(dev, s); -#ifdef DEBUG_INTERRUPT - status = devpriv->stc_readw(dev, AI_Status_1_Register); - if (status & Interrupt_A_St) { - printk - ("handle_a_interrupt: didn't clear interrupt? status=0x%x\n", - status); - } -#endif + cfc_handle_events(dev, s); } static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) @@ -1149,27 +1062,20 @@ static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) struct ni_private *devpriv = dev->private; unsigned short ack = 0; - if (b_status & AO_BC_TC_St) { + if (b_status & AO_BC_TC_St) ack |= AO_BC_TC_Interrupt_Ack; - } - if (b_status & AO_Overrun_St) { + if (b_status & AO_Overrun_St) ack |= AO_Error_Interrupt_Ack; - } - if (b_status & AO_START_St) { + if (b_status & AO_START_St) ack |= AO_START_Interrupt_Ack; - } - if (b_status & AO_START1_St) { + if (b_status & AO_START1_St) ack |= AO_START1_Interrupt_Ack; - } - if (b_status & AO_UC_TC_St) { + if (b_status & AO_UC_TC_St) ack |= AO_UC_TC_Interrupt_Ack; - } - if (b_status & AO_UI2_TC_St) { + if (b_status & AO_UI2_TC_St) ack |= AO_UI2_TC_Interrupt_Ack; - } - if (b_status & AO_UPDATE_St) { + if (b_status & AO_UPDATE_St) ack |= AO_UPDATE_Interrupt_Ack; - } if (ack) devpriv->stc_writew(dev, ack, Interrupt_B_Ack_Register); } @@ -1181,17 +1087,10 @@ static void handle_b_interrupt(struct comedi_device *dev, struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV]; /* unsigned short ack=0; */ -#ifdef DEBUG_INTERRUPT - printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n", - b_status, ao_mite_status); - ni_mio_print_status_b(b_status); -#endif - #ifdef PCIDMA /* Currently, mite.c requires us to handle LINKC */ - if (ao_mite_status & CHSR_LINKC) { + if (ao_mite_status & CHSR_LINKC) mite_handle_b_linkc(devpriv->mite, dev); - } if (ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | @@ -1199,7 +1098,6 @@ static void handle_b_interrupt(struct comedi_device *dev, printk ("unknown mite interrupt, ack! (ao_mite_status=%08x)\n", ao_mite_status); - /* mite_print_chsr(ao_mite_status); */ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } #endif @@ -1213,12 +1111,9 @@ static void handle_b_interrupt(struct comedi_device *dev, s->async->events |= COMEDI_CB_OVERFLOW; } - if (b_status & AO_BC_TC_St) { - MDPRINTK - ("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n", - b_status, devpriv->stc_readw(dev, AO_Status_2_Register)); + if (b_status & AO_BC_TC_St) s->async->events |= COMEDI_CB_EOA; - } + #ifndef PCIDMA if (b_status & AO_FIFO_Request_St) { int ret; @@ -1234,52 +1129,8 @@ static void handle_b_interrupt(struct comedi_device *dev, } #endif - ni_event(dev, s); -} - -#ifdef DEBUG_STATUS_A -static const char *const status_a_strings[] = { - "passthru0", "fifo", "G0_gate", "G0_TC", - "stop", "start", "sc_tc", "start1", - "start2", "sc_tc_error", "overflow", "overrun", - "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_a" -}; - -static void ni_mio_print_status_a(int status) -{ - int i; - - printk("A status:"); - for (i = 15; i >= 0; i--) { - if (status & (1 << i)) { - printk(" %s", status_a_strings[i]); - } - } - printk("\n"); + cfc_handle_events(dev, s); } -#endif - -#ifdef DEBUG_STATUS_B -static const char *const status_b_strings[] = { - "passthru1", "fifo", "G1_gate", "G1_TC", - "UI2_TC", "UPDATE", "UC_TC", "BC_TC", - "start1", "overrun", "start", "bc_tc_error", - "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_b" -}; - -static void ni_mio_print_status_b(int status) -{ - int i; - - printk("B status:"); - for (i = 15; i >= 0; i--) { - if (status & (1 << i)) { - printk(" %s", status_b_strings[i]); - } - } - printk("\n"); -} -#endif #ifndef PCIDMA @@ -1291,14 +1142,14 @@ static void ni_ao_fifo_load(struct comedi_device *dev, struct comedi_cmd *cmd = &async->cmd; int chan; int i; - short d; + unsigned short d; u32 packed_data; int range; int err = 1; chan = async->cur_chan; for (i = 0; i < n; i++) { - err &= comedi_buf_get(async, &d); + err &= comedi_buf_get(s, &d); if (err == 0) break; @@ -1308,7 +1159,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev, packed_data = d & 0xffff; /* 6711 only has 16 bit wide ao fifo */ if (board->reg_type != ni_reg_6711) { - err &= comedi_buf_get(async, &d); + err &= comedi_buf_get(s, &d); if (err == 0) break; chan++; @@ -1323,9 +1174,8 @@ static void ni_ao_fifo_load(struct comedi_device *dev, chan %= cmd->chanlist_len; } async->cur_chan = chan; - if (err == 0) { + if (err == 0) async->events |= COMEDI_CB_OVERFLOW; - } } /* @@ -1350,7 +1200,7 @@ static int ni_ao_fifo_half_empty(struct comedi_device *dev, const struct ni_board_struct *board = comedi_board(dev); int n; - n = comedi_buf_read_n_available(s->async); + n = comedi_buf_read_n_available(s); if (n == 0) { s->async->events |= COMEDI_CB_OVERFLOW; return 0; @@ -1380,7 +1230,7 @@ static int ni_ao_prep_fifo(struct comedi_device *dev, ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x); /* load some data */ - n = comedi_buf_read_n_available(s->async); + n = comedi_buf_read_n_available(s); if (n == 0) return 0; @@ -1402,7 +1252,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev, int i; if (board->reg_type == ni_reg_611x) { - short data[2]; + unsigned short data[2]; u32 dl; for (i = 0; i < n / 2; i++) { @@ -1419,7 +1269,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev, cfc_write_to_buffer(s, data[0]); } } else if (board->reg_type == ni_reg_6143) { - short data[2]; + unsigned short data[2]; u32 dl; /* This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed */ @@ -1510,9 +1360,9 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; - short data[2]; + unsigned short data[2]; u32 dl; - short fifo_empty; + unsigned short fifo_empty; int i; if (board->reg_type == ni_reg_611x) { @@ -1576,7 +1426,7 @@ static void get_last_sample_611x(struct comedi_device *dev) const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv __maybe_unused = dev->private; struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; - short data; + unsigned short data; u32 dl; if (board->reg_type != ni_reg_611x) @@ -1595,7 +1445,7 @@ static void get_last_sample_6143(struct comedi_device *dev) const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv __maybe_unused = dev->private; struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; - short data; + unsigned short data; u32 dl; if (board->reg_type != ni_reg_6143) @@ -1618,10 +1468,11 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, { struct ni_private *devpriv = dev->private; struct comedi_async *async = s->async; - unsigned int i; + struct comedi_cmd *cmd = &async->cmd; unsigned int length = num_bytes / bytes_per_sample(s); - short *array = data; + unsigned short *array = data; unsigned int *larray = data; + unsigned int i; for (i = 0; i < length; i++) { #ifdef PCIDMA @@ -1635,7 +1486,7 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, else array[i] += devpriv->ai_offset[chan_index]; chan_index++; - chan_index %= async->cmd.chanlist_len; + chan_index %= cmd->chanlist_len; } } @@ -1655,7 +1506,7 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev) /* printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel); */ /* write alloc the entire buffer */ - comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_write_alloc(s, s->async->prealloc_bufsz); spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ai_mite_chan == NULL) { @@ -1695,7 +1546,7 @@ static int ni_ao_setup_MITE_dma(struct comedi_device *dev) return retval; /* read alloc the entire buffer */ - comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_read_alloc(s, s->async->prealloc_bufsz); spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ao_mite_chan) { @@ -2230,7 +2081,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; int err = 0; - int tmp; + unsigned int tmp; unsigned int sources; /* Step 1 : check if triggers are trivially valid */ @@ -2269,17 +2120,19 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_EXT) { - /* external trigger */ - unsigned int tmp = CR_CHAN(cmd->start_arg); + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + tmp = CR_CHAN(cmd->start_arg); if (tmp > 16) tmp = 16; tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE)); err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp); - } else { - /* true for both TRIG_NOW and TRIG_INT */ - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; } if (cmd->scan_begin_src == TRIG_TIMER) { @@ -2391,7 +2244,6 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) unsigned int stop_count; int interrupt_a_enable = 0; - MDPRINTK("ni_ai_cmd\n"); if (dev->irq == 0) { comedi_error(dev, "cannot run command without an irq"); return -EIO; @@ -2629,15 +2481,11 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) ni_set_bits(dev, Interrupt_A_Enable_Register, interrupt_a_enable, 1); - - MDPRINTK("Interrupt_A_Enable_Register = 0x%04x\n", - devpriv->int_a_enable_reg); } else { /* interrupt on nothing */ ni_set_bits(dev, Interrupt_A_Enable_Register, ~0, 0); /* XXX start polling if necessary */ - MDPRINTK("interrupting on nothing\n"); } /* end configuration */ @@ -2663,35 +2511,30 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (retval) return retval; } - /* mite_dump_regs(devpriv->mite); */ #endif - switch (cmd->start_src) { - case TRIG_NOW: + if (cmd->start_src == TRIG_NOW) { /* AI_START1_Pulse */ devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register); s->async->inttrig = NULL; - break; - case TRIG_EXT: + } else if (cmd->start_src == TRIG_EXT) { s->async->inttrig = NULL; - break; - case TRIG_INT: - s->async->inttrig = &ni_ai_inttrig; - break; + } else { /* TRIG_INT */ + s->async->inttrig = ni_ai_inttrig; } - MDPRINTK("exit ni_ai_cmd\n"); - return 0; } -static int ni_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_ai_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { struct ni_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2, @@ -2868,22 +2711,22 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, { const struct ni_board_struct *board = comedi_board(dev); struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int length = num_bytes / sizeof(short); + unsigned int offset = 1 << (board->aobits - 1); + unsigned short *array = data; unsigned int range; unsigned int i; - unsigned int offset; - unsigned int length = num_bytes / sizeof(short); - short *array = data; - offset = 1 << (board->aobits - 1); for (i = 0; i < length; i++) { - range = CR_RANGE(async->cmd.chanlist[chan_index]); + range = CR_RANGE(cmd->chanlist[chan_index]); if (board->ao_unipolar == 0 || (range & 1) == 0) array[i] -= offset; #ifdef PCIDMA array[i] = cpu_to_le16(array[i]); #endif chan_index++; - chan_index %= async->cmd.chanlist_len; + chan_index %= cmd->chanlist_len; } } @@ -3104,17 +2947,19 @@ static int ni_ao_insn_config(struct comedi_device *dev, return -EINVAL; } -static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_ao_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { const struct ni_board_struct *board __maybe_unused = comedi_board(dev); struct ni_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; int interrupt_b_bits; int i; static const int timeout = 1000; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; /* Null trig at beginning prevent ao start trigger from executing more than @@ -3247,11 +3092,10 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->stc_writew(dev, devpriv->ao_mode1, AO_Mode_1_Register); devpriv->ao_mode2 &= ~AO_BC_Initial_Load_Source; devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register); - if (cmd->stop_src == TRIG_NONE) { + if (cmd->stop_src == TRIG_NONE) devpriv->stc_writel(dev, 0xffffff, AO_BC_Load_A_Register); - } else { + else devpriv->stc_writel(dev, 0, AO_BC_Load_A_Register); - } devpriv->stc_writew(dev, AO_BC_Load, AO_Command_1_Register); devpriv->ao_mode2 &= ~AO_UC_Initial_Load_Source; devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register); @@ -3376,7 +3220,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) AO_BC_TC_Interrupt_Enable, 1); } - s->async->inttrig = &ni_ao_inttrig; + s->async->inttrig = ni_ao_inttrig; return 0; } @@ -3387,7 +3231,7 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; int err = 0; - int tmp; + unsigned int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -3417,17 +3261,18 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_EXT) { - /* external trigger */ - unsigned int tmp = CR_CHAN(cmd->start_arg); + switch (cmd->start_src) { + case TRIG_INT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + tmp = CR_CHAN(cmd->start_arg); if (tmp > 18) tmp = 18; tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE)); err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp); - } else { - /* true for both TRIG_NOW and TRIG_INT */ - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; } if (cmd->scan_begin_src == TRIG_TIMER) { @@ -3463,11 +3308,6 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - /* step 5: fix up chanlist */ - - if (err) - return 5; - return 0; } @@ -3512,9 +3352,8 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s) if (board->reg_type & ni_reg_6xxx_mask) { unsigned immediate_bits = 0; unsigned i; - for (i = 0; i < s->n_chan; ++i) { + for (i = 0; i < s->n_chan; ++i) immediate_bits |= 1 << i; - } ao_win_out(immediate_bits, AO_Immediate_671x); ao_win_out(CLEAR_WG, AO_Misc_611x); } @@ -3527,63 +3366,41 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s) static int ni_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni_private *devpriv = dev->private; + int ret; -#ifdef DEBUG_DIO - printk("ni_dio_insn_config() chan=%d io=%d\n", - CR_CHAN(insn->chanspec), data[0]); -#endif - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << CR_CHAN(insn->chanspec); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; devpriv->dio_control &= ~DIO_Pins_Dir_Mask; devpriv->dio_control |= DIO_Pins_Dir(s->io_bits); devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register); - return 1; + return insn->n; } static int ni_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni_private *devpriv = dev->private; -#ifdef DEBUG_DIO - printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], data[1]); -#endif - - if (data[0]) { - /* Perform check to make sure we're not using the - serial part of the dio */ - if ((data[0] & (DIO_SDIN | DIO_SDOUT)) - && devpriv->serial_interval_ns) - return -EBUSY; + /* Make sure we're not using the serial part of the dio */ + if ((data[0] & (DIO_SDIN | DIO_SDOUT)) && devpriv->serial_interval_ns) + return -EBUSY; - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { devpriv->dio_output &= ~DIO_Parallel_Data_Mask; devpriv->dio_output |= DIO_Parallel_Data_Out(s->state); devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register); } + data[1] = devpriv->stc_readw(dev, DIO_Parallel_Input_Register); return insn->n; @@ -3595,32 +3412,15 @@ static int ni_m_series_dio_insn_config(struct comedi_device *dev, unsigned int *data) { struct ni_private *devpriv __maybe_unused = dev->private; + int ret; -#ifdef DEBUG_DIO - printk("ni_m_series_dio_insn_config() chan=%d io=%d\n", - CR_CHAN(insn->chanspec), data[0]); -#endif - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << CR_CHAN(insn->chanspec); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; ni_writel(s->io_bits, M_Offset_DIO_Direction); - return 1; + return insn->n; } static int ni_m_series_dio_insn_bits(struct comedi_device *dev, @@ -3630,27 +3430,35 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev, { struct ni_private *devpriv __maybe_unused = dev->private; -#ifdef DEBUG_DIO - printk("ni_m_series_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], - data[1]); -#endif - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) ni_writel(s->state, M_Offset_Static_Digital_Output); - } + data[1] = ni_readl(M_Offset_Static_Digital_Input); return insn->n; } +static int ni_cdio_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int i; + + for (i = 0; i < cmd->chanlist_len; ++i) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != i) + return -EINVAL; + } + + return 0; +} + static int ni_cdio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; int tmp; - unsigned i; /* Step 1 : check if triggers are trivially valid */ @@ -3690,12 +3498,9 @@ static int ni_cdio_cmdtest(struct comedi_device *dev, if (err) return 4; - /* step 5: check chanlist */ - - for (i = 0; i < cmd->chanlist_len; ++i) { - if (cmd->chanlist[i] != i) - err = 1; - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= ni_cdio_check_chanlist(dev, s, cmd); if (err) return 5; @@ -3734,28 +3539,34 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return -EIO; } retval = ni_request_cdo_mite_channel(dev); - if (retval < 0) { + if (retval < 0) return retval; - } - s->async->inttrig = &ni_cdo_inttrig; + + s->async->inttrig = ni_cdo_inttrig; + return 0; } -static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_cdo_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { #ifdef PCIDMA struct ni_private *devpriv = dev->private; unsigned long flags; #endif + struct comedi_cmd *cmd = &s->async->cmd; int retval = 0; unsigned i; const unsigned timeout = 1000; + if (trig_num != cmd->start_arg) + return -EINVAL; + s->async->inttrig = NULL; /* read alloc the entire buffer */ - comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_read_alloc(s, s->async->prealloc_bufsz); #ifdef PCIDMA spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -3818,9 +3629,8 @@ static void handle_cdio_interrupt(struct comedi_device *dev) unsigned long flags; #endif - if ((board->reg_type & ni_reg_m_series_mask) == 0) { + if ((board->reg_type & ni_reg_m_series_mask) == 0) return; - } #ifdef PCIDMA spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->cdo_mite_chan) { @@ -3831,24 +3641,24 @@ static void handle_cdio_interrupt(struct comedi_device *dev) devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->cdo_mite_chan->channel)); } - mite_sync_output_dma(devpriv->cdo_mite_chan, s->async); + mite_sync_output_dma(devpriv->cdo_mite_chan, s); } spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); #endif cdio_status = ni_readl(M_Offset_CDIO_Status); if (cdio_status & (CDO_Overrun_Bit | CDO_Underflow_Bit)) { -/* printk("cdio error: statux=0x%x\n", cdio_status); */ + /* printk("cdio error: statux=0x%x\n", cdio_status); */ ni_writel(CDO_Error_Interrupt_Confirm_Bit, M_Offset_CDIO_Command); /* XXX just guessing this is needed and does something useful */ s->async->events |= COMEDI_CB_OVERFLOW; } if (cdio_status & CDO_FIFO_Empty_Bit) { -/* printk("cdio fifo empty\n"); */ + /* printk("cdio fifo empty\n"); */ ni_writel(CDO_Empty_FIFO_Interrupt_Enable_Clear_Bit, M_Offset_CDIO_Command); -/* s->async->events |= COMEDI_CB_EOA; */ + /* s->async->events |= COMEDI_CB_EOA; */ } - ni_event(dev, s); + cfc_handle_events(dev, s); } static int ni_serial_insn_config(struct comedi_device *dev, @@ -3864,10 +3674,6 @@ static int ni_serial_insn_config(struct comedi_device *dev, switch (data[0]) { case INSN_CONFIG_SERIAL_CLOCK: - -#ifdef DEBUG_DIO - printk("SPI serial clock Config cd\n", data[1]); -#endif devpriv->serial_hw_mode = 1; devpriv->dio_control |= DIO_HW_Serial_Enable; @@ -3919,9 +3725,8 @@ static int ni_serial_insn_config(struct comedi_device *dev, case INSN_CONFIG_BIDIRECTIONAL_DATA: - if (devpriv->serial_interval_ns == 0) { + if (devpriv->serial_interval_ns == 0) return -EINVAL; - } byte_out = data[1] & 0xFF; @@ -3956,10 +3761,6 @@ static int ni_serial_hw_readwrite8(struct comedi_device *dev, unsigned int status1; int err = 0, count = 20; -#ifdef DEBUG_DIO - printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out); -#endif - devpriv->dio_output &= ~DIO_Serial_Data_Mask; devpriv->dio_output |= DIO_Serial_Data_Out(data_out); devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register); @@ -3993,12 +3794,8 @@ static int ni_serial_hw_readwrite8(struct comedi_device *dev, DIO_Serial_IO_In_Progress_St goes high one bit too early. */ udelay((devpriv->serial_interval_ns + 999) / 1000); - if (data_in != NULL) { + if (data_in != NULL) *data_in = devpriv->stc_readw(dev, DIO_Serial_Input_Register); -#ifdef DEBUG_DIO - printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in); -#endif - } Error: devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register); @@ -4014,10 +3811,6 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, struct ni_private *devpriv = dev->private; unsigned char mask, input = 0; -#ifdef DEBUG_DIO - printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out); -#endif - /* Wait for one bit before transfer */ udelay((devpriv->serial_interval_ns + 999) / 1000); @@ -4026,9 +3819,8 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, because it is a per-subdevice field, and serial is a separate subdevice from DIO. */ devpriv->dio_output &= ~DIO_SDOUT; - if (data_out & mask) { + if (data_out & mask) devpriv->dio_output |= DIO_SDOUT; - } devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register); @@ -4048,15 +3840,12 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, /* Input current bit */ if (devpriv->stc_readw(dev, - DIO_Parallel_Input_Register) & DIO_SDIN) - { -/* printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */ + DIO_Parallel_Input_Register) & DIO_SDIN) { + /* printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */ input |= mask; } } -#ifdef DEBUG_DIO - printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input); -#endif + if (data_in) *data_in = input; @@ -4068,9 +3857,8 @@ static void mio_common_detach(struct comedi_device *dev) struct ni_private *devpriv = dev->private; if (devpriv) { - if (devpriv->counter_dev) { + if (devpriv->counter_dev) ni_gpct_device_destroy(devpriv->counter_dev); - } } } @@ -4089,82 +3877,82 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg) { unsigned stc_register; switch (reg) { - case NITIO_G0_Autoincrement_Reg: + case NITIO_G0_AUTO_INC: stc_register = G_Autoincrement_Register(0); break; - case NITIO_G1_Autoincrement_Reg: + case NITIO_G1_AUTO_INC: stc_register = G_Autoincrement_Register(1); break; - case NITIO_G0_Command_Reg: + case NITIO_G0_CMD: stc_register = G_Command_Register(0); break; - case NITIO_G1_Command_Reg: + case NITIO_G1_CMD: stc_register = G_Command_Register(1); break; - case NITIO_G0_HW_Save_Reg: + case NITIO_G0_HW_SAVE: stc_register = G_HW_Save_Register(0); break; - case NITIO_G1_HW_Save_Reg: + case NITIO_G1_HW_SAVE: stc_register = G_HW_Save_Register(1); break; - case NITIO_G0_SW_Save_Reg: + case NITIO_G0_SW_SAVE: stc_register = G_Save_Register(0); break; - case NITIO_G1_SW_Save_Reg: + case NITIO_G1_SW_SAVE: stc_register = G_Save_Register(1); break; - case NITIO_G0_Mode_Reg: + case NITIO_G0_MODE: stc_register = G_Mode_Register(0); break; - case NITIO_G1_Mode_Reg: + case NITIO_G1_MODE: stc_register = G_Mode_Register(1); break; - case NITIO_G0_LoadA_Reg: + case NITIO_G0_LOADA: stc_register = G_Load_A_Register(0); break; - case NITIO_G1_LoadA_Reg: + case NITIO_G1_LOADA: stc_register = G_Load_A_Register(1); break; - case NITIO_G0_LoadB_Reg: + case NITIO_G0_LOADB: stc_register = G_Load_B_Register(0); break; - case NITIO_G1_LoadB_Reg: + case NITIO_G1_LOADB: stc_register = G_Load_B_Register(1); break; - case NITIO_G0_Input_Select_Reg: + case NITIO_G0_INPUT_SEL: stc_register = G_Input_Select_Register(0); break; - case NITIO_G1_Input_Select_Reg: + case NITIO_G1_INPUT_SEL: stc_register = G_Input_Select_Register(1); break; - case NITIO_G01_Status_Reg: + case NITIO_G01_STATUS: stc_register = G_Status_Register; break; - case NITIO_G01_Joint_Reset_Reg: + case NITIO_G01_RESET: stc_register = Joint_Reset_Register; break; - case NITIO_G01_Joint_Status1_Reg: + case NITIO_G01_STATUS1: stc_register = Joint_Status_1_Register; break; - case NITIO_G01_Joint_Status2_Reg: + case NITIO_G01_STATUS2: stc_register = Joint_Status_2_Register; break; - case NITIO_G0_Interrupt_Acknowledge_Reg: + case NITIO_G0_INT_ACK: stc_register = Interrupt_A_Ack_Register; break; - case NITIO_G1_Interrupt_Acknowledge_Reg: + case NITIO_G1_INT_ACK: stc_register = Interrupt_B_Ack_Register; break; - case NITIO_G0_Status_Reg: + case NITIO_G0_STATUS: stc_register = AI_Status_1_Register; break; - case NITIO_G1_Status_Reg: + case NITIO_G1_STATUS: stc_register = AO_Status_1_Register; break; - case NITIO_G0_Interrupt_Enable_Reg: + case NITIO_G0_INT_ENA: stc_register = Interrupt_A_Enable_Register; break; - case NITIO_G1_Interrupt_Enable_Reg: + case NITIO_G1_INT_ENA: stc_register = Interrupt_B_Enable_Register; break; default: @@ -4192,52 +3980,52 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, switch (reg) { /* m-series-only registers */ - case NITIO_G0_Counting_Mode_Reg: + case NITIO_G0_CNT_MODE: ni_writew(bits, M_Offset_G0_Counting_Mode); break; - case NITIO_G1_Counting_Mode_Reg: + case NITIO_G1_CNT_MODE: ni_writew(bits, M_Offset_G1_Counting_Mode); break; - case NITIO_G0_Second_Gate_Reg: + case NITIO_G0_GATE2: ni_writew(bits, M_Offset_G0_Second_Gate); break; - case NITIO_G1_Second_Gate_Reg: + case NITIO_G1_GATE2: ni_writew(bits, M_Offset_G1_Second_Gate); break; - case NITIO_G0_DMA_Config_Reg: + case NITIO_G0_DMA_CFG: ni_writew(bits, M_Offset_G0_DMA_Config); break; - case NITIO_G1_DMA_Config_Reg: + case NITIO_G1_DMA_CFG: ni_writew(bits, M_Offset_G1_DMA_Config); break; - case NITIO_G0_ABZ_Reg: + case NITIO_G0_ABZ: ni_writew(bits, M_Offset_G0_MSeries_ABZ); break; - case NITIO_G1_ABZ_Reg: + case NITIO_G1_ABZ: ni_writew(bits, M_Offset_G1_MSeries_ABZ); break; /* 32 bit registers */ - case NITIO_G0_LoadA_Reg: - case NITIO_G1_LoadA_Reg: - case NITIO_G0_LoadB_Reg: - case NITIO_G1_LoadB_Reg: + case NITIO_G0_LOADA: + case NITIO_G1_LOADA: + case NITIO_G0_LOADB: + case NITIO_G1_LOADB: stc_register = ni_gpct_to_stc_register(reg); devpriv->stc_writel(dev, bits, stc_register); break; /* 16 bit registers */ - case NITIO_G0_Interrupt_Enable_Reg: + case NITIO_G0_INT_ENA: BUG_ON(bits & ~gpct_interrupt_a_enable_mask); ni_set_bitfield(dev, Interrupt_A_Enable_Register, gpct_interrupt_a_enable_mask, bits); break; - case NITIO_G1_Interrupt_Enable_Reg: + case NITIO_G1_INT_ENA: BUG_ON(bits & ~gpct_interrupt_b_enable_mask); ni_set_bitfield(dev, Interrupt_B_Enable_Register, gpct_interrupt_b_enable_mask, bits); break; - case NITIO_G01_Joint_Reset_Reg: + case NITIO_G01_RESET: BUG_ON(bits & ~gpct_joint_reset_mask); /* fall-through */ default: @@ -4255,21 +4043,18 @@ static unsigned ni_gpct_read_register(struct ni_gpct *counter, switch (reg) { /* m-series only registers */ - case NITIO_G0_DMA_Status_Reg: + case NITIO_G0_DMA_STATUS: return ni_readw(M_Offset_G0_DMA_Status); - break; - case NITIO_G1_DMA_Status_Reg: + case NITIO_G1_DMA_STATUS: return ni_readw(M_Offset_G1_DMA_Status); - break; /* 32 bit registers */ - case NITIO_G0_HW_Save_Reg: - case NITIO_G1_HW_Save_Reg: - case NITIO_G0_SW_Save_Reg: - case NITIO_G1_SW_Save_Reg: + case NITIO_G0_HW_SAVE: + case NITIO_G1_HW_SAVE: + case NITIO_G0_SW_SAVE: + case NITIO_G1_SW_SAVE: stc_register = ni_gpct_to_stc_register(reg); return devpriv->stc_readl(dev, stc_register); - break; /* 16 bit registers */ default: @@ -4363,10 +4148,9 @@ static int ni_alloc_private(struct comedi_device *dev) { struct ni_private *devpriv; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; spin_lock_init(&devpriv->window_lock); spin_lock_init(&devpriv->soft_reg_copy_lock); @@ -4437,11 +4221,10 @@ static int ni_E_init(struct comedi_device *dev) s->maxdata = (1 << board->aobits) - 1; s->range_table = board->ao_range_table; s->insn_read = &ni_ao_insn_read; - if (board->reg_type & ni_reg_6xxx_mask) { + if (board->reg_type & ni_reg_6xxx_mask) s->insn_write = &ni_ao_insn_write_671x; - } else { + else s->insn_write = &ni_ao_insn_write; - } s->insn_config = &ni_ao_insn_config; #ifdef PCIDMA if (board->n_aochan) { @@ -4475,7 +4258,7 @@ static int ni_E_init(struct comedi_device *dev) s->n_chan = board->num_p0_dio_channels; if (board->reg_type & ni_reg_m_series_mask) { s->subdev_flags |= - SDF_LSAMPL | SDF_CMD_WRITE /* | SDF_CMD_READ */ ; + SDF_LSAMPL | SDF_CMD_WRITE /* | SDF_CMD_READ */; s->insn_bits = &ni_m_series_dio_insn_bits; s->insn_config = &ni_m_series_dio_insn_config; s->do_cmd = &ni_cdio_cmd; @@ -4496,7 +4279,10 @@ static int ni_E_init(struct comedi_device *dev) /* 8255 device */ s = &dev->subdevices[NI_8255_DIO_SUBDEV]; if (board->has_8255) { - subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev); + ret = subdev_8255_init(dev, s, ni_8255_callback, + (unsigned long)dev); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -4557,9 +4343,8 @@ static int ni_E_init(struct comedi_device *dev) s->n_chan = 10; } s->maxdata = 1; - if (board->reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) s->insn_bits = &ni_pfi_insn_bits; - } s->insn_config = &ni_pfi_insn_config; ni_set_bits(dev, IO_Bidirection_Pin_Register, ~0, 0); @@ -4599,16 +4384,18 @@ static int ni_E_init(struct comedi_device *dev) s->insn_config = ni_rtsi_insn_config; ni_rtsi_init(dev); - if (board->reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) counter_variant = ni_gpct_variant_m_series; - } else { + else counter_variant = ni_gpct_variant_e_series; - } devpriv->counter_dev = ni_gpct_device_construct(dev, &ni_gpct_write_register, &ni_gpct_read_register, counter_variant, NUM_GPCT); + if (!devpriv->counter_dev) + return -ENOMEM; + /* General purpose counters */ for (j = 0; j < NUM_GPCT; ++j) { s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; @@ -4619,14 +4406,14 @@ static int ni_E_init(struct comedi_device *dev) s->maxdata = 0xffffffff; else s->maxdata = 0xffffff; - s->insn_read = &ni_gpct_insn_read; - s->insn_write = &ni_gpct_insn_write; - s->insn_config = &ni_gpct_insn_config; + s->insn_read = ni_tio_insn_read; + s->insn_write = ni_tio_insn_read; + s->insn_config = ni_tio_insn_config; #ifdef PCIDMA s->subdev_flags |= SDF_CMD_READ /* | SDF_CMD_WRITE */; s->do_cmd = &ni_gpct_cmd; s->len_chanlist = 1; - s->do_cmdtest = &ni_gpct_cmdtest; + s->do_cmdtest = ni_tio_cmdtest; s->cancel = &ni_gpct_cancel; s->async_dma_dir = DMA_BIDIRECTIONAL; #endif @@ -4699,7 +4486,6 @@ static int ni_E_init(struct comedi_device *dev) ni_writeb(0x0, M_Offset_AO_Calibration); } - printk("\n"); return 0; } @@ -4947,7 +4733,7 @@ static int pack_ad8842(int addr, int val, int *bitstring); struct caldac_struct { int n_chans; int n_bits; - int (*packbits) (int, int, int *); + int (*packbits)(int, int, int *); }; static struct caldac_struct caldacs[] = { @@ -4990,9 +4776,8 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) if (diffbits) { unsigned int *maxdata_list; - if (n_chans > MAX_N_CALDACS) { + if (n_chans > MAX_N_CALDACS) printk("BUG! MAX_N_CALDACS too small\n"); - } s->maxdata_list = maxdata_list = devpriv->caldac_maxdata_list; chan = 0; for (i = 0; i < n_dacs; i++) { @@ -5189,36 +4974,11 @@ static void GPCT_Reset(struct comedi_device *dev, int chan) #endif -static int ni_gpct_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct ni_gpct *counter = s->private; - return ni_tio_insn_config(counter, insn, data); -} - -static int ni_gpct_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct ni_gpct *counter = s->private; - return ni_tio_rinsn(counter, insn, data); -} - -static int ni_gpct_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct ni_gpct *counter = s->private; - return ni_tio_winsn(counter, insn, data); -} - #ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - int retval; struct ni_gpct *counter = s->private; -/* const struct comedi_cmd *cmd = &s->async->cmd; */ + int retval; retval = ni_request_gpct_mite_channel(dev, counter->counter_index, COMEDI_INPUT); @@ -5229,25 +4989,14 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL); ni_e_series_enable_second_irq(dev, counter->counter_index, 1); - retval = ni_tio_cmd(counter, s->async); - return retval; -} -#endif -#ifdef PCIDMA -static int ni_gpct_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - struct ni_gpct *counter = s->private; - - return ni_tio_cmdtest(counter, cmd); - return -ENOTSUPP; + return ni_tio_cmd(dev, s); } #endif +#ifdef PCIDMA static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { -#ifdef PCIDMA struct ni_gpct *counter = s->private; int retval; @@ -5255,10 +5004,8 @@ static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) ni_e_series_enable_second_irq(dev, counter->counter_index, 0); ni_release_gpct_mite_channel(dev, counter->counter_index); return retval; -#else - return 0; -#endif } +#endif /* * @@ -5376,9 +5123,8 @@ static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel, struct ni_private *devpriv __maybe_unused = dev->private; unsigned bits; - if ((board->reg_type & ni_reg_m_series_mask) == 0) { + if ((board->reg_type & ni_reg_m_series_mask) == 0) return -ENOTSUPP; - } bits = ni_readl(M_Offset_PFI_Filter); bits &= ~MSeries_PFI_Filter_Select_Mask(pfi_channel); bits |= MSeries_PFI_Filter_Select_Bits(pfi_channel, filter); @@ -5388,20 +5134,20 @@ static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel, static int ni_pfi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv __maybe_unused = dev->private; - if ((board->reg_type & ni_reg_m_series_mask) == 0) { + if (!(board->reg_type & ni_reg_m_series_mask)) return -ENOTSUPP; - } - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + + if (comedi_dio_update_state(s, data)) ni_writew(s->state, M_Offset_PFI_DO); - } + data[1] = ni_readw(M_Offset_PFI_DI); + return insn->n; } @@ -5459,9 +5205,8 @@ static void ni_rtsi_init(struct comedi_device *dev) /* Set clock mode to internal */ devpriv->clock_and_fout2 = MSeries_RTSI_10MHz_Bit; - if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0) { + if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0) printk("ni_set_master_clock failed, bug?"); - } /* default internal lines routing to RTSI bus lines */ devpriv->rtsi_trig_a_output_reg = RTSI_Trig_Output_Bits(0, @@ -5644,9 +5389,8 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device *dev, devpriv->clock_source = source; /* it seems to typically take a few hundred microseconds for PLL to lock */ for (i = 0; i < timeout; ++i) { - if (ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit) { + if (ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit) break; - } udelay(1); } if (i == timeout) { @@ -5868,13 +5612,11 @@ static int cs5529_wait_for_idle(struct comedi_device *dev) for (i = 0; i < timeout; i++) { status = ni_ao_win_inw(dev, CAL_ADC_Status_67xx); - if ((status & CSS_ADC_BUSY) == 0) { + if ((status & CSS_ADC_BUSY) == 0) break; - } set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout(1)) { + if (schedule_timeout(1)) return -EIO; - } } /* printk("looped %i times waiting for idle\n", i); */ if (i == timeout) { @@ -5900,9 +5642,8 @@ static void cs5529_command(struct comedi_device *dev, unsigned short value) udelay(1); } /* printk("looped %i times writing command to cs5529\n", i); */ - if (i == timeout) { + if (i == timeout) comedi_error(dev, "possible problem - never saw adc go busy?"); - } } /* write to cs5529 register */ @@ -5919,25 +5660,6 @@ static void cs5529_config_write(struct comedi_device *dev, unsigned int value, comedi_error(dev, "time or signal in cs5529_config_write()"); } -#ifdef NI_CS5529_DEBUG -/* read from cs5529 register */ -static unsigned int cs5529_config_read(struct comedi_device *dev, - unsigned int reg_select_bits) -{ - unsigned int value; - - reg_select_bits &= CSCMD_REGISTER_SELECT_MASK; - cs5529_command(dev, CSCMD_COMMAND | CSCMD_READ | reg_select_bits); - if (cs5529_wait_for_idle(dev)) - comedi_error(dev, "timeout or signal in cs5529_config_read()"); - value = (ni_ao_win_inw(dev, - CAL_ADC_Config_Data_High_Word_67xx) << 16) & - 0xff0000; - value |= ni_ao_win_inw(dev, CAL_ADC_Config_Data_Low_Word_67xx) & 0xffff; - return value; -} -#endif - static int cs5529_do_conversion(struct comedi_device *dev, unsigned short *data) { int retval; @@ -6014,12 +5736,5 @@ static int init_cs5529(struct comedi_device *dev) if (cs5529_wait_for_idle(dev)) comedi_error(dev, "timeout or signal in init_cs5529()\n"); #endif -#ifdef NI_CS5529_DEBUG - printk("config: 0x%x\n", cs5529_config_read(dev, - CSCMD_CONFIG_REGISTER)); - printk("gain: 0x%x\n", cs5529_config_read(dev, CSCMD_GAIN_REGISTER)); - printk("offset: 0x%x\n", cs5529_config_read(dev, - CSCMD_OFFSET_REGISTER)); -#endif return 0; } diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index f813f576367..de421486b75 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -36,6 +36,7 @@ See the notes in the ni_atmio.o driver. */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> @@ -46,8 +47,6 @@ See the notes in the ni_atmio.o driver. #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> -#undef DEBUG - #define ATMIO 1 #undef PCIMIO diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 5b2f72e102e..5fc74d6ff6a 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -47,9 +47,8 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org */ #define USE_DMA -/* #define DEBUG 1 */ -/* #define DEBUG_FLAGS */ +#include <linux/module.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/sched.h> @@ -59,13 +58,6 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org #include "comedi_fc.h" #include "mite.h" -#undef DPRINTK -#ifdef DEBUG -#define DPRINTK(format, args...) pr_debug(format, ## args) -#else -#define DPRINTK(format, args...) do { } while (0) -#endif - #define PCI_DIO_SIZE 4096 #define PCI_MITE_SIZE 4096 @@ -271,9 +263,6 @@ enum FPGA_Control_Bits { #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -static int ni_pcidio_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - enum nidio_boardid { BOARD_PCIDIO_32HS, BOARD_PXI6533, @@ -318,14 +307,6 @@ static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode); static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s); -#ifdef DEBUG_FLAGS -static void ni_pcidio_print_flags(unsigned int flags); -static void ni_pcidio_print_status(unsigned int status); -#else -#define ni_pcidio_print_flags(x) -#define ni_pcidio_print_status(x) -#endif - static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev) { struct nidio96_private *devpriv = dev->private; @@ -369,17 +350,6 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } -static void ni_pcidio_event(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_pcidio_cancel(dev, s); - } - comedi_event(dev, s); -} - static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct nidio96_private *devpriv = dev->private; @@ -389,7 +359,7 @@ static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s) spin_lock_irqsave(&dev->spinlock, irq_flags); spin_lock(&devpriv->mite_channel_lock); if (devpriv->di_mite_chan) - mite_sync_input_dma(devpriv->di_mite_chan, s->async); + mite_sync_input_dma(devpriv->di_mite_chan, s); spin_unlock(&devpriv->mite_channel_lock); count = s->async->buf_write_count - s->async->buf_read_count; spin_unlock_irqrestore(&dev->spinlock, irq_flags); @@ -400,14 +370,14 @@ static irqreturn_t nidio_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct nidio96_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; /* int i, j; */ - long int AuxData = 0; - short data1 = 0; - short data2 = 0; + unsigned int auxdata = 0; + unsigned short data1 = 0; + unsigned short data2 = 0; int flags; int status; int work = 0; @@ -426,30 +396,22 @@ static irqreturn_t nidio_interrupt(int irq, void *d) Interrupt_And_Window_Status); flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x\n", - status, flags); - ni_pcidio_print_flags(flags); - ni_pcidio_print_status(status); - spin_lock(&devpriv->mite_channel_lock); if (devpriv->di_mite_chan) m_status = mite_get_status(devpriv->di_mite_chan); -#ifdef MITE_DEBUG - mite_print_chsr(m_status); -#endif - /* mite_dump_regs(mite); */ if (m_status & CHSR_INT) { if (m_status & CHSR_LINKC) { writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(devpriv->di_mite_chan->channel)); - mite_sync_input_dma(devpriv->di_mite_chan, s->async); + mite_sync_input_dma(devpriv->di_mite_chan, s); /* XXX need to byteswap */ } if (m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_DRDY | CHSR_DRQ1 | CHSR_MRDY)) { - DPRINTK("unknown mite interrupt, disabling IRQ\n"); + dev_dbg(dev->class_dev, + "unknown mite interrupt, disabling IRQ\n"); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; disable_irq(dev->irq); } @@ -459,7 +421,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) while (status & DataLeft) { work++; if (work > 20) { - DPRINTK("too much work in interrupt\n"); + dev_dbg(dev->class_dev, "too much work in interrupt\n"); writeb(0x00, devpriv->mite->daq_io_addr + Master_DMA_And_Interrupt_Control); @@ -469,39 +431,31 @@ static irqreturn_t nidio_interrupt(int irq, void *d) flags &= IntEn; if (flags & TransferReady) { - /* DPRINTK("TransferReady\n"); */ while (flags & TransferReady) { work++; if (work > 100) { - DPRINTK("too much work in interrupt\n"); + dev_dbg(dev->class_dev, + "too much work in interrupt\n"); writeb(0x00, devpriv->mite->daq_io_addr + Master_DMA_And_Interrupt_Control ); goto out; } - AuxData = + auxdata = readl(devpriv->mite->daq_io_addr + Group_1_FIFO); - data1 = AuxData & 0xffff; - data2 = (AuxData & 0xffff0000) >> 16; - comedi_buf_put(async, data1); - comedi_buf_put(async, data2); - /* DPRINTK("read:%d, %d\n",data1,data2); */ + data1 = auxdata & 0xffff; + data2 = (auxdata & 0xffff0000) >> 16; + comedi_buf_put(s, data1); + comedi_buf_put(s, data2); flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); } - /* DPRINTK("buf_int_count: %d\n", - async->buf_int_count); */ - /* DPRINTK("1) IntEn=%d,flags=%d,status=%d\n", - IntEn,flags,status); */ - /* ni_pcidio_print_flags(flags); */ - /* ni_pcidio_print_status(status); */ async->events |= COMEDI_CB_BLOCK; } if (flags & CountExpired) { - DPRINTK("CountExpired\n"); writeb(ClearExpired, devpriv->mite->daq_io_addr + Group_1_Second_Clear); @@ -510,45 +464,30 @@ static irqreturn_t nidio_interrupt(int irq, void *d) writeb(0x00, devpriv->mite->daq_io_addr + OpMode); break; } else if (flags & Waited) { - DPRINTK("Waited\n"); writeb(ClearWaited, devpriv->mite->daq_io_addr + Group_1_First_Clear); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; break; } else if (flags & PrimaryTC) { - DPRINTK("PrimaryTC\n"); writeb(ClearPrimaryTC, devpriv->mite->daq_io_addr + Group_1_First_Clear); async->events |= COMEDI_CB_EOA; } else if (flags & SecondaryTC) { - DPRINTK("SecondaryTC\n"); writeb(ClearSecondaryTC, devpriv->mite->daq_io_addr + Group_1_First_Clear); async->events |= COMEDI_CB_EOA; } -#if 0 - else { - DPRINTK("ni_pcidio: unknown interrupt\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - writeb(0x00, - devpriv->mite->daq_io_addr + - Master_DMA_And_Interrupt_Control); - } -#endif + flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); status = readb(devpriv->mite->daq_io_addr + Interrupt_And_Window_Status); - /* DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x," - "status=0x%02x\n", IntEn, flags, status); */ - /* ni_pcidio_print_flags(flags); */ - /* ni_pcidio_print_status(status); */ } out: - ni_pcidio_event(dev, s); + cfc_handle_events(dev, s); #if 0 if (!tag) { writeb(0x03, @@ -561,123 +500,33 @@ out: return IRQ_HANDLED; } -#ifdef DEBUG_FLAGS -static const char *bit_set_string(unsigned int bits, unsigned int bit, - const char *const strings[]) -{ - return (bits & (1U << bit)) ? strings[bit] : ""; -} - -static const char *const flags_strings[] = { - " TransferReady", " CountExpired", " 2", " 3", - " 4", " Waited", " PrimaryTC", " SecondaryTC", -}; - - -static void ni_pcidio_print_flags(unsigned int flags) -{ - pr_debug("group_1_flags:%s%s%s%s%s%s%s%s\n", - bit_set_string(flags, 7, flags_strings), - bit_set_string(flags, 6, flags_strings), - bit_set_string(flags, 5, flags_strings), - bit_set_string(flags, 4, flags_strings), - bit_set_string(flags, 3, flags_strings), - bit_set_string(flags, 2, flags_strings), - bit_set_string(flags, 1, flags_strings), - bit_set_string(flags, 0, flags_strings)); -} - -static const char *const status_strings[] = { - " DataLeft1", " Reserved1", " Req1", " StopTrig1", - " DataLeft2", " Reserved2", " Req2", " StopTrig2", -}; - -static void ni_pcidio_print_status(unsigned int flags) -{ - pr_debug("group_status:%s%s%s%s%s%s%s%s\n", - bit_set_string(flags, 7, status_strings), - bit_set_string(flags, 6, status_strings), - bit_set_string(flags, 5, status_strings), - bit_set_string(flags, 4, status_strings), - bit_set_string(flags, 3, status_strings), - bit_set_string(flags, 2, status_strings), - bit_set_string(flags, 1, status_strings), - bit_set_string(flags, 0, status_strings)); -} -#endif - -#ifdef unused -static void debug_int(struct comedi_device *dev) -{ - struct nidio96_private *devpriv = dev->private; - int a, b; - static int n_int; - struct timeval tv; - - do_gettimeofday(&tv); - a = readb(devpriv->mite->daq_io_addr + Group_Status); - b = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - - if (n_int < 10) { - DPRINTK("status 0x%02x flags 0x%02x time %06d\n", a, b, - (int)tv.tv_usec); - } - - while (b & 1) { - writew(0xff, devpriv->mite->daq_io_addr + Group_1_FIFO); - b = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - } - - b = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - - if (n_int < 10) { - DPRINTK("new status 0x%02x\n", b); - n_int++; - } -} -#endif - static int ni_pcidio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct nidio96_private *devpriv = dev->private; + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - if (insn->n != 1) - return -EINVAL; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << CR_CHAN(insn->chanspec); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } writel(s->io_bits, devpriv->mite->daq_io_addr + Port_Pin_Directions(0)); - return 1; + return insn->n; } static int ni_pcidio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct nidio96_private *devpriv = dev->private; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) writel(s->state, devpriv->mite->daq_io_addr + Port_IO(0)); - } + data[1] = readl(devpriv->mite->daq_io_addr + Port_IO(0)); return insn->n; @@ -687,7 +536,7 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -746,11 +595,9 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - ni_pcidio_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + ni_pcidio_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) @@ -896,7 +743,6 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->inttrig = ni_pcidio_inttrig; } - DPRINTK("ni_pcidio: command started\n"); return 0; } @@ -911,7 +757,7 @@ static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s) return retval; /* write alloc the entire buffer */ - comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_write_alloc(s, s->async->prealloc_bufsz); spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->di_mite_chan) { @@ -925,11 +771,13 @@ static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s) } static int ni_pcidio_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { struct nidio96_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; writeb(devpriv->OpModeBits, devpriv->mite->daq_io_addr + OpMode); @@ -956,7 +804,7 @@ static int ni_pcidio_change(struct comedi_device *dev, struct nidio96_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->di_mite_ring, s->async); + ret = mite_buf_change(devpriv->di_mite_ring, s); if (ret < 0) return ret; @@ -1087,6 +935,19 @@ static int pci_6534_upload_firmware(struct comedi_device *dev) return ret; } +static void nidio_reset_board(struct comedi_device *dev) +{ + struct nidio96_private *devpriv = dev->private; + void __iomem *daq_mmio = devpriv->mite->daq_io_addr; + + writel(0, daq_mmio + Port_IO(0)); + writel(0, daq_mmio + Port_Pin_Directions(0)); + writel(0, daq_mmio + Port_Pin_Mask(0)); + + /* disable interrupts on board */ + writeb(0, daq_mmio + Master_DMA_And_Interrupt_Control); +} + static int nidio_auto_attach(struct comedi_device *dev, unsigned long context) { @@ -1108,10 +969,9 @@ static int nidio_auto_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; spin_lock_init(&devpriv->mite_channel_lock); @@ -1129,13 +989,14 @@ static int nidio_auto_attach(struct comedi_device *dev, if (devpriv->di_mite_ring == NULL) return -ENOMEM; - irq = mite_irq(devpriv->mite); if (board->uses_firmware) { ret = pci_6534_upload_firmware(dev); if (ret < 0) return ret; } + nidio_reset_board(dev); + ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; @@ -1163,21 +1024,13 @@ static int nidio_auto_attach(struct comedi_device *dev, s->async_dma_dir = DMA_BIDIRECTIONAL; s->poll = &ni_pcidio_poll; - writel(0, devpriv->mite->daq_io_addr + Port_IO(0)); - writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0)); - writel(0, devpriv->mite->daq_io_addr + Port_Pin_Mask(0)); - - /* disable interrupts on board */ - writeb(0x00, - devpriv->mite->daq_io_addr + - Master_DMA_And_Interrupt_Control); - - ret = request_irq(irq, nidio_interrupt, IRQF_SHARED, - "ni_pcidio", dev); - if (ret < 0) - dev_warn(dev->class_dev, "irq not available\n"); - - dev->irq = irq; + irq = mite_irq(devpriv->mite); + if (irq) { + ret = request_irq(irq, nidio_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = irq; + } return 0; } @@ -1214,7 +1067,7 @@ static int ni_pcidio_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_pcidio_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = { +static const struct pci_device_id ni_pcidio_pci_table[] = { { PCI_VDEVICE(NI, 0x1150), BOARD_PCIDIO_32HS }, { PCI_VDEVICE(NI, 0x12b0), BOARD_PCI6534 }, { PCI_VDEVICE(NI, 0x1320), BOARD_PXI6533 }, diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 35681ba1f36..89300dc78e3 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -106,6 +106,7 @@ Bugs: */ +#include <linux/module.h> #include <linux/delay.h> #include "../comedidev.h" @@ -115,8 +116,6 @@ Bugs: #include "ni_stc.h" #include "mite.h" -/* #define PCI_DEBUG */ - #define PCIDMA #define PCIMIO 1 @@ -133,24 +132,26 @@ Bugs: 63 different possibilities. An AO channel can not act as it's own OFFSET or REFERENCE. */ -static const struct comedi_lrange range_ni_M_628x_ao = { 8, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-5, 15), - RANGE(0, 10), - RANGE(3, 7), - RANGE(4, 6), - RANGE_ext(-1, 1) - } +static const struct comedi_lrange range_ni_M_628x_ao = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + RANGE(-5, 15), + UNI_RANGE(10), + RANGE(3, 7), + RANGE(4, 6), + RANGE_ext(-1, 1) + } }; -static const struct comedi_lrange range_ni_M_625x_ao = { 3, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE_ext(-1, 1) - } +static const struct comedi_lrange range_ni_M_625x_ao = { + 3, { + BIP_RANGE(10), + BIP_RANGE(5), + RANGE_ext(-1, 1) + } }; enum ni_pcimio_boardid { @@ -1177,9 +1178,9 @@ static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, offset = M_Offset_AO_FIFO_Clear; break; case DIO_Control_Register: - printk - ("%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n", - __func__, reg); + dev_dbg(dev->class_dev, + "%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n", + __func__, reg); return; break; case G_Autoincrement_Register(0): @@ -1470,6 +1471,7 @@ static int pcimio_auto_attach(struct comedi_device *dev, struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct ni_board_struct *board = NULL; struct ni_private *devpriv; + unsigned int irq; int ret; if (context < ARRAY_SIZE(ni_boards)) @@ -1531,18 +1533,12 @@ static int pcimio_auto_attach(struct comedi_device *dev, if (board->reg_type == ni_reg_6143) init_6143(dev); - dev->irq = mite_irq(devpriv->mite); - - if (dev->irq == 0) { - pr_warn("unknown irq (bad)\n"); - } else { - pr_debug("( irq = %u )\n", dev->irq); - ret = request_irq(dev->irq, ni_E_interrupt, NI_E_IRQ_FLAGS, - DRV_NAME, dev); - if (ret < 0) { - pr_warn("irq not available\n"); - dev->irq = 0; - } + irq = mite_irq(devpriv->mite); + if (irq) { + ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, + dev->board_name, dev); + if (ret == 0) + dev->irq = irq; } ret = ni_E_init(dev); @@ -1555,7 +1551,7 @@ static int pcimio_auto_attach(struct comedi_device *dev, dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change; dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change; - return ret; + return 0; } static int pcimio_ai_change(struct comedi_device *dev, @@ -1564,7 +1560,7 @@ static int pcimio_ai_change(struct comedi_device *dev, struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->ai_mite_ring, s->async); + ret = mite_buf_change(devpriv->ai_mite_ring, s); if (ret < 0) return ret; @@ -1577,7 +1573,7 @@ static int pcimio_ao_change(struct comedi_device *dev, struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->ao_mite_ring, s->async); + ret = mite_buf_change(devpriv->ao_mite_ring, s); if (ret < 0) return ret; @@ -1591,7 +1587,7 @@ static int pcimio_gpct0_change(struct comedi_device *dev, struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->gpct_mite_ring[0], s->async); + ret = mite_buf_change(devpriv->gpct_mite_ring[0], s); if (ret < 0) return ret; @@ -1605,7 +1601,7 @@ static int pcimio_gpct1_change(struct comedi_device *dev, struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->gpct_mite_ring[1], s->async); + ret = mite_buf_change(devpriv->gpct_mite_ring[1], s); if (ret < 0) return ret; @@ -1618,7 +1614,7 @@ static int pcimio_dio_change(struct comedi_device *dev, struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->cdo_mite_ring, s->async); + ret = mite_buf_change(devpriv->cdo_mite_ring, s); if (ret < 0) return ret; @@ -1638,7 +1634,7 @@ static int ni_pcimio_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &ni_pcimio_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = { +static const struct pci_device_id ni_pcimio_pci_table[] = { { PCI_VDEVICE(NI, 0x0162), BOARD_PCIMIO_16XE_50 }, /* 0x1620? */ { PCI_VDEVICE(NI, 0x1170), BOARD_PCIMIO_16XE_10 }, { PCI_VDEVICE(NI, 0x1180), BOARD_PCIMIO_16E_1 }, diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index 11bf0aab82e..f0630b7897b 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -1491,7 +1491,7 @@ struct ni_board_struct { unsigned short pwm_up_count; \ unsigned short pwm_down_count; \ \ - short ai_fifo_buffer[0x2000]; \ + unsigned short ai_fifo_buffer[0x2000]; \ uint8_t eeprom_buffer[M_SERIES_EEPROM_SIZE]; \ uint32_t serial_number; \ \ diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c index f2cf76d15d7..92691b491c2 100644 --- a/drivers/staging/comedi/drivers/ni_tio.c +++ b/drivers/staging/comedi/drivers/ni_tio.c @@ -44,16 +44,15 @@ TODO: Support use of both banks X and Y */ +#include <linux/module.h> +#include <linux/slab.h> + #include "ni_tio_internal.h" static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, unsigned generic_clock_source); static unsigned ni_tio_generic_clock_src_select(const struct ni_gpct *counter); -MODULE_AUTHOR("Comedi <comedi@comedi.org>"); -MODULE_DESCRIPTION("Comedi support for NI general-purpose counters"); -MODULE_LICENSE("GPL"); - static inline enum Gi_Counting_Mode_Reg_Bits Gi_Alternate_Sync_Bit(enum ni_gpct_variant variant) @@ -274,19 +273,6 @@ static inline unsigned NI_660x_RTSI_Second_Gate_Select(unsigned n) static const unsigned int counter_status_mask = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; -static int __init ni_tio_init_module(void) -{ - return 0; -} - -module_init(ni_tio_init_module); - -static void __exit ni_tio_cleanup_module(void) -{ -} - -module_exit(ni_tio_cleanup_module); - struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device *dev, void (*write_register) (struct ni_gpct @@ -359,74 +345,64 @@ static int ni_tio_second_gate_registers_present(const struct ni_gpct_device static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter) { - write_register(counter, Gi_Reset_Bit(counter->counter_index), - NITIO_Gxx_Joint_Reset_Reg(counter->counter_index)); + unsigned cidx = counter->counter_index; + + write_register(counter, Gi_Reset_Bit(cidx), NITIO_RESET_REG(cidx)); } void ni_tio_init_counter(struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; ni_tio_reset_count_and_disarm(counter); + /* initialize counter registers */ - counter_dev->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)] = - 0x0; - write_register(counter, - counter_dev-> - regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)], - NITIO_Gi_Autoincrement_Reg(counter->counter_index)); - ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), + counter_dev->regs[NITIO_AUTO_INC_REG(cidx)] = 0x0; + write_register(counter, counter_dev->regs[NITIO_AUTO_INC_REG(cidx)], + NITIO_AUTO_INC_REG(cidx)); + + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), ~0, Gi_Synchronize_Gate_Bit); - ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), ~0, - 0); - counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = 0x0; - write_register(counter, - counter_dev-> - regs[NITIO_Gi_LoadA_Reg(counter->counter_index)], - NITIO_Gi_LoadA_Reg(counter->counter_index)); - counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = 0x0; - write_register(counter, - counter_dev-> - regs[NITIO_Gi_LoadB_Reg(counter->counter_index)], - NITIO_Gi_LoadB_Reg(counter->counter_index)); - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), ~0, - 0); - if (ni_tio_counting_mode_registers_present(counter_dev)) { - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg(counter-> - counter_index), ~0, - 0); - } + + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), ~0, 0); + + counter_dev->regs[NITIO_LOADA_REG(cidx)] = 0x0; + write_register(counter, counter_dev->regs[NITIO_LOADA_REG(cidx)], + NITIO_LOADA_REG(cidx)); + + counter_dev->regs[NITIO_LOADB_REG(cidx)] = 0x0; + write_register(counter, counter_dev->regs[NITIO_LOADB_REG(cidx)], + NITIO_LOADB_REG(cidx)); + + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), ~0, 0); + + if (ni_tio_counting_mode_registers_present(counter_dev)) + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), ~0, 0); + if (ni_tio_second_gate_registers_present(counter_dev)) { - counter_dev-> - regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)] = - 0x0; + counter_dev->regs[NITIO_GATE2_REG(cidx)] = 0x0; write_register(counter, - counter_dev-> - regs[NITIO_Gi_Second_Gate_Reg - (counter->counter_index)], - NITIO_Gi_Second_Gate_Reg(counter-> - counter_index)); + counter_dev->regs[NITIO_GATE2_REG(cidx)], + NITIO_GATE2_REG(cidx)); } - ni_tio_set_bits(counter, - NITIO_Gi_DMA_Config_Reg(counter->counter_index), ~0, - 0x0); - ni_tio_set_bits(counter, - NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index), - ~0, 0x0); + + ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), ~0, 0x0); + + ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), ~0, 0x0); } EXPORT_SYMBOL_GPL(ni_tio_init_counter); static unsigned int ni_tio_counter_status(struct ni_gpct *counter) { - unsigned int status = 0; + unsigned cidx = counter->counter_index; const unsigned bits = read_register(counter, - NITIO_Gxx_Status_Reg(counter-> - counter_index)); - if (bits & Gi_Armed_Bit(counter->counter_index)) { + NITIO_SHARED_STATUS_REG(cidx)); + unsigned int status = 0; + + if (bits & Gi_Armed_Bit(cidx)) { status |= COMEDI_COUNTER_ARMED; - if (bits & Gi_Counting_Bit(counter->counter_index)) + if (bits & Gi_Counting_Bit(cidx)) status |= COMEDI_COUNTER_COUNTING; } return status; @@ -435,8 +411,8 @@ static unsigned int ni_tio_counter_status(struct ni_gpct *counter) static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned counting_mode_reg = - NITIO_Gi_Counting_Mode_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned counting_mode_reg = NITIO_CNT_MODE_REG(cidx); static const uint64_t min_normal_sync_period_ps = 25000; const uint64_t clock_period_ps = ni_tio_clock_period_ps(counter, ni_tio_generic_clock_src_select @@ -473,6 +449,7 @@ static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; unsigned mode_reg_mask; unsigned mode_reg_values; unsigned input_select_bits = 0; @@ -499,7 +476,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) default: break; } - ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), mode_reg_mask, mode_reg_values); if (ni_tio_counting_mode_registers_present(counter_dev)) { @@ -512,15 +489,13 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask; if (mode & NI_GPCT_INDEX_ENABLE_BIT) counting_mode_bits |= Gi_Index_Mode_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), Gi_Counting_Mode_Mask | Gi_Index_Phase_Mask | Gi_Index_Mode_Bit, counting_mode_bits); ni_tio_set_sync_mode(counter, 0); } - ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Up_Down_Mask, (mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) << Gi_Up_Down_Shift); @@ -529,8 +504,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) input_select_bits |= Gi_Or_Gate_Bit; if (mode & NI_GPCT_INVERT_OUTPUT_BIT) input_select_bits |= Gi_Output_Polarity_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Gate_Select_Load_Source_Bit | Gi_Or_Gate_Bit | Gi_Output_Polarity_Bit, input_select_bits); @@ -540,7 +514,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) { struct ni_gpct_device *counter_dev = counter->counter_dev; - + unsigned cidx = counter->counter_index; unsigned command_transient_bits = 0; if (arm) { @@ -578,9 +552,7 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) } break; } - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg - (counter->counter_index), + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), Gi_HW_Arm_Select_Mask (counter_dev->variant) | Gi_HW_Arm_Enable_Bit, @@ -589,8 +561,7 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) } else { command_transient_bits |= Gi_Disarm_Bit; } - ni_tio_set_bits_transient(counter, - NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx), 0, 0, command_transient_bits); return 0; } @@ -714,8 +685,8 @@ static void ni_tio_set_source_subselect(struct ni_gpct *counter, unsigned int clock_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); if (counter_dev->variant != ni_gpct_variant_m_series) return; @@ -744,6 +715,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, unsigned int period_ns) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; unsigned input_select_bits = 0; static const uint64_t pico_per_nano = 1000; @@ -763,8 +735,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, } if (clock_source & NI_GPCT_INVERT_CLOCK_SRC_BIT) input_select_bits |= Gi_Source_Polarity_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Source_Select_Mask | Gi_Source_Polarity_Bit, input_select_bits); ni_tio_set_source_subselect(counter, clock_source); @@ -788,9 +759,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, return -EINVAL; break; } - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), Gi_Prescale_X2_Bit(counter_dev->variant) | Gi_Prescale_X8_Bit(counter_dev->variant), counting_mode_bits); @@ -803,15 +772,12 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned counting_mode_bits = ni_tio_get_soft_copy(counter, - NITIO_Gi_Counting_Mode_Reg - (counter-> - counter_index)); + unsigned cidx = counter->counter_index; + const unsigned counting_mode_bits = + ni_tio_get_soft_copy(counter, NITIO_CNT_MODE_REG(cidx)); unsigned bits = 0; - if (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) & + if (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) & Gi_Source_Polarity_Bit) bits |= NI_GPCT_INVERT_CLOCK_SRC_BIT; if (counting_mode_bits & Gi_Prescale_X2_Bit(counter_dev->variant)) @@ -824,15 +790,13 @@ static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct *counter) static unsigned ni_m_series_clock_src_select(const struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); unsigned clock_source = 0; unsigned i; - const unsigned input_select = (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) - & Gi_Source_Select_Mask) >> - Gi_Source_Select_Shift; + const unsigned input_select = + (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) & + Gi_Source_Select_Mask) >> Gi_Source_Select_Shift; switch (input_select) { case NI_M_Series_Timebase_1_Clock: @@ -892,12 +856,11 @@ static unsigned ni_m_series_clock_src_select(const struct ni_gpct *counter) static unsigned ni_660x_clock_src_select(const struct ni_gpct *counter) { unsigned clock_source = 0; + unsigned cidx = counter->counter_index; + const unsigned input_select = + (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) & + Gi_Source_Select_Mask) >> Gi_Source_Select_Shift; unsigned i; - const unsigned input_select = (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) - & Gi_Source_Select_Mask) >> - Gi_Source_Select_Shift; switch (input_select) { case NI_660x_Timebase_1_Clock: @@ -1019,6 +982,7 @@ static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter, unsigned int gate_source) { const unsigned mode_mask = Gi_Gate_Polarity_Bit | Gi_Gating_Mode_Mask; + unsigned cidx = counter->counter_index; unsigned mode_values = 0; if (gate_source & CR_INVERT) @@ -1027,7 +991,7 @@ static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter, mode_values |= Gi_Rising_Edge_Gating_Bits; else mode_values |= Gi_Level_Gating_Bits; - ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), mode_mask, mode_values); } @@ -1035,6 +999,7 @@ static int ni_660x_set_first_gate(struct ni_gpct *counter, unsigned int gate_source) { const unsigned selected_gate = CR_CHAN(gate_source); + unsigned cidx = counter->counter_index; /* bits of selected_gate that may be meaningful to input select register */ const unsigned selected_gate_mask = 0x1f; unsigned ni_660x_gate_select; @@ -1072,8 +1037,7 @@ static int ni_660x_set_first_gate(struct ni_gpct *counter, return -EINVAL; break; } - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Gate_Select_Mask, Gi_Gate_Select_Bits(ni_660x_gate_select)); return 0; @@ -1083,6 +1047,7 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter, unsigned int gate_source) { const unsigned selected_gate = CR_CHAN(gate_source); + unsigned cidx = counter->counter_index; /* bits of selected_gate that may be meaningful to input select register */ const unsigned selected_gate_mask = 0x1f; unsigned ni_m_series_gate_select; @@ -1121,8 +1086,7 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter, return -EINVAL; break; } - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Gate_Select_Mask, Gi_Gate_Select_Bits(ni_m_series_gate_select)); return 0; @@ -1132,8 +1096,8 @@ static int ni_660x_set_second_gate(struct ni_gpct *counter, unsigned int gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); const unsigned selected_second_gate = CR_CHAN(gate_source); /* bits of second_gate that may be meaningful to second gate register */ static const unsigned selected_second_gate_mask = 0x1f; @@ -1191,8 +1155,8 @@ static int ni_m_series_set_second_gate(struct ni_gpct *counter, unsigned int gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); const unsigned selected_second_gate = CR_CHAN(gate_source); /* bits of second_gate that may be meaningful to second gate register */ static const unsigned selected_second_gate_mask = 0x1f; @@ -1219,15 +1183,13 @@ int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, unsigned int gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); switch (gate_index) { case 0: if (CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) { - ni_tio_set_bits(counter, - NITIO_Gi_Mode_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), Gi_Gating_Mode_Mask, Gi_Gating_Disabled_Bits); return 0; @@ -1289,11 +1251,12 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index, unsigned int source) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; if (counter_dev->variant == ni_gpct_variant_m_series) { unsigned int abz_reg, shift, mask; - abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index); + abz_reg = NITIO_ABZ_REG(cidx); switch (index) { case NI_GPCT_SOURCE_ENCODER_A: shift = 10; @@ -1316,7 +1279,6 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index, counter_dev->regs[abz_reg] &= ~mask; counter_dev->regs[abz_reg] |= (source << shift) & mask; write_register(counter, counter_dev->regs[abz_reg], abz_reg); -/* printk("%s %x %d %d\n", __func__, counter_dev->regs[abz_reg], index, source); */ return 0; } return -EINVAL; @@ -1488,12 +1450,10 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, unsigned int *gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned mode_bits = ni_tio_get_soft_copy(counter, - NITIO_Gi_Mode_Reg - (counter-> - counter_index)); - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned mode_bits = + ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)); + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); unsigned gate_select_bits; switch (gate_index) { @@ -1505,8 +1465,7 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, } else { gate_select_bits = (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) & + NITIO_INPUT_SEL_REG(cidx)) & Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift; } switch (counter_dev->variant) { @@ -1574,9 +1533,13 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, return 0; } -int ni_tio_insn_config(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data) +int ni_tio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct ni_gpct *counter = s->private; + switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: return ni_tio_set_counter_mode(counter, data[1]); @@ -1620,11 +1583,15 @@ int ni_tio_insn_config(struct ni_gpct *counter, } EXPORT_SYMBOL_GPL(ni_tio_insn_config); -int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn, - unsigned int *data) +int ni_tio_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct ni_gpct *counter = s->private; struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned channel = CR_CHAN(insn->chanspec); + unsigned cidx = counter->counter_index; unsigned first_read; unsigned second_read; unsigned correct_read; @@ -1633,65 +1600,57 @@ int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn, return 0; switch (channel) { case 0: - ni_tio_set_bits(counter, - NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Save_Trace_Bit, 0); - ni_tio_set_bits(counter, - NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Save_Trace_Bit, Gi_Save_Trace_Bit); /* The count doesn't get latched until the next clock edge, so it is possible the count may change (once) while we are reading. Since the read of the SW_Save_Reg isn't atomic (apparently even when it's a 32 bit register according to 660x docs), we need to read twice and make sure the reading hasn't changed. If it has, a third read will be correct since the count value will definitely have latched by then. */ - first_read = - read_register(counter, - NITIO_Gi_SW_Save_Reg(counter->counter_index)); - second_read = - read_register(counter, - NITIO_Gi_SW_Save_Reg(counter->counter_index)); + first_read = read_register(counter, NITIO_SW_SAVE_REG(cidx)); + second_read = read_register(counter, NITIO_SW_SAVE_REG(cidx)); if (first_read != second_read) correct_read = - read_register(counter, - NITIO_Gi_SW_Save_Reg(counter-> - counter_index)); + read_register(counter, NITIO_SW_SAVE_REG(cidx)); else correct_read = first_read; data[0] = correct_read; return 0; break; case 1: - data[0] = - counter_dev-> - regs[NITIO_Gi_LoadA_Reg(counter->counter_index)]; + data[0] = counter_dev->regs[NITIO_LOADA_REG(cidx)]; break; case 2: - data[0] = - counter_dev-> - regs[NITIO_Gi_LoadB_Reg(counter->counter_index)]; + data[0] = counter_dev->regs[NITIO_LOADB_REG(cidx)]; break; } return 0; } -EXPORT_SYMBOL_GPL(ni_tio_rinsn); +EXPORT_SYMBOL_GPL(ni_tio_insn_read); static unsigned ni_tio_next_load_register(struct ni_gpct *counter) { - const unsigned bits = read_register(counter, - NITIO_Gxx_Status_Reg(counter-> - counter_index)); + unsigned cidx = counter->counter_index; + const unsigned bits = + read_register(counter, NITIO_SHARED_STATUS_REG(cidx)); - if (bits & Gi_Next_Load_Source_Bit(counter->counter_index)) - return NITIO_Gi_LoadB_Reg(counter->counter_index); + if (bits & Gi_Next_Load_Source_Bit(cidx)) + return NITIO_LOADB_REG(cidx); else - return NITIO_Gi_LoadA_Reg(counter->counter_index); + return NITIO_LOADA_REG(cidx); } -int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn, - unsigned int *data) +int ni_tio_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct ni_gpct *counter = s->private; struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned channel = CR_CHAN(insn->chanspec); + unsigned cidx = counter->counter_index; unsigned load_reg; if (insn->n < 1) @@ -1702,24 +1661,18 @@ int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn, /* Don't disturb load source select, just use whichever load register is already selected. */ load_reg = ni_tio_next_load_register(counter); write_register(counter, data[0], load_reg); - ni_tio_set_bits_transient(counter, - NITIO_Gi_Command_Reg(counter-> - counter_index), + ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx), 0, 0, Gi_Load_Bit); /* restore state of load reg to whatever the user set last set it to */ write_register(counter, counter_dev->regs[load_reg], load_reg); break; case 1: - counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = - data[0]; - write_register(counter, data[0], - NITIO_Gi_LoadA_Reg(counter->counter_index)); + counter_dev->regs[NITIO_LOADA_REG(cidx)] = data[0]; + write_register(counter, data[0], NITIO_LOADA_REG(cidx)); break; case 2: - counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = - data[0]; - write_register(counter, data[0], - NITIO_Gi_LoadB_Reg(counter->counter_index)); + counter_dev->regs[NITIO_LOADB_REG(cidx)] = data[0]; + write_register(counter, data[0], NITIO_LOADB_REG(cidx)); break; default: return -EINVAL; @@ -1727,4 +1680,19 @@ int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn, } return 0; } -EXPORT_SYMBOL_GPL(ni_tio_winsn); +EXPORT_SYMBOL_GPL(ni_tio_insn_write); + +static int __init ni_tio_init_module(void) +{ + return 0; +} +module_init(ni_tio_init_module); + +static void __exit ni_tio_cleanup_module(void) +{ +} +module_exit(ni_tio_cleanup_module); + +MODULE_AUTHOR("Comedi <comedi@comedi.org>"); +MODULE_DESCRIPTION("Comedi support for NI general-purpose counters"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h index 7e13697b325..1056bf001e5 100644 --- a/drivers/staging/comedi/drivers/ni_tio.h +++ b/drivers/staging/comedi/drivers/ni_tio.h @@ -25,77 +25,77 @@ struct mite_struct; struct ni_gpct_device; enum ni_gpct_register { - NITIO_G0_Autoincrement_Reg, - NITIO_G1_Autoincrement_Reg, - NITIO_G2_Autoincrement_Reg, - NITIO_G3_Autoincrement_Reg, - NITIO_G0_Command_Reg, - NITIO_G1_Command_Reg, - NITIO_G2_Command_Reg, - NITIO_G3_Command_Reg, - NITIO_G0_HW_Save_Reg, - NITIO_G1_HW_Save_Reg, - NITIO_G2_HW_Save_Reg, - NITIO_G3_HW_Save_Reg, - NITIO_G0_SW_Save_Reg, - NITIO_G1_SW_Save_Reg, - NITIO_G2_SW_Save_Reg, - NITIO_G3_SW_Save_Reg, - NITIO_G0_Mode_Reg, - NITIO_G1_Mode_Reg, - NITIO_G2_Mode_Reg, - NITIO_G3_Mode_Reg, - NITIO_G0_LoadA_Reg, - NITIO_G1_LoadA_Reg, - NITIO_G2_LoadA_Reg, - NITIO_G3_LoadA_Reg, - NITIO_G0_LoadB_Reg, - NITIO_G1_LoadB_Reg, - NITIO_G2_LoadB_Reg, - NITIO_G3_LoadB_Reg, - NITIO_G0_Input_Select_Reg, - NITIO_G1_Input_Select_Reg, - NITIO_G2_Input_Select_Reg, - NITIO_G3_Input_Select_Reg, - NITIO_G0_Counting_Mode_Reg, - NITIO_G1_Counting_Mode_Reg, - NITIO_G2_Counting_Mode_Reg, - NITIO_G3_Counting_Mode_Reg, - NITIO_G0_Second_Gate_Reg, - NITIO_G1_Second_Gate_Reg, - NITIO_G2_Second_Gate_Reg, - NITIO_G3_Second_Gate_Reg, - NITIO_G01_Status_Reg, - NITIO_G23_Status_Reg, - NITIO_G01_Joint_Reset_Reg, - NITIO_G23_Joint_Reset_Reg, - NITIO_G01_Joint_Status1_Reg, - NITIO_G23_Joint_Status1_Reg, - NITIO_G01_Joint_Status2_Reg, - NITIO_G23_Joint_Status2_Reg, - NITIO_G0_DMA_Config_Reg, - NITIO_G1_DMA_Config_Reg, - NITIO_G2_DMA_Config_Reg, - NITIO_G3_DMA_Config_Reg, - NITIO_G0_DMA_Status_Reg, - NITIO_G1_DMA_Status_Reg, - NITIO_G2_DMA_Status_Reg, - NITIO_G3_DMA_Status_Reg, - NITIO_G0_ABZ_Reg, - NITIO_G1_ABZ_Reg, - NITIO_G0_Interrupt_Acknowledge_Reg, - NITIO_G1_Interrupt_Acknowledge_Reg, - NITIO_G2_Interrupt_Acknowledge_Reg, - NITIO_G3_Interrupt_Acknowledge_Reg, - NITIO_G0_Status_Reg, - NITIO_G1_Status_Reg, - NITIO_G2_Status_Reg, - NITIO_G3_Status_Reg, - NITIO_G0_Interrupt_Enable_Reg, - NITIO_G1_Interrupt_Enable_Reg, - NITIO_G2_Interrupt_Enable_Reg, - NITIO_G3_Interrupt_Enable_Reg, - NITIO_Num_Registers, + NITIO_G0_AUTO_INC, + NITIO_G1_AUTO_INC, + NITIO_G2_AUTO_INC, + NITIO_G3_AUTO_INC, + NITIO_G0_CMD, + NITIO_G1_CMD, + NITIO_G2_CMD, + NITIO_G3_CMD, + NITIO_G0_HW_SAVE, + NITIO_G1_HW_SAVE, + NITIO_G2_HW_SAVE, + NITIO_G3_HW_SAVE, + NITIO_G0_SW_SAVE, + NITIO_G1_SW_SAVE, + NITIO_G2_SW_SAVE, + NITIO_G3_SW_SAVE, + NITIO_G0_MODE, + NITIO_G1_MODE, + NITIO_G2_MODE, + NITIO_G3_MODE, + NITIO_G0_LOADA, + NITIO_G1_LOADA, + NITIO_G2_LOADA, + NITIO_G3_LOADA, + NITIO_G0_LOADB, + NITIO_G1_LOADB, + NITIO_G2_LOADB, + NITIO_G3_LOADB, + NITIO_G0_INPUT_SEL, + NITIO_G1_INPUT_SEL, + NITIO_G2_INPUT_SEL, + NITIO_G3_INPUT_SEL, + NITIO_G0_CNT_MODE, + NITIO_G1_CNT_MODE, + NITIO_G2_CNT_MODE, + NITIO_G3_CNT_MODE, + NITIO_G0_GATE2, + NITIO_G1_GATE2, + NITIO_G2_GATE2, + NITIO_G3_GATE2, + NITIO_G01_STATUS, + NITIO_G23_STATUS, + NITIO_G01_RESET, + NITIO_G23_RESET, + NITIO_G01_STATUS1, + NITIO_G23_STATUS1, + NITIO_G01_STATUS2, + NITIO_G23_STATUS2, + NITIO_G0_DMA_CFG, + NITIO_G1_DMA_CFG, + NITIO_G2_DMA_CFG, + NITIO_G3_DMA_CFG, + NITIO_G0_DMA_STATUS, + NITIO_G1_DMA_STATUS, + NITIO_G2_DMA_STATUS, + NITIO_G3_DMA_STATUS, + NITIO_G0_ABZ, + NITIO_G1_ABZ, + NITIO_G0_INT_ACK, + NITIO_G1_INT_ACK, + NITIO_G2_INT_ACK, + NITIO_G3_INT_ACK, + NITIO_G0_STATUS, + NITIO_G1_STATUS, + NITIO_G2_STATUS, + NITIO_G3_STATUS, + NITIO_G0_INT_ENA, + NITIO_G1_INT_ENA, + NITIO_G2_INT_ENA, + NITIO_G3_INT_ENA, + NITIO_NUM_REGS, }; enum ni_gpct_variant { @@ -115,55 +115,42 @@ struct ni_gpct { struct ni_gpct_device { struct comedi_device *dev; - void (*write_register) (struct ni_gpct *counter, unsigned bits, - enum ni_gpct_register reg); - unsigned (*read_register) (struct ni_gpct *counter, - enum ni_gpct_register reg); + void (*write_register)(struct ni_gpct *counter, unsigned bits, + enum ni_gpct_register reg); + unsigned (*read_register)(struct ni_gpct *counter, + enum ni_gpct_register reg); enum ni_gpct_variant variant; struct ni_gpct *counters; unsigned num_counters; - unsigned regs[NITIO_Num_Registers]; + unsigned regs[NITIO_NUM_REGS]; spinlock_t regs_lock; }; -extern struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device - *dev, - void (*write_register) - (struct ni_gpct * - counter, unsigned bits, - enum ni_gpct_register - reg), - unsigned (*read_register) - (struct ni_gpct * - counter, - enum ni_gpct_register - reg), - enum ni_gpct_variant - variant, - unsigned num_counters); -extern void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev); -extern void ni_tio_init_counter(struct ni_gpct *counter); -extern int ni_tio_rinsn(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data); -extern int ni_tio_insn_config(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data); -extern int ni_tio_winsn(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data); -extern int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async); -extern int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd); -extern int ni_tio_cancel(struct ni_gpct *counter); -extern void ni_tio_handle_interrupt(struct ni_gpct *counter, - struct comedi_subdevice *s); -extern void ni_tio_set_mite_channel(struct ni_gpct *counter, - struct mite_channel *mite_chan); -extern void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, - int *gate_error, int *tc_error, - int *perm_stale_data, - int *stale_data); - -static inline struct ni_gpct *subdev_to_counter(struct comedi_subdevice *s) -{ - return s->private; -} +struct ni_gpct_device * +ni_gpct_device_construct(struct comedi_device *, + void (*write_register)(struct ni_gpct *, + unsigned bits, + enum ni_gpct_register), + unsigned (*read_register)(struct ni_gpct *, + enum ni_gpct_register), + enum ni_gpct_variant, + unsigned num_counters); +void ni_gpct_device_destroy(struct ni_gpct_device *); +void ni_tio_init_counter(struct ni_gpct *); +int ni_tio_insn_read(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data); +int ni_tio_insn_config(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data); +int ni_tio_insn_write(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data); +int ni_tio_cmd(struct comedi_device *, struct comedi_subdevice *); +int ni_tio_cmdtest(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); +int ni_tio_cancel(struct ni_gpct *); +void ni_tio_handle_interrupt(struct ni_gpct *, struct comedi_subdevice *); +void ni_tio_set_mite_channel(struct ni_gpct *, struct mite_channel *); +void ni_tio_acknowledge_and_confirm(struct ni_gpct *, + int *gate_error, int *tc_error, + int *perm_stale_data, int *stale_data); #endif /* _COMEDI_NI_TIO_H */ diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h index b009876754a..15b81b8fc5c 100644 --- a/drivers/staging/comedi/drivers/ni_tio_internal.h +++ b/drivers/staging/comedi/drivers/ni_tio_internal.h @@ -21,409 +21,26 @@ #include "ni_tio.h" -static inline enum ni_gpct_register NITIO_Gi_Autoincrement_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Autoincrement_Reg; - break; - case 1: - return NITIO_G1_Autoincrement_Reg; - break; - case 2: - return NITIO_G2_Autoincrement_Reg; - break; - case 3: - return NITIO_G3_Autoincrement_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Command_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Command_Reg; - break; - case 1: - return NITIO_G1_Command_Reg; - break; - case 2: - return NITIO_G2_Command_Reg; - break; - case 3: - return NITIO_G3_Command_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Counting_Mode_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Counting_Mode_Reg; - break; - case 1: - return NITIO_G1_Counting_Mode_Reg; - break; - case 2: - return NITIO_G2_Counting_Mode_Reg; - break; - case 3: - return NITIO_G3_Counting_Mode_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Input_Select_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Input_Select_Reg; - break; - case 1: - return NITIO_G1_Input_Select_Reg; - break; - case 2: - return NITIO_G2_Input_Select_Reg; - break; - case 3: - return NITIO_G3_Input_Select_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Joint_Reset_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Joint_Reset_Reg; - break; - case 2: - case 3: - return NITIO_G23_Joint_Reset_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Joint_Status1_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Joint_Status1_Reg; - break; - case 2: - case 3: - return NITIO_G23_Joint_Status1_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Joint_Status2_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Joint_Status2_Reg; - break; - case 2: - case 3: - return NITIO_G23_Joint_Status2_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Status_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Status_Reg; - break; - case 2: - case 3: - return NITIO_G23_Status_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_LoadA_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_LoadA_Reg; - break; - case 1: - return NITIO_G1_LoadA_Reg; - break; - case 2: - return NITIO_G2_LoadA_Reg; - break; - case 3: - return NITIO_G3_LoadA_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_LoadB_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_LoadB_Reg; - break; - case 1: - return NITIO_G1_LoadB_Reg; - break; - case 2: - return NITIO_G2_LoadB_Reg; - break; - case 3: - return NITIO_G3_LoadB_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Mode_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Mode_Reg; - break; - case 1: - return NITIO_G1_Mode_Reg; - break; - case 2: - return NITIO_G2_Mode_Reg; - break; - case 3: - return NITIO_G3_Mode_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_SW_Save_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_SW_Save_Reg; - break; - case 1: - return NITIO_G1_SW_Save_Reg; - break; - case 2: - return NITIO_G2_SW_Save_Reg; - break; - case 3: - return NITIO_G3_SW_Save_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Second_Gate_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Second_Gate_Reg; - break; - case 1: - return NITIO_G1_Second_Gate_Reg; - break; - case 2: - return NITIO_G2_Second_Gate_Reg; - break; - case 3: - return NITIO_G3_Second_Gate_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_DMA_Config_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_DMA_Config_Reg; - break; - case 1: - return NITIO_G1_DMA_Config_Reg; - break; - case 2: - return NITIO_G2_DMA_Config_Reg; - break; - case 3: - return NITIO_G3_DMA_Config_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_DMA_Status_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_DMA_Status_Reg; - break; - case 1: - return NITIO_G1_DMA_Status_Reg; - break; - case 2: - return NITIO_G2_DMA_Status_Reg; - break; - case 3: - return NITIO_G3_DMA_Status_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_ABZ_Reg; - break; - case 1: - return NITIO_G1_ABZ_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg( - int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Interrupt_Acknowledge_Reg; - break; - case 1: - return NITIO_G1_Interrupt_Acknowledge_Reg; - break; - case 2: - return NITIO_G2_Interrupt_Acknowledge_Reg; - break; - case 3: - return NITIO_G3_Interrupt_Acknowledge_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Status_Reg; - break; - case 1: - return NITIO_G1_Status_Reg; - break; - case 2: - return NITIO_G2_Status_Reg; - break; - case 3: - return NITIO_G3_Status_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg( - int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Interrupt_Enable_Reg; - break; - case 1: - return NITIO_G1_Interrupt_Enable_Reg; - break; - case 2: - return NITIO_G2_Interrupt_Enable_Reg; - break; - case 3: - return NITIO_G3_Interrupt_Enable_Reg; - break; - default: - BUG(); - break; - } - return 0; -} +#define NITIO_AUTO_INC_REG(x) (NITIO_G0_AUTO_INC + (x)) +#define NITIO_CMD_REG(x) (NITIO_G0_CMD + (x)) +#define NITIO_HW_SAVE_REG(x) (NITIO_G0_HW_SAVE + (x)) +#define NITIO_SW_SAVE_REG(x) (NITIO_G0_SW_SAVE + (x)) +#define NITIO_MODE_REG(x) (NITIO_G0_MODE + (x)) +#define NITIO_LOADA_REG(x) (NITIO_G0_LOADA + (x)) +#define NITIO_LOADB_REG(x) (NITIO_G0_LOADB + (x)) +#define NITIO_INPUT_SEL_REG(x) (NITIO_G0_INPUT_SEL + (x)) +#define NITIO_CNT_MODE_REG(x) (NITIO_G0_CNT_MODE + (x)) +#define NITIO_GATE2_REG(x) (NITIO_G0_GATE2 + (x)) +#define NITIO_SHARED_STATUS_REG(x) (NITIO_G01_STATUS + ((x) / 2)) +#define NITIO_RESET_REG(x) (NITIO_G01_RESET + ((x) / 2)) +#define NITIO_STATUS1_REG(x) (NITIO_G01_STATUS1 + ((x) / 2)) +#define NITIO_STATUS2_REG(x) (NITIO_G01_STATUS2 + ((x) / 2)) +#define NITIO_DMA_CFG_REG(x) (NITIO_G0_DMA_CFG + (x)) +#define NITIO_DMA_STATUS_REG(x) (NITIO_G0_DMA_STATUS + (x)) +#define NITIO_ABZ_REG(x) (NITIO_G0_ABZ + (x)) +#define NITIO_INT_ACK_REG(x) (NITIO_G0_INT_ACK + (x)) +#define NITIO_STATUS_REG(x) (NITIO_G0_STATUS + (x)) +#define NITIO_INT_ENA_REG(x) (NITIO_G0_INT_ENA + (x)) enum Gi_Auto_Increment_Reg_Bits { Gi_Auto_Increment_Mask = 0xff @@ -699,14 +316,14 @@ static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index) static inline void write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) { - BUG_ON(reg >= NITIO_Num_Registers); + BUG_ON(reg >= NITIO_NUM_REGS); counter->counter_dev->write_register(counter, bits, reg); } static inline unsigned read_register(struct ni_gpct *counter, enum ni_gpct_register reg) { - BUG_ON(reg >= NITIO_Num_Registers); + BUG_ON(reg >= NITIO_NUM_REGS); return counter->counter_dev->read_register(counter, reg); } @@ -738,7 +355,7 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter, struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned long flags; - BUG_ON(register_index >= NITIO_Num_Registers); + BUG_ON(register_index >= NITIO_NUM_REGS); spin_lock_irqsave(&counter_dev->regs_lock, flags); counter_dev->regs[register_index] &= ~bit_mask; counter_dev->regs[register_index] |= (bit_values & bit_mask); @@ -773,7 +390,7 @@ static inline unsigned ni_tio_get_soft_copy(const struct ni_gpct *counter, unsigned long flags; unsigned value; - BUG_ON(register_index >= NITIO_Num_Registers); + BUG_ON(register_index >= NITIO_NUM_REGS); spin_lock_irqsave(&counter_dev->regs_lock, flags); value = counter_dev->regs[register_index]; spin_unlock_irqrestore(&counter_dev->regs_lock, flags); diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index cff50bc45bc..2557ab48cb6 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -44,18 +44,16 @@ TODO: Support use of both banks X and Y */ +#include <linux/module.h> #include "comedi_fc.h" #include "ni_tio_internal.h" #include "mite.h" -MODULE_AUTHOR("Comedi <comedi@comedi.org>"); -MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters"); -MODULE_LICENSE("GPL"); - static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, short read_not_write) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; unsigned input_select_bits = 0; if (enable) { @@ -64,8 +62,7 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, else input_select_bits |= Gi_Write_Acknowledges_Irq; } - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Read_Acknowledges_Irq | Gi_Write_Acknowledges_Irq, input_select_bits); switch (counter_dev->variant) { @@ -82,9 +79,7 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, } if (read_not_write == 0) gi_dma_config_bits |= Gi_DMA_Write_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_DMA_Config_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), Gi_DMA_Enable_Bit | Gi_DMA_Int_Bit | Gi_DMA_Write_Bit, gi_dma_config_bits); } @@ -94,14 +89,16 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, static int ni_tio_input_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { + struct ni_gpct *counter = s->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int retval = 0; - struct ni_gpct *counter = s->private; BUG_ON(counter == NULL); - if (trignum != 0) + + if (trig_num != cmd->start_src) return -EINVAL; spin_lock_irqsave(&counter->lock, flags); @@ -118,14 +115,17 @@ static int ni_tio_input_inttrig(struct comedi_device *dev, return retval; } -static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) +static int ni_tio_input_cmd(struct comedi_subdevice *s) { + struct ni_gpct *counter = s->private; struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; + struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; int retval = 0; /* write alloc the entire buffer */ - comedi_buf_write_alloc(async, async->prealloc_bufsz); + comedi_buf_write_alloc(s, async->prealloc_bufsz); counter->mite_chan->dir = COMEDI_INPUT; switch (counter_dev->variant) { case ni_gpct_variant_m_series: @@ -139,8 +139,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) BUG(); break; } - ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), - Gi_Save_Trace_Bit, 0); + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Save_Trace_Bit, 0); ni_tio_configure_dma(counter, 1, 1); switch (cmd->start_src) { case TRIG_NOW: @@ -167,9 +166,10 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) return retval; } -static int ni_tio_output_cmd(struct ni_gpct *counter, - struct comedi_async *async) +static int ni_tio_output_cmd(struct comedi_subdevice *s) { + struct ni_gpct *counter = s->private; + dev_err(counter->counter_dev->dev->class_dev, "output commands not yet implemented.\n"); return -ENOTSUPP; @@ -181,9 +181,11 @@ static int ni_tio_output_cmd(struct ni_gpct *counter, return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); } -static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async) +static int ni_tio_cmd_setup(struct comedi_subdevice *s) { - struct comedi_cmd *cmd = &async->cmd; + struct comedi_cmd *cmd = &s->async->cmd; + struct ni_gpct *counter = s->private; + unsigned cidx = counter->counter_index; int set_gate_source = 0; unsigned gate_source; int retval = 0; @@ -198,19 +200,17 @@ static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async) if (set_gate_source) retval = ni_tio_set_gate_src(counter, 0, gate_source); if (cmd->flags & TRIG_WAKE_EOS) { - ni_tio_set_bits(counter, - NITIO_Gi_Interrupt_Enable_Reg(counter-> - counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter-> - counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter-> - counter_index)); + ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), + Gi_Gate_Interrupt_Enable_Bit(cidx), + Gi_Gate_Interrupt_Enable_Bit(cidx)); } return retval; } -int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) +int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_gpct *counter = s->private; + struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; int retval = 0; unsigned long flags; @@ -223,12 +223,12 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) "Interrupt-driven commands not yet implemented.\n"); retval = -EIO; } else { - retval = ni_tio_cmd_setup(counter, async); + retval = ni_tio_cmd_setup(s); if (retval == 0) { if (cmd->flags & CMDF_WRITE) - retval = ni_tio_output_cmd(counter, async); + retval = ni_tio_output_cmd(s); else - retval = ni_tio_input_cmd(counter, async); + retval = ni_tio_input_cmd(s); } } spin_unlock_irqrestore(&counter->lock, flags); @@ -236,8 +236,11 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) } EXPORT_SYMBOL_GPL(ni_tio_cmd); -int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) +int ni_tio_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { + struct ni_gpct *counter = s->private; int err = 0; unsigned int sources; @@ -274,8 +277,16 @@ int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src != TRIG_EXT) + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: + case TRIG_OTHER: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* start_arg is the start_trigger passed to ni_tio_arm() */ + break; + } if (cmd->scan_begin_src != TRIG_EXT) err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); @@ -300,6 +311,7 @@ EXPORT_SYMBOL_GPL(ni_tio_cmdtest); int ni_tio_cancel(struct ni_gpct *counter) { + unsigned cidx = counter->counter_index; unsigned long flags; ni_tio_arm(counter, 0, 0); @@ -309,10 +321,8 @@ int ni_tio_cancel(struct ni_gpct *counter) spin_unlock_irqrestore(&counter->lock, flags); ni_tio_configure_dma(counter, 0, 0); - ni_tio_set_bits(counter, - NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), - 0x0); + ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), + Gi_Gate_Interrupt_Enable_Bit(cidx), 0x0); return 0; } EXPORT_SYMBOL_GPL(ni_tio_cancel); @@ -352,14 +362,11 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, int *perm_stale_data, int *stale_data) { + unsigned cidx = counter->counter_index; const unsigned short gxx_status = read_register(counter, - NITIO_Gxx_Status_Reg - (counter-> - counter_index)); + NITIO_SHARED_STATUS_REG(cidx)); const unsigned short gi_status = read_register(counter, - NITIO_Gi_Status_Reg - (counter-> - counter_index)); + NITIO_STATUS_REG(cidx)); unsigned ack = 0; if (gate_error) @@ -371,8 +378,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, if (stale_data) *stale_data = 0; - if (gxx_status & Gi_Gate_Error_Bit(counter->counter_index)) { - ack |= Gi_Gate_Error_Confirm_Bit(counter->counter_index); + if (gxx_status & Gi_Gate_Error_Bit(cidx)) { + ack |= Gi_Gate_Error_Confirm_Bit(cidx); if (gate_error) { /*660x don't support automatic acknowledgement of gate interrupt via dma read/write @@ -383,8 +390,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, } } } - if (gxx_status & Gi_TC_Error_Bit(counter->counter_index)) { - ack |= Gi_TC_Error_Confirm_Bit(counter->counter_index); + if (gxx_status & Gi_TC_Error_Bit(cidx)) { + ack |= Gi_TC_Error_Confirm_Bit(cidx); if (tc_error) *tc_error = 1; } @@ -395,21 +402,15 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, ack |= Gi_Gate_Interrupt_Ack_Bit; } if (ack) - write_register(counter, ack, - NITIO_Gi_Interrupt_Acknowledge_Reg - (counter->counter_index)); - if (ni_tio_get_soft_copy - (counter, - NITIO_Gi_Mode_Reg(counter->counter_index)) & + write_register(counter, ack, NITIO_INT_ACK_REG(cidx)); + if (ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)) & Gi_Loading_On_Gate_Bit) { - if (gxx_status & Gi_Stale_Data_Bit(counter->counter_index)) { + if (gxx_status & Gi_Stale_Data_Bit(cidx)) { if (stale_data) *stale_data = 1; } - if (read_register(counter, - NITIO_Gxx_Joint_Status2_Reg - (counter->counter_index)) & - Gi_Permanent_Stale_Bit(counter->counter_index)) { + if (read_register(counter, NITIO_STATUS2_REG(cidx)) & + Gi_Permanent_Stale_Bit(cidx)) { dev_info(counter->counter_dev->dev->class_dev, "%s: Gi_Permanent_Stale_Data detected.\n", __func__); @@ -423,6 +424,7 @@ EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm); void ni_tio_handle_interrupt(struct ni_gpct *counter, struct comedi_subdevice *s) { + unsigned cidx = counter->counter_index; unsigned gpct_mite_status; unsigned long flags; int gate_error; @@ -441,9 +443,8 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: case ni_gpct_variant_660x: - if (read_register(counter, - NITIO_Gi_DMA_Status_Reg - (counter->counter_index)) & Gi_DRQ_Error_Bit) { + if (read_register(counter, NITIO_DMA_STATUS_REG(cidx)) & + Gi_DRQ_Error_Bit) { dev_notice(counter->counter_dev->dev->class_dev, "%s: Gi_DRQ_Error detected.\n", __func__); s->async->events |= COMEDI_CB_OVERFLOW; @@ -463,7 +464,7 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, counter->mite_chan->mite->mite_io_addr + MITE_CHOR(counter->mite_chan->channel)); } - mite_sync_input_dma(counter->mite_chan, s->async); + mite_sync_input_dma(counter->mite_chan, s); spin_unlock_irqrestore(&counter->lock, flags); } EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt); @@ -483,11 +484,13 @@ static int __init ni_tiocmd_init_module(void) { return 0; } - module_init(ni_tiocmd_init_module); static void __exit ni_tiocmd_cleanup_module(void) { } - module_exit(ni_tiocmd_cleanup_module); + +MODULE_AUTHOR("Comedi <comedi@comedi.org>"); +MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index 7abf3f74144..c38d97a9a89 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -1,266 +1,302 @@ /* - comedi/drivers/pcl711.c - hardware driver for PC-LabCard PCL-711 and AdSys ACL-8112 - and compatibles - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - Janne Jalkanen <jalkanen@cs.hut.fi> - Eric Bunn <ebu@cs.hut.fi> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * pcl711.c + * Comedi driver for PC-LabCard PCL-711 and AdSys ACL-8112 and compatibles + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * Janne Jalkanen <jalkanen@cs.hut.fi> + * Eric Bunn <ebu@cs.hut.fi> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: pcl711 -Description: Advantech PCL-711 and 711b, ADLink ACL-8112 -Author: ds, Janne Jalkanen <jalkanen@cs.hut.fi>, Eric Bunn <ebu@cs.hut.fi> -Status: mostly complete -Devices: [Advantech] PCL-711 (pcl711), PCL-711B (pcl711b), - [AdLink] ACL-8112HG (acl8112hg), ACL-8112DG (acl8112dg) - -Since these boards do not have DMA or FIFOs, only immediate mode is -supported. - -*/ /* - Dave Andruczyk <dave@tech.buffalostate.edu> also wrote a - driver for the PCL-711. I used a few ideas from his driver - here. His driver also has more comments, if you are - interested in understanding how this driver works. - http://tech.buffalostate.edu/~dave/driver/ - - The ACL-8112 driver was hacked from the sources of the PCL-711 - driver (the 744 chip used on the 8112 is almost the same as - the 711b chip, but it has more I/O channels) by - Janne Jalkanen (jalkanen@cs.hut.fi) and - Erik Bunn (ebu@cs.hut.fi). Remerged with the PCL-711 driver - by ds. - - [acl-8112] - This driver supports both TRIGNOW and TRIGCLK, - but does not yet support DMA transfers. It also supports - both high (HG) and low (DG) versions of the card, though - the HG version has been untested. - + * Driver: pcl711 + * Description: Advantech PCL-711 and 711b, ADLink ACL-8112 + * Devices: (Advantech) PCL-711 [pcl711] + * (Advantech) PCL-711B [pcl711b] + * (AdLink) ACL-8112HG [acl8112hg] + * (AdLink) ACL-8112DG [acl8112dg] + * Author: David A. Schleef <ds@schleef.org> + * Janne Jalkanen <jalkanen@cs.hut.fi> + * Eric Bunn <ebu@cs.hut.fi> + * Updated: + * Status: mostly complete + * + * Configuration Options: + * [0] - I/O port base + * [1] - IRQ, optional */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> -#include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/delay.h> +#include "../comedidev.h" #include "comedi_fc.h" #include "8253.h" -#define PCL711_SIZE 16 - -#define PCL711_CTR0 0 -#define PCL711_CTR1 1 -#define PCL711_CTR2 2 -#define PCL711_CTRCTL 3 -#define PCL711_AD_LO 4 -#define PCL711_DA0_LO 4 -#define PCL711_AD_HI 5 -#define PCL711_DA0_HI 5 -#define PCL711_DI_LO 6 -#define PCL711_DA1_LO 6 -#define PCL711_DI_HI 7 -#define PCL711_DA1_HI 7 -#define PCL711_CLRINTR 8 -#define PCL711_GAIN 9 -#define PCL711_MUX 10 -#define PCL711_MODE 11 -#define PCL711_SOFTTRIG 12 -#define PCL711_DO_LO 13 -#define PCL711_DO_HI 14 - -static const struct comedi_lrange range_pcl711b_ai = { 5, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125) - } +/* + * I/O port register map + */ +#define PCL711_TIMER_BASE 0x00 +#define PCL711_AI_LSB_REG 0x04 +#define PCL711_AI_MSB_REG 0x05 +#define PCL711_AI_MSB_DRDY (1 << 4) +#define PCL711_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL711_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL711_DI_LSB_REG 0x06 +#define PCL711_DI_MSB_REG 0x07 +#define PCL711_INT_STAT_REG 0x08 +#define PCL711_INT_STAT_CLR (0 << 0) /* any value will work */ +#define PCL711_AI_GAIN_REG 0x09 +#define PCL711_AI_GAIN(x) (((x) & 0xf) << 0) +#define PCL711_MUX_REG 0x0a +#define PCL711_MUX_CHAN(x) (((x) & 0xf) << 0) +#define PCL711_MUX_CS0 (1 << 4) +#define PCL711_MUX_CS1 (1 << 5) +#define PCL711_MUX_DIFF (PCL711_MUX_CS0 | PCL711_MUX_CS1) +#define PCL711_MODE_REG 0x0b +#define PCL711_MODE_DEFAULT (0 << 0) +#define PCL711_MODE_SOFTTRIG (1 << 0) +#define PCL711_MODE_EXT (2 << 0) +#define PCL711_MODE_EXT_IRQ (3 << 0) +#define PCL711_MODE_PACER (4 << 0) +#define PCL711_MODE_PACER_IRQ (6 << 0) +#define PCL711_MODE_IRQ(x) (((x) & 0x7) << 4) +#define PCL711_SOFTTRIG_REG 0x0c +#define PCL711_SOFTTRIG (0 << 0) /* any value will work */ +#define PCL711_DO_LSB_REG 0x0d +#define PCL711_DO_MSB_REG 0x0e + +static const struct comedi_lrange range_pcl711b_ai = { + 5, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_acl8112hg_ai = { 12, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01) - } +static const struct comedi_lrange range_acl8112hg_ai = { + 12, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_acl8112dg_ai = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10) - } +static const struct comedi_lrange range_acl8112dg_ai = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; -/* - * flags - */ - -#define PCL711_TIMEOUT 100 -#define PCL711_DRDY 0x10 - -static const int i8253_osc_base = 500; /* 2 Mhz */ - struct pcl711_board { - const char *name; - int is_pcl711b; - int is_8112; - int is_dg; - int n_ranges; int n_aichan; int n_aochan; int maxirq; const struct comedi_lrange *ai_range_type; }; -struct pcl711_private { +static const struct pcl711_board boardtypes[] = { + { + .name = "pcl711", + .n_aichan = 8, + .n_aochan = 1, + .ai_range_type = &range_bipolar5, + }, { + .name = "pcl711b", + .n_aichan = 8, + .n_aochan = 1, + .maxirq = 7, + .ai_range_type = &range_pcl711b_ai, + }, { + .name = "acl8112hg", + .n_aichan = 16, + .n_aochan = 2, + .maxirq = 15, + .ai_range_type = &range_acl8112hg_ai, + }, { + .name = "acl8112dg", + .n_aichan = 16, + .n_aochan = 2, + .maxirq = 15, + .ai_range_type = &range_acl8112dg_ai, + }, +}; - int board; - int adchan; - int ntrig; - int aip[8]; - int mode; +struct pcl711_private { + unsigned int ntrig; unsigned int ao_readback[2]; unsigned int divisor1; unsigned int divisor2; }; +static void pcl711_ai_set_mode(struct comedi_device *dev, unsigned int mode) +{ + /* + * The pcl711b board uses bits in the mode register to select the + * interrupt. The other boards supported by this driver all use + * jumpers on the board. + * + * Enables the interrupt when needed on the pcl711b board. These + * bits do nothing on the other boards. + */ + if (mode == PCL711_MODE_EXT_IRQ || mode == PCL711_MODE_PACER_IRQ) + mode |= PCL711_MODE_IRQ(dev->irq); + + outb(mode, dev->iobase + PCL711_MODE_REG); +} + +static unsigned int pcl711_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + PCL711_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL711_AI_LSB_REG); + + return val & s->maxdata; +} + +static int pcl711_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); + return 0; +} + static irqreturn_t pcl711_interrupt(int irq, void *d) { - int lo, hi; - int data; struct comedi_device *dev = d; - const struct pcl711_board *board = comedi_board(dev); struct pcl711_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int data; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); return IRQ_HANDLED; } - hi = inb(dev->iobase + PCL711_AD_HI); - lo = inb(dev->iobase + PCL711_AD_LO); - outb(0, dev->iobase + PCL711_CLRINTR); - - data = (hi << 8) | lo; + data = pcl711_ai_get_sample(dev, s); - /* FIXME! Nothing else sets ntrig! */ - if (!(--devpriv->ntrig)) { - if (board->is_8112) - outb(1, dev->iobase + PCL711_MODE); - else - outb(0, dev->iobase + PCL711_MODE); + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); - s->async->events |= COMEDI_CB_EOA; + if (comedi_buf_put(s, data) == 0) { + s->async->events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + } else { + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + if (cmd->stop_src == TRIG_COUNT && !(--devpriv->ntrig)) { + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); + s->async->events |= COMEDI_CB_EOA; + } } comedi_event(dev, s); return IRQ_HANDLED; } -static void pcl711_set_changain(struct comedi_device *dev, int chan) +static void pcl711_set_changain(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chanspec) { - const struct pcl711_board *board = comedi_board(dev); - int chan_register; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int mux = 0; + + outb(PCL711_AI_GAIN(range), dev->iobase + PCL711_AI_GAIN_REG); + + if (s->n_chan > 8) { + /* Select the correct MPC508A chip */ + if (aref == AREF_DIFF) { + chan &= 0x7; + mux |= PCL711_MUX_DIFF; + } else { + if (chan < 8) + mux |= PCL711_MUX_CS0; + else + mux |= PCL711_MUX_CS1; + } + } + outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG); +} - outb(CR_RANGE(chan), dev->iobase + PCL711_GAIN); +static int pcl711_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; - chan_register = CR_CHAN(chan); + status = inb(dev->iobase + PCL711_AI_MSB_REG); + if ((status & PCL711_AI_MSB_DRDY) == 0) + return 0; + return -EBUSY; +} - if (board->is_8112) { +static int pcl711_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + int i; - /* - * Set the correct channel. The two channel banks are switched - * using the mask value. - * NB: To use differential channels, you should use - * mask = 0x30, but I haven't written the support for this - * yet. /JJ - */ + pcl711_set_changain(dev, s, insn->chanspec); - if (chan_register >= 8) - chan_register = 0x20 | (chan_register & 0x7); - else - chan_register |= 0x10; - } else { - outb(chan_register, dev->iobase + PCL711_MUX); - } -} + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); -static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - const struct pcl711_board *board = comedi_board(dev); - int i, n; - int hi, lo; - - pcl711_set_changain(dev, insn->chanspec); - - for (n = 0; n < insn->n; n++) { - /* - * Write the correct mode (software polling) and start polling - * by writing to the trigger register - */ - outb(1, dev->iobase + PCL711_MODE); - - if (!board->is_8112) - outb(0, dev->iobase + PCL711_SOFTTRIG); - - i = PCL711_TIMEOUT; - while (--i) { - hi = inb(dev->iobase + PCL711_AD_HI); - if (!(hi & PCL711_DRDY)) - goto ok; - udelay(1); - } - printk(KERN_ERR "comedi%d: pcl711: A/D timeout\n", dev->minor); - return -ETIME; + for (i = 0; i < insn->n; i++) { + outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG); -ok: - lo = inb(dev->iobase + PCL711_AD_LO); + ret = comedi_timeout(dev, s, insn, pcl711_ai_eoc, 0); + if (ret) + return ret; - data[n] = ((hi & 0xf) << 8) | lo; + data[i] = pcl711_ai_get_sample(dev, s); } - return n; + return insn->n; } static int pcl711_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { struct pcl711_private *devpriv = dev->private; - int tmp; int err = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -292,7 +328,6 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } else { #define MAX_SPEED 1000 -#define TIMER_BASE 100 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, MAX_SPEED); } @@ -300,11 +335,8 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) { + if (cmd->stop_src == TRIG_NONE) err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } else { - /* ignore */ - } if (err) return 3; @@ -312,14 +344,12 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, /* step 4 */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) @@ -328,113 +358,116 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, return 0; } +static void pcl711_ai_load_counters(struct comedi_device *dev) +{ + struct pcl711_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL711_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); +} + static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl711_private *devpriv = dev->private; - int timer1, timer2; struct comedi_cmd *cmd = &s->async->cmd; - pcl711_set_changain(dev, cmd->chanlist[0]); + pcl711_set_changain(dev, s, cmd->chanlist[0]); + + if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_arg == 0) { + /* an empty acquisition */ + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + return 0; + } + devpriv->ntrig = cmd->stop_arg; + } if (cmd->scan_begin_src == TRIG_TIMER) { - /* - * Set timers - * timer chip is an 8253, with timers 1 and 2 - * cascaded - * 0x74 = Select Counter 1 | LSB/MSB | Mode=2 | Binary - * Mode 2 = Rate generator - * - * 0xb4 = Select Counter 2 | LSB/MSB | Mode=2 | Binary - */ - - timer1 = timer2 = 0; - i8253_cascade_ns_to_timer(i8253_osc_base, &timer1, &timer2, - &cmd->scan_begin_arg, - TRIG_ROUND_NEAREST); - - outb(0x74, dev->iobase + PCL711_CTRCTL); - outb(timer1 & 0xff, dev->iobase + PCL711_CTR1); - outb((timer1 >> 8) & 0xff, dev->iobase + PCL711_CTR1); - outb(0xb4, dev->iobase + PCL711_CTRCTL); - outb(timer2 & 0xff, dev->iobase + PCL711_CTR2); - outb((timer2 >> 8) & 0xff, dev->iobase + PCL711_CTR2); - - /* clear pending interrupts (just in case) */ - outb(0, dev->iobase + PCL711_CLRINTR); - - /* - * Set mode to IRQ transfer - */ - outb(devpriv->mode | 6, dev->iobase + PCL711_MODE); + pcl711_ai_load_counters(dev); + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); + pcl711_ai_set_mode(dev, PCL711_MODE_PACER_IRQ); } else { - /* external trigger */ - outb(devpriv->mode | 3, dev->iobase + PCL711_MODE); + pcl711_ai_set_mode(dev, PCL711_MODE_EXT_IRQ); } return 0; } -/* - analog output -*/ -static int pcl711_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl711_ao_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) { - struct pcl711_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); + outb(val & 0xff, dev->iobase + PCL711_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + PCL711_AO_MSB_REG(chan)); +} - for (n = 0; n < insn->n; n++) { - outb((data[n] & 0xff), - dev->iobase + (chan ? PCL711_DA1_LO : PCL711_DA0_LO)); - outb((data[n] >> 8), - dev->iobase + (chan ? PCL711_DA1_HI : PCL711_DA0_HI)); +static int pcl711_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl711_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int i; - devpriv->ao_readback[chan] = data[n]; + for (i = 0; i < insn->n; i++) { + val = data[i]; + pcl711_ao_write(dev, chan, val); } + devpriv->ao_readback[chan] = val; - return n; + return insn->n; } static int pcl711_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct pcl711_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - return n; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + return insn->n; } -/* Digital port read - Untested on 8112 */ static int pcl711_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - data[1] = inb(dev->iobase + PCL711_DI_LO) | - (inb(dev->iobase + PCL711_DI_HI) << 8); + unsigned int val; + + val = inb(dev->iobase + PCL711_DI_LSB_REG); + val |= (inb(dev->iobase + PCL711_DI_MSB_REG) << 8); + + data[1] = val; return insn->n; } -/* Digital port write - Untested on 8112 */ static int pcl711_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x00ff) + outb(s->state & 0xff, dev->iobase + PCL711_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), dev->iobase + PCL711_DO_MSB_REG); } - if (data[0] & 0x00ff) - outb(s->state & 0xff, dev->iobase + PCL711_DO_LO); - if (data[0] & 0xff00) - outb((s->state >> 8), dev->iobase + PCL711_DO_HI); data[1] = s->state; @@ -445,113 +478,82 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl711_board *board = comedi_board(dev); struct pcl711_private *devpriv; - int ret; - unsigned int irq; struct comedi_subdevice *s; + int ret; - ret = comedi_request_region(dev, it->options[0], PCL711_SIZE); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - /* grab our IRQ */ - irq = it->options[1]; - if (irq > board->maxirq) { - printk(KERN_ERR "irq out of range\n"); - return -EINVAL; - } - if (irq) { - if (request_irq(irq, pcl711_interrupt, 0, dev->board_name, - dev)) { - printk(KERN_ERR "unable to allocate irq %u\n", irq); - return -EINVAL; - } else { - printk(KERN_INFO "( irq = %u )\n", irq); - } + if (it->options[1] && it->options[1] <= board->maxirq) { + ret = request_irq(it->options[1], pcl711_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - dev->irq = irq; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* AI subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = board->n_aichan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = board->ai_range_type; - s->insn_read = pcl711_ai_insn; - if (irq) { + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + if (board->n_aichan > 8) + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan; + s->maxdata = 0xfff; + s->range_table = board->ai_range_type; + s->insn_read = pcl711_ai_insn_read; + if (dev->irq) { dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = pcl711_ai_cmdtest; - s->do_cmd = pcl711_ai_cmd; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->do_cmdtest = pcl711_ai_cmdtest; + s->do_cmd = pcl711_ai_cmd; + s->cancel = pcl711_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* AO subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = &range_bipolar5; - s->insn_write = pcl711_ao_insn; - s->insn_read = pcl711_ao_insn_read; - + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &range_bipolar5; + s->insn_write = pcl711_ao_insn_write; + s->insn_read = pcl711_ao_insn_read; + + /* Digital Input subdevice */ s = &dev->subdevices[2]; - /* 16-bit digital input */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->insn_bits = pcl711_di_insn_bits; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl711_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - /* 16-bit digital out */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->state = 0; - s->insn_bits = pcl711_do_insn_bits; - - /* - this is the "base value" for the mode register, which is - used for the irq on the PCL711 - */ - if (board->is_pcl711b) - devpriv->mode = (dev->irq << 4); + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl711_do_insn_bits; /* clear DAC */ - outb(0, dev->iobase + PCL711_DA0_LO); - outb(0, dev->iobase + PCL711_DA0_HI); - outb(0, dev->iobase + PCL711_DA1_LO); - outb(0, dev->iobase + PCL711_DA1_HI); - - printk(KERN_INFO "\n"); + pcl711_ao_write(dev, 0, 0x0); + pcl711_ao_write(dev, 1, 0x0); return 0; } -static const struct pcl711_board boardtypes[] = { - { "pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5 }, - { "pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai }, - { "acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai }, - { "acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai }, -}; - static struct comedi_driver pcl711_driver = { .driver_name = "pcl711", .module = THIS_MODULE, @@ -564,5 +566,5 @@ static struct comedi_driver pcl711_driver = { module_comedi_driver(pcl711_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for PCL-711 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c index cea657c7801..8af13e790ad 100644 --- a/drivers/staging/comedi/drivers/pcl724.c +++ b/drivers/staging/comedi/drivers/pcl724.c @@ -1,6 +1,6 @@ /* * pcl724.c - * Comedi driver for 8255 based ISA DIO boards + * Comedi driver for 8255 based ISA and PC/104 DIO boards * * Michal Dobes <dobes@tesnet.cz> */ @@ -14,6 +14,7 @@ * (ADLink) ACL-7122 [acl7122] * (ADLink) ACL-7124 [acl7124] * (ADLink) PET-48DIO [pet48dio] + * (WinSystems) PCM-IO48 [pcmio48] * Author: Michal Dobes <dobes@tesnet.cz> * Status: untested * @@ -25,11 +26,9 @@ * 1, 96: 96 DIO configuration */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/delay.h> - #include "8255.h" #define SIZE_8255 4 @@ -70,6 +69,10 @@ static const struct pcl724_board boardtypes[] = { .io_range = 0x02, .is_pet48 = 1, .numofports = 2, /* 48 DIO channels */ + }, { + .name = "pcmio48", + .io_range = 0x08, + .numofports = 2, /* 48 DIO channels */ }, }; @@ -148,5 +151,5 @@ static struct comedi_driver pcl724_driver = { module_comedi_driver(pcl724_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi driver for 8255 based ISA DIO boards"); +MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index 893f012a1b7..74f6489bd12 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -1,330 +1,439 @@ /* - comedi/drivers/pcl726.c - - hardware driver for Advantech cards: - card: PCL-726, PCL-727, PCL-728 - driver: pcl726, pcl727, pcl728 - and for ADLink cards: - card: ACL-6126, ACL-6128 - driver: acl6126, acl6128 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: pcl726 -Description: Advantech PCL-726 & compatibles -Author: ds -Status: untested -Devices: [Advantech] PCL-726 (pcl726), PCL-727 (pcl727), PCL-728 (pcl728), - [ADLink] ACL-6126 (acl6126), ACL-6128 (acl6128) - -Interrupts are not supported. - - Options for PCL-726: - [0] - IO Base - [2]...[7] - D/A output range for channel 1-6: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA, 5: unknown (external reference) - - Options for PCL-727: - [0] - IO Base - [2]...[13] - D/A output range for channel 1-12: - 0: 0-5V, 1: 0-10V, 2: +/-5V, - 3: 4-20mA - - Options for PCL-728 and ACL-6128: - [0] - IO Base - [2], [3] - D/A output range for channel 1 and 2: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA, 5: 0-20mA - - Options for ACL-6126: - [0] - IO Base - [1] - IRQ (0=disable, 3, 5, 6, 7, 9, 10, 11, 12, 15) (currently ignored) - [2]...[7] - D/A output range for channel 1-6: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA -*/ + * pcl726.c + * Comedi driver for 6/12-Channel D/A Output and DIO cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* - Thanks to Circuit Specialists for having programming info (!) on - their web page. (http://www.cir.com/) -*/ + * Driver: pcl726 + * Description: Advantech PCL-726 & compatibles + * Author: David A. Schleef <ds@schleef.org> + * Status: untested + * Devices: (Advantech) PCL-726 [pcl726] + * (Advantech) PCL-727 [pcl727] + * (Advantech) PCL-728 [pcl728] + * (ADLink) ACL-6126 [acl6126] + * (ADLink) ACL-6128 [acl6128] + * + * Configuration Options: + * [0] - IO Base + * [1] - IRQ (ACL-6126 only) + * [2] - D/A output range for channel 0 + * [3] - D/A output range for channel 1 + * + * Boards with > 2 analog output channels: + * [4] - D/A output range for channel 2 + * [5] - D/A output range for channel 3 + * [6] - D/A output range for channel 4 + * [7] - D/A output range for channel 5 + * + * Boards with > 6 analog output channels: + * [8] - D/A output range for channel 6 + * [9] - D/A output range for channel 7 + * [10] - D/A output range for channel 8 + * [11] - D/A output range for channel 9 + * [12] - D/A output range for channel 10 + * [13] - D/A output range for channel 11 + * + * For PCL-726 the D/A output ranges are: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: unknown + * + * For PCL-727: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: 4-20mA + * + * For PCL-728 and ACL-6128: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: 0-20mA + * + * For ACL-6126: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA + */ + +#include <linux/module.h> +#include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#undef ACL6126_IRQ /* no interrupt support (yet) */ - -#define PCL726_SIZE 16 -#define PCL727_SIZE 32 -#define PCL728_SIZE 8 +#include "comedi_fc.h" -#define PCL726_DAC0_HI 0 -#define PCL726_DAC0_LO 1 +#define PCL726_AO_MSB_REG(x) (0x00 + ((x) * 2)) +#define PCL726_AO_LSB_REG(x) (0x01 + ((x) * 2)) +#define PCL726_DO_MSB_REG 0x0c +#define PCL726_DO_LSB_REG 0x0d +#define PCL726_DI_MSB_REG 0x0e +#define PCL726_DI_LSB_REG 0x0f -#define PCL726_DO_HI 12 -#define PCL726_DO_LO 13 -#define PCL726_DI_HI 14 -#define PCL726_DI_LO 15 - -#define PCL727_DO_HI 24 -#define PCL727_DO_LO 25 -#define PCL727_DI_HI 0 -#define PCL727_DI_LO 1 +#define PCL727_DI_MSB_REG 0x00 +#define PCL727_DI_LSB_REG 0x01 +#define PCL727_DO_MSB_REG 0x18 +#define PCL727_DO_LSB_REG 0x19 static const struct comedi_lrange *const rangelist_726[] = { - &range_unipolar5, &range_unipolar10, - &range_bipolar5, &range_bipolar10, - &range_4_20mA, &range_unknown + &range_unipolar5, + &range_unipolar10, + &range_bipolar5, + &range_bipolar10, + &range_4_20mA, + &range_unknown }; static const struct comedi_lrange *const rangelist_727[] = { - &range_unipolar5, &range_unipolar10, + &range_unipolar5, + &range_unipolar10, &range_bipolar5, &range_4_20mA }; static const struct comedi_lrange *const rangelist_728[] = { - &range_unipolar5, &range_unipolar10, - &range_bipolar5, &range_bipolar10, - &range_4_20mA, &range_0_20mA + &range_unipolar5, + &range_unipolar10, + &range_bipolar5, + &range_bipolar10, + &range_4_20mA, + &range_0_20mA }; struct pcl726_board { - - const char *name; /* driver name */ - int n_aochan; /* num of D/A chans */ - int num_of_ranges; /* num of ranges */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int io_range; /* len of IO space */ - char have_dio; /* 1=card have DI/DO ports */ - int di_hi; /* ports for DI/DO operations */ - int di_lo; - int do_hi; - int do_lo; - const struct comedi_lrange *const *range_type_list; - /* list of supported ranges */ + const char *name; + unsigned long io_len; + unsigned int irq_mask; + const struct comedi_lrange *const *ao_ranges; + int ao_num_ranges; + int ao_nchan; + unsigned int have_dio:1; + unsigned int is_pcl727:1; }; -static const struct pcl726_board boardtypes[] = { - {"pcl726", 6, 6, 0x0000, PCL726_SIZE, 1, - PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, - &rangelist_726[0],}, - {"pcl727", 12, 4, 0x0000, PCL727_SIZE, 1, - PCL727_DI_HI, PCL727_DI_LO, PCL727_DO_HI, PCL727_DO_LO, - &rangelist_727[0],}, - {"pcl728", 2, 6, 0x0000, PCL728_SIZE, 0, - 0, 0, 0, 0, - &rangelist_728[0],}, - {"acl6126", 6, 5, 0x96e8, PCL726_SIZE, 1, - PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, - &rangelist_726[0],}, - {"acl6128", 2, 6, 0x0000, PCL728_SIZE, 0, - 0, 0, 0, 0, - &rangelist_728[0],}, +static const struct pcl726_board pcl726_boards[] = { + { + .name = "pcl726", + .io_len = 0x10, + .ao_ranges = &rangelist_726[0], + .ao_num_ranges = ARRAY_SIZE(rangelist_726), + .ao_nchan = 6, + .have_dio = 1, + }, { + .name = "pcl727", + .io_len = 0x20, + .ao_ranges = &rangelist_727[0], + .ao_num_ranges = ARRAY_SIZE(rangelist_727), + .ao_nchan = 12, + .have_dio = 1, + .is_pcl727 = 1, + }, { + .name = "pcl728", + .io_len = 0x08, + .ao_num_ranges = ARRAY_SIZE(rangelist_728), + .ao_ranges = &rangelist_728[0], + .ao_nchan = 2, + }, { + .name = "acl6126", + .io_len = 0x10, + .irq_mask = 0x96e8, + .ao_num_ranges = ARRAY_SIZE(rangelist_726), + .ao_ranges = &rangelist_726[0], + .ao_nchan = 6, + .have_dio = 1, + }, { + .name = "acl6128", + .io_len = 0x08, + .ao_num_ranges = ARRAY_SIZE(rangelist_728), + .ao_ranges = &rangelist_728[0], + .ao_nchan = 2, + }, }; struct pcl726_private { - - int bipolar[12]; const struct comedi_lrange *rangelist[12]; unsigned int ao_readback[12]; + unsigned int cmd_running:1; }; -static int pcl726_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcl726_intr_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = 0; + return insn->n; +} + +static int pcl726_intr_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: ignored */ + + if (err) + return 4; + + return 0; +} + +static int pcl726_intr_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl726_private *devpriv = dev->private; + + devpriv->cmd_running = 1; + + return 0; +} + +static int pcl726_intr_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl726_private *devpriv = dev->private; - int hi, lo; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - lo = data[n] & 0xff; - hi = (data[n] >> 8) & 0xf; - if (devpriv->bipolar[chan]) - hi ^= 0x8; - /* - * the programming info did not say which order - * to write bytes. switch the order of the next - * two lines if you get glitches. - */ - outb(hi, dev->iobase + PCL726_DAC0_HI + 2 * chan); - outb(lo, dev->iobase + PCL726_DAC0_LO + 2 * chan); - devpriv->ao_readback[chan] = data[n]; + + devpriv->cmd_running = 0; + + return 0; +} + +static irqreturn_t pcl726_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct pcl726_private *devpriv = dev->private; + + if (devpriv->cmd_running) { + pcl726_intr_cancel(dev, s); + + comedi_buf_put(s, 0); + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + comedi_event(dev, s); } - return n; + return IRQ_HANDLED; +} + +static int pcl726_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl726_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + devpriv->ao_readback[chan] = val; + + /* bipolar data to the DAC is two's complement */ + if (comedi_chan_range_is_bipolar(s, chan, range)) + val = comedi_offset_munge(s, val); + + /* order is important, MSB then LSB */ + outb((val >> 8) & 0xff, dev->iobase + PCL726_AO_MSB_REG(chan)); + outb(val & 0xff, dev->iobase + PCL726_AO_LSB_REG(chan)); + } + + return insn->n; } static int pcl726_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct pcl726_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int n; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; - return n; + return insn->n; } static int pcl726_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct pcl726_board *board = comedi_board(dev); + unsigned int val; - data[1] = inb(dev->iobase + board->di_lo) | - (inb(dev->iobase + board->di_hi) << 8); + if (board->is_pcl727) { + val = inb(dev->iobase + PCL727_DI_LSB_REG); + val |= (inb(dev->iobase + PCL727_DI_MSB_REG) << 8); + } else { + val = inb(dev->iobase + PCL726_DI_LSB_REG); + val |= (inb(dev->iobase + PCL726_DI_MSB_REG) << 8); + } + + data[1] = val; return insn->n; } static int pcl726_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct pcl726_board *board = comedi_board(dev); - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + unsigned long io = dev->iobase; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (board->is_pcl727) { + if (mask & 0x00ff) + outb(s->state & 0xff, io + PCL727_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), io + PCL727_DO_MSB_REG); + } else { + if (mask & 0x00ff) + outb(s->state & 0xff, io + PCL726_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), io + PCL726_DO_MSB_REG); + } } - if (data[1] & 0x00ff) - outb(s->state & 0xff, dev->iobase + board->do_lo); - if (data[1] & 0xff00) - outb((s->state >> 8), dev->iobase + board->do_hi); data[1] = s->state; return insn->n; } -static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcl726_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { const struct pcl726_board *board = comedi_board(dev); struct pcl726_private *devpriv; struct comedi_subdevice *s; - int ret, i; -#ifdef ACL6126_IRQ - unsigned int irq; -#endif + int subdev; + int ret; + int i; - ret = comedi_request_region(dev, it->options[0], board->io_range); + ret = comedi_request_region(dev, it->options[0], board->io_len); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; - - for (i = 0; i < 12; i++) { - devpriv->bipolar[i] = 0; - devpriv->rangelist[i] = &range_unknown; - } -#ifdef ACL6126_IRQ - irq = 0; - if (boardtypes[board].IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - devpriv->first_chan = 2; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & boardtypes[board].IRQbits) == 0) { - printk(KERN_WARNING - ", IRQ %d is out of allowed range," - " DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq(irq, interrupt_pcl818, 0, - dev->board_name, dev)) { - printk(KERN_WARNING - ", unable to allocate IRQ %d," - " DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%d", irq); - } - } + /* + * Hook up the external trigger source interrupt only if the + * user config option is valid and the board supports interrupts. + */ + if (it->options[1] && (board->irq_mask & (1 << it->options[1]))) { + ret = request_irq(it->options[1], pcl726_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + /* External trigger source is from Pin-17 of CN3 */ + dev->irq = it->options[1]; } } - dev->irq = irq; -#endif + /* setup the per-channel analog output range_table_list */ + for (i = 0; i < 12; i++) { + unsigned int opt = it->options[2 + i]; - printk("\n"); + if (opt < board->ao_num_ranges && i < board->ao_nchan) + devpriv->rangelist[i] = board->ao_ranges[opt]; + else + devpriv->rangelist[i] = &range_unknown; + } - ret = comedi_alloc_subdevices(dev, 3); + subdev = board->have_dio ? 3 : 1; + if (dev->irq) + subdev++; + ret = comedi_alloc_subdevices(dev, subdev); if (ret) return ret; - s = &dev->subdevices[0]; - /* ao */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->insn_write = pcl726_ao_insn; - s->insn_read = pcl726_ao_insn_read; - s->range_table_list = devpriv->rangelist; - for (i = 0; i < board->n_aochan; i++) { - int j; - - j = it->options[2 + 1]; - if ((j < 0) || (j >= board->num_of_ranges)) { - printk - ("Invalid range for channel %d! Must be 0<=%d<%d\n", - i, j, board->num_of_ranges - 1); - j = 0; - } - devpriv->rangelist[i] = board->range_type_list[j]; - if (devpriv->rangelist[i]->range[0].min == - -devpriv->rangelist[i]->range[0].max) - devpriv->bipolar[i] = 1; /* bipolar range */ - } + subdev = 0; - s = &dev->subdevices[1]; - /* di */ - if (!board->have_dio) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 1; - s->insn_bits = pcl726_di_insn_bits; - s->range_table = &range_digital; + /* Analog Output subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->ao_nchan; + s->maxdata = 0x0fff; + s->range_table_list = devpriv->rangelist; + s->insn_write = pcl726_ao_insn_write; + s->insn_read = pcl726_ao_insn_read; + + if (board->have_dio) { + /* Digital Input subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->insn_bits = pcl726_di_insn_bits; + s->range_table = &range_digital; + + /* Digital Output subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->insn_bits = pcl726_do_insn_bits; + s->range_table = &range_digital; } - s = &dev->subdevices[2]; - /* do */ - if (!board->have_dio) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 1; - s->insn_bits = pcl726_do_insn_bits; - s->range_table = &range_digital; + if (dev->irq) { + /* Digial Input subdevice - Interrupt support */ + s = &dev->subdevices[subdev++]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl726_intr_insn_bits; + s->len_chanlist = 1; + s->do_cmdtest = pcl726_intr_cmdtest; + s->do_cmd = pcl726_intr_cmd; + s->cancel = pcl726_intr_cancel; } return 0; @@ -335,12 +444,12 @@ static struct comedi_driver pcl726_driver = { .module = THIS_MODULE, .attach = pcl726_attach, .detach = comedi_legacy_detach, - .board_name = &boardtypes[0].name, - .num_names = ARRAY_SIZE(boardtypes), + .board_name = &pcl726_boards[0].name, + .num_names = ARRAY_SIZE(pcl726_boards), .offset = sizeof(struct pcl726_board), }; module_comedi_driver(pcl726_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Advantech PCL-726 & compatibles"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index 862e75fd68f..7fb044ce399 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -17,6 +17,8 @@ * (ICP) P16R16-DIO [p16r16dio] * (Advantech) PCL-733 [pcl733] * (Advantech) PCL-734 [pcl734] + * (Diamond Systems) OPMM-1616-XT [opmm-1616-xt] + * (Diamond Systems) PEARL-MM-P [prearl-mm-p] * Author: José Luis Sánchez (jsanchezv@teleline.es) * Status: untested * @@ -27,10 +29,9 @@ * The ACL-7130 card has an 8254 timer/counter not supported by this driver. */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - /* * Register map * @@ -71,6 +72,27 @@ * BASE+1 Isolated outputs 8-15 (write) or inputs 8-15 (read) * BASE+2 Isolated outputs 16-23 (write) or inputs 16-23 (read) * BASE+3 Isolated outputs 24-31 (write) or inputs 24-31 (read) + * + * The opmm-1616-xt board has this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) (read back) + * BASE+1 Isolated outputs 8-15 (write) (read back) + * BASE+2 Isolated inputs 0-7 (read) + * BASE+3 Isolated inputs 8-15 (read) + * + * These registers are not currently supported: + * + * BASE+2 Relay select register (write) + * BASE+3 Board reset control register (write) + * BASE+4 Interrupt control register (write) + * BASE+4 Change detect 7-0 status register (read) + * BASE+5 LED control register (write) + * BASE+5 Change detect 15-8 status register (read) + * + * The pearl-mm-p board has this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) + * BASE+1 Isolated outputs 8-15 (write) */ struct pcl730_board { @@ -159,6 +181,19 @@ static const struct pcl730_board pcl730_boards[] = { .io_range = 0x04, .n_subdevs = 1, .n_iso_out_chan = 32, + }, { + .name = "opmm-1616-xt", + .io_range = 0x10, + .is_acl7225b = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + }, { + .name = "pearl-mm-p", + .io_range = 0x02, + .n_subdevs = 1, + .n_iso_out_chan = 16, }, }; @@ -168,13 +203,10 @@ static int pcl730_do_insn_bits(struct comedi_device *dev, unsigned int *data) { unsigned long reg = (unsigned long)s->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; + unsigned int mask; + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - if (mask & 0x00ff) outb(s->state & 0xff, dev->iobase + reg); if ((mask & 0xff00) && (s->n_chan > 8)) diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index cd02786702c..4c1b9470647 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -108,12 +108,12 @@ * 3= 20V unipolar inputs */ +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/gfp.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> #include <linux/io.h> #include <asm/dma.h> @@ -131,405 +131,586 @@ #define boardACL8216 8 /* and ICP DAS A-826PG */ #define boardA821 9 /* PGH, PGL, PGL/NDA versions */ -#define PCLx1x_IORANGE 16 - -#define PCL812_CTR0 0 -#define PCL812_CTR1 1 -#define PCL812_CTR2 2 -#define PCL812_CTRCTL 3 -#define PCL812_AD_LO 4 -#define PCL812_DA1_LO 4 -#define PCL812_AD_HI 5 -#define PCL812_DA1_HI 5 -#define PCL812_DA2_LO 6 -#define PCL812_DI_LO 6 -#define PCL812_DA2_HI 7 -#define PCL812_DI_HI 7 -#define PCL812_CLRINT 8 -#define PCL812_GAIN 9 -#define PCL812_MUX 10 -#define PCL812_MODE 11 -#define PCL812_CNTENABLE 10 -#define PCL812_SOFTTRIG 12 -#define PCL812_DO_LO 13 -#define PCL812_DO_HI 14 - -#define PCL812_DRDY 0x10 /* =0 data ready */ - -#define ACL8216_STATUS 8 /* 5. bit signalize data ready */ - -#define ACL8216_DRDY 0x20 /* =0 data ready */ +/* + * Register I/O map + */ +#define PCL812_TIMER_BASE 0x00 +#define PCL812_AI_LSB_REG 0x04 +#define PCL812_AI_MSB_REG 0x05 +#define PCL812_AI_MSB_DRDY (1 << 4) +#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL812_DI_LSB_REG 0x06 +#define PCL812_DI_MSB_REG 0x07 +#define PCL812_STATUS_REG 0x08 +#define PCL812_STATUS_DRDY (1 << 5) +#define PCL812_RANGE_REG 0x09 +#define PCL812_MUX_REG 0x0a +#define PCL812_MUX_CHAN(x) ((x) << 0) +#define PCL812_MUX_CS0 (1 << 4) +#define PCL812_MUX_CS1 (1 << 5) +#define PCL812_CTRL_REG 0x0b +#define PCL812_CTRL_DISABLE_TRIG (0 << 0) +#define PCL812_CTRL_SOFT_TRIG (1 << 0) +#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0) +#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0) +#define PCL812_SOFTTRIG_REG 0x0c +#define PCL812_DO_LSB_REG 0x0d +#define PCL812_DO_MSB_REG 0x0e #define MAX_CHANLIST_LEN 256 /* length of scan list */ -static const struct comedi_lrange range_pcl812pg_ai = { 5, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125), - } +static const struct comedi_lrange range_pcl812pg_ai = { + 5, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_pcl812pg2_ai = { 5, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_pcl812pg2_ai = { + 5, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range812_bipolar1_25 = { 1, { - BIP_RANGE(1.25), - } +static const struct comedi_lrange range812_bipolar1_25 = { + 1, { + BIP_RANGE(1.25) + } }; -static const struct comedi_lrange range812_bipolar0_625 = { 1, { - BIP_RANGE - (0.625), - } +static const struct comedi_lrange range812_bipolar0_625 = { + 1, { + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range812_bipolar0_3125 = { 1, { - BIP_RANGE - (0.3125), - } +static const struct comedi_lrange range812_bipolar0_3125 = { + 1, { + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_pcl813b_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_pcl813b_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_pcl813b2_ai = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_pcl813b2_ai = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_iso813_1_ai = { 5, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125), - } +static const struct comedi_lrange range_iso813_1_ai = { + 5, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_iso813_1_2_ai = { 5, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - UNI_RANGE(0.625), - } +static const struct comedi_lrange range_iso813_1_2_ai = { + 5, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625) + } }; -static const struct comedi_lrange range_iso813_2_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_iso813_2_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_iso813_2_2_ai = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_iso813_2_2_ai = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_acl8113_1_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_acl8113_1_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_acl8113_1_2_ai = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_acl8113_1_2_ai = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_acl8113_2_ai = { 3, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - } +static const struct comedi_lrange range_acl8113_2_ai = { + 3, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } }; -static const struct comedi_lrange range_acl8113_2_2_ai = { 3, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - } +static const struct comedi_lrange range_acl8113_2_2_ai = { + 3, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5) + } }; -static const struct comedi_lrange range_acl8112dg_ai = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10), - } +static const struct comedi_lrange range_acl8112dg_ai = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; -static const struct comedi_lrange range_acl8112hg_ai = { 12, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - } +static const struct comedi_lrange range_acl8112hg_ai = { + 12, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_a821pgh_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - } +static const struct comedi_lrange range_a821pgh_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005) + } }; struct pcl812_board { + const char *name; + int board_type; + int n_aichan; + int n_aochan; + unsigned int ai_ns_min; + const struct comedi_lrange *rangelist_ai; + unsigned int IRQbits; + unsigned int has_dma:1; + unsigned int has_16bit_ai:1; + unsigned int has_mpc508_mux:1; + unsigned int has_dio:1; +}; - const char *name; /* board name */ - int board_type; /* type of this board */ - int n_aichan; /* num of AI chans in S.E. */ - int n_aichan_diff; /* DIFF num of chans */ - int n_aochan; /* num of DA chans */ - int n_dichan; /* DI and DO chans */ - int n_dochan; - int ai_maxdata; /* AI resolution */ - unsigned int ai_ns_min; /* max sample speed of card v ns */ - unsigned int i8254_osc_base; /* clock base */ - const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ - unsigned int IRQbits; /* allowed IRQ */ - unsigned char DMAbits; /* allowed DMA chans */ - unsigned char io_range; /* iorange for this board */ - unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ +static const struct pcl812_board boardtypes[] = { + { + .name = "pcl812", + .board_type = boardPCL812, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_bipolar10, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl812pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112dg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "acl8112hg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a821pgl", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a821pglnda", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + }, { + .name = "a821pgh", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_a821pgh_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a822pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a822pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl813", + .board_type = boardPCL813, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "pcl813b", + .board_type = boardPCL813B, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "acl8113", + .board_type = boardACL8113, + .n_aichan = 32, + .rangelist_ai = &range_acl8113_1_ai, + }, { + .name = "iso813", + .board_type = boardISO813, + .n_aichan = 32, + .rangelist_ai = &range_iso813_1_ai, + }, { + .name = "acl8216", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a826pg", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_dio = 1, + }, }; struct pcl812_private { - - unsigned char valid; /* =1 device is OK */ unsigned char dma; /* >0 use dma ( usedDMA channel) */ - unsigned char use_diff; /* =1 diff inputs */ - unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */ - unsigned char use_ext_trg; /* 1=board uses external trigger */ unsigned char range_correction; /* =1 we must add 1 to range number */ - unsigned char old_chan_reg; /* lastly used chan/gain pair */ - unsigned char old_gain_reg; + unsigned int last_ai_chanspec; unsigned char mode_reg_int; /* there is stored INT number for some card */ - unsigned char ai_neverending; /* =1 we do unlimited AI */ - unsigned char ai_eos; /* 1=EOS wake up */ - unsigned char ai_dma; /* =1 we use DMA */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - unsigned int ai_scans; /* len of scanlist */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ - unsigned int ai_is16b; /* =1 we have 16 bit card */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* PTR to DMA buf */ - unsigned int dmapages[2]; /* how many pages we have allocated */ unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ - unsigned int hwdmasize[2]; /* DMA buf size in bytes */ unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */ int next_dma_buf; /* which buffer is next to use */ unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ unsigned int ao_readback[2]; /* data for AO readback */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int use_diff:1; + unsigned int use_mpc508:1; + unsigned int use_ext_trg:1; + unsigned int ai_dma:1; + unsigned int ai_eos:1; }; -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait); -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -/* -============================================================================== -*/ -static int pcl812_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers) { struct pcl812_private *devpriv = dev->private; - int n; - int timeout, hi; - - /* select software trigger */ - outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - hi = inb(dev->iobase + PCL812_AD_HI); - if (!(hi & PCL812_DRDY)) - goto conv_finish; - udelay(1); - } - printk - ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", - dev->minor, dev->board_name, dev->iobase); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return -ETIME; - -conv_finish: - data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO); + unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); + + if (load_timers) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return n; } -/* -============================================================================== -*/ -static int acl8216_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - int n; - int timeout; - - /* select software trigger */ - outb(1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) - goto conv_finish; - udelay(1); + struct pcl812_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; + + /* we use EOS, so adapt DMA buffer to one scan */ + if (devpriv->ai_eos) { + devpriv->dmabytestomove[0] = cfc_bytes_per_scan(s); + devpriv->dmabytestomove[1] = cfc_bytes_per_scan(s); + devpriv->dma_runs_to_end = 1; + } else { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + if (s->async->prealloc_bufsz < devpriv->hwdmasize) { + devpriv->dmabytestomove[0] = + s->async->prealloc_bufsz; + devpriv->dmabytestomove[1] = + s->async->prealloc_bufsz; } - printk - ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", - dev->minor, dev->board_name, dev->iobase); - outb(0, dev->iobase + PCL812_MODE); - return -ETIME; - -conv_finish: - data[n] = - (inb(dev->iobase + - PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO); + if (cmd->stop_src == TRIG_NONE) { + devpriv->dma_runs_to_end = 1; + } else { + /* how many samples we must transfer? */ + bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + + /* how many DMA pages we must fill */ + devpriv->dma_runs_to_end = + bytes / devpriv->dmabytestomove[0]; + + /* on last dma transfer must be moved */ + devpriv->last_dma_run = + bytes % devpriv->dmabytestomove[0]; + if (devpriv->dma_runs_to_end == 0) + devpriv->dmabytestomove[0] = + devpriv->last_dma_run; + devpriv->dma_runs_to_end--; + } + } + if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->ai_eos = 0; } - outb(0, dev->iobase + PCL812_MODE); - return n; + if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) { + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + devpriv->ai_eos = 0; + } + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int i; + unsigned long dma_flags; - for (i = 0; i < insn->n; i++) { - outb((data[i] & 0xff), - dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO)); - outb((data[i] >> 8) & 0x0f, - dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI)); - devpriv->ao_readback[chan] = data[i]; + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + disable_dma(devpriv->dma); + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->ai_eos) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv->next_dma_buf]); + } else { + if (devpriv->dma_runs_to_end) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv-> + next_dma_buf]); + } else { + set_dma_count(devpriv->dma, devpriv->last_dma_run); + } + devpriv->dma_runs_to_end--; } - - return i; + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_set_chan_range(struct comedi_device *dev, + unsigned int chanspec, char wait) { struct pcl812_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int i; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int mux = 0; - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + if (chanspec == devpriv->last_ai_chanspec) + return; + + devpriv->last_ai_chanspec = chanspec; + + if (devpriv->use_mpc508) { + if (devpriv->use_diff) { + mux |= PCL812_MUX_CS0 | PCL812_MUX_CS1; + } else { + if (chan < 8) + mux |= PCL812_MUX_CS0; + else + mux |= PCL812_MUX_CS1; + } + } + + outb(mux | PCL812_MUX_CHAN(chan), dev->iobase + PCL812_MUX_REG); + outb(range + devpriv->range_correction, dev->iobase + PCL812_RANGE_REG); + + if (wait) + /* + * XXX this depends on selected range and can be very long for + * some high gain ranges! + */ + udelay(devpriv->max_812_ai_mode0_rangewait); +} - return i; +static void pcl812_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL812_STATUS_REG); } -/* -============================================================================== -*/ -static int pcl812_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_soft_trig(struct comedi_device *dev) { - data[1] = inb(dev->iobase + PCL812_DI_LO); - data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8; + /* writing any value triggers a software conversion */ + outb(255, dev->iobase + PCL812_SOFTTRIG_REG); +} - return insn->n; +static unsigned int pcl812_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL812_AI_LSB_REG); + + return val & s->maxdata; } -/* -============================================================================== -*/ -static int pcl812_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcl812_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); - outb((s->state >> 8), dev->iobase + PCL812_DO_HI); - } - data[1] = s->state; + unsigned int status; - return insn->n; + if (s->maxdata > 0x0fff) { + status = inb(dev->iobase + PCL812_STATUS_REG); + if ((status & PCL812_STATUS_DRDY) == 0) + return 0; + } else { + status = inb(dev->iobase + PCL812_AI_MSB_REG); + if ((status & PCL812_AI_MSB_DRDY) == 0) + return 0; + } + return -EBUSY; } -/* -============================================================================== -*/ static int pcl812_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -537,7 +718,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, struct pcl812_private *devpriv = dev->private; int err = 0; unsigned int flags; - int tmp, divisor1, divisor2; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -577,7 +758,6 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, MAX_CHANLIST_LEN); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) @@ -591,14 +771,12 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -607,71 +785,27 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl = 0; + unsigned int i; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (devpriv->use_ext_trg) { - if (cmd->convert_src != TRIG_EXT) - return -EINVAL; - } else { - if (cmd->convert_src != TRIG_TIMER) - return -EINVAL; - } - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; - if (cmd->chanlist_len > MAX_CHANLIST_LEN) - return -EINVAL; - - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl812_start_pacer(dev, false); - devpriv->ai_n_chan = cmd->chanlist_len; - memcpy(devpriv->ai_chanlist, cmd->chanlist, - sizeof(unsigned int) * cmd->scan_end_arg); - /* select first channel and range */ - setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); + pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1); if (devpriv->dma) { /* check if we can use DMA transfer */ devpriv->ai_dma = 1; - for (i = 1; i < devpriv->ai_n_chan; i++) - if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) { + for (i = 1; i < cmd->chanlist_len; i++) + if (cmd->chanlist[0] != cmd->chanlist[i]) { /* we cann't use DMA :-( */ devpriv->ai_dma = 0; break; } - } else - devpriv->ai_dma = 0; - - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; + devpriv->ai_dma = 0; } devpriv->ai_act_scan = 0; @@ -679,258 +813,137 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->cur_chan = 0; /* don't we want wake up every scan? */ - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { + if (cmd->flags & TRIG_WAKE_EOS) { devpriv->ai_eos = 1; /* DMA is useless for this situation */ - if (devpriv->ai_n_chan == 1) + if (cmd->chanlist_len == 1) devpriv->ai_dma = 0; } - if (devpriv->ai_dma) { - /* we use EOS, so adapt DMA buffer to one scan */ - if (devpriv->ai_eos) { - devpriv->dmabytestomove[0] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dmabytestomove[1] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dma_runs_to_end = 1; - } else { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - if (devpriv->ai_data_len < devpriv->hwdmasize[0]) - devpriv->dmabytestomove[0] = - devpriv->ai_data_len; - if (devpriv->ai_data_len < devpriv->hwdmasize[1]) - devpriv->dmabytestomove[1] = - devpriv->ai_data_len; - if (devpriv->ai_neverending) { - devpriv->dma_runs_to_end = 1; - } else { - /* how many samples we must transfer? */ - bytes = devpriv->ai_n_chan * - devpriv->ai_scans * sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = - bytes / devpriv->dmabytestomove[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = - bytes % devpriv->dmabytestomove[0]; - if (devpriv->dma_runs_to_end == 0) - devpriv->dmabytestomove[0] = - devpriv->last_dma_run; - devpriv->dma_runs_to_end--; - } - } - if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->ai_eos = 0; - } - if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) { - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - devpriv->ai_eos = 0; - } - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } + if (devpriv->ai_dma) + pcl812_ai_setup_dma(dev, s); switch (cmd->convert_src) { case TRIG_TIMER: - start_pacer(dev, 1, divisor1, divisor2); + pcl812_start_pacer(dev, true); break; } - if (devpriv->ai_dma) /* let's go! */ - outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); - else /* let's go! */ - outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); + if (devpriv->ai_dma) + ctrl |= PCL812_CTRL_PACER_DMA_TRIG; + else + ctrl |= PCL812_CTRL_PACER_EOC_TRIG; + outb(devpriv->mode_reg_int | ctrl, dev->iobase + PCL812_CTRL_REG); return 0; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) +static bool pcl812_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) { - char err = 1; - unsigned int mask, timeout; - struct comedi_device *dev = d; struct pcl812_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - unsigned int next_chan; + struct comedi_cmd *cmd = &s->async->cmd; - s->async->events = 0; + s->async->events |= COMEDI_CB_BLOCK; - timeout = 50; /* wait max 50us, it must finish under 33us */ - if (devpriv->ai_is16b) { - mask = 0xffff; - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } else { - mask = 0x0fff; - while (timeout--) { - if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { - err = 0; - break; - } - udelay(1); - } + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; + } + + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - if (err) { - printk - ("comedi%d: pcl812: (%s at 0x%lx) " - "A/D cmd IRQ without DRDY!\n", - dev->minor, dev->board_name, dev->iobase); - pcl812_ai_cancel(dev, s); + return true; +} + +static void pcl812_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int next_chan; + + if (pcl812_ai_eoc(dev, s, NULL, 0)) { + dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - comedi_buf_put(s->async, - ((inb(dev->iobase + PCL812_AD_HI) << 8) | - inb(dev->iobase + PCL812_AD_LO)) & mask); + comedi_buf_put(s, pcl812_ai_get_sample(dev, s)); /* Set up next channel. Added by abbotti 2010-01-20, but untested. */ next_chan = s->async->cur_chan + 1; - if (next_chan >= devpriv->ai_n_chan) + if (next_chan >= cmd->chanlist_len) next_chan = 0; - if (devpriv->ai_chanlist[s->async->cur_chan] != - devpriv->ai_chanlist[next_chan]) - setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0); - - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan]) + pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0); - s->async->cur_chan = next_chan; - if (next_chan == 0) { /* one scan done */ - devpriv->ai_act_scan++; - if (!(devpriv->ai_neverending)) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - } - - comedi_event(dev, s); - return IRQ_HANDLED; + pcl812_ai_next_chan(dev, s); } -/* -============================================================================== -*/ static void transfer_from_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, short *ptr, + struct comedi_subdevice *s, + unsigned short *ptr, unsigned int bufptr, unsigned int len) { - struct pcl812_private *devpriv = dev->private; unsigned int i; - s->async->events = 0; for (i = len; i; i--) { - /* get one sample */ - comedi_buf_put(s->async, ptr[bufptr++]); - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - break; - } - } - } + comedi_buf_put(s, ptr[bufptr++]); - comedi_event(dev, s); + if (!pcl812_ai_next_chan(dev, s)) + break; + } } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) +static void pcl812_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl812_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - unsigned long dma_flags; int len, bufptr; - short *ptr; + unsigned short *ptr; - ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf]; + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - devpriv->ai_poll_ptr; - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - disable_dma(devpriv->dma); - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->ai_eos) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv->next_dma_buf]); - } else { - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - devpriv->dma_runs_to_end--; - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + pcl812_ai_setup_next_dma(dev, s); bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); - - return IRQ_HANDLED; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812(int irq, void *d) +static irqreturn_t pcl812_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; struct pcl812_private *devpriv = dev->private; if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); + pcl812_ai_clear_eoc(dev); return IRQ_HANDLED; } + if (devpriv->ai_dma) - return interrupt_pcl812_ai_dma(irq, d); + pcl812_handle_dma(dev, s); else - return interrupt_pcl812_ai_int(irq, d); + pcl812_handle_eoc(dev, s); + + pcl812_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; @@ -975,222 +988,308 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== -*/ -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait) +static int pcl812_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; - unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */ - /* gain index */ - unsigned char gain_reg = CR_RANGE(rangechan) + - devpriv->range_correction; - if ((chan_reg == devpriv->old_chan_reg) - && (gain_reg == devpriv->old_gain_reg)) - return; /* we can return, no change */ + if (devpriv->ai_dma) + disable_dma(devpriv->dma); - devpriv->old_chan_reg = chan_reg; - devpriv->old_gain_reg = gain_reg; + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_start_pacer(dev, false); + pcl812_ai_clear_eoc(dev); + return 0; +} - if (devpriv->use_MPC) { - if (devpriv->use_diff) { - chan_reg = chan_reg | 0x30; /* DIFF inputs */ - } else { - if (chan_reg & 0x80) - /* SE inputs 8-15 */ - chan_reg = chan_reg | 0x20; - else - /* SE inputs 0-7 */ - chan_reg = chan_reg | 0x10; - } - } +static int pcl812_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl812_private *devpriv = dev->private; + int ret = 0; + int i; - outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */ - outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ + outb(devpriv->mode_reg_int | PCL812_CTRL_SOFT_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_set_chan_range(dev, insn->chanspec, 1); - if (wait) - /* - * XXX this depends on selected range and can be very long for - * some high gain ranges! - */ - udelay(devpriv->max_812_ai_mode0_rangewait); + for (i = 0; i < insn->n; i++) { + pcl812_ai_clear_eoc(dev); + pcl812_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl812_ai_get_sample(dev, s); + } + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + + return ret ? ret : insn->n; } -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static int pcl812_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - outb(0xb4, dev->iobase + PCL812_CTRCTL); - outb(0x74, dev->iobase + PCL812_CTRCTL); - udelay(1); + struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); + for (i = 0; i < insn->n; i++) { + outb((data[i] & 0xff), + dev->iobase + PCL812_AO_LSB_REG(chan)); + outb((data[i] >> 8) & 0x0f, + dev->iobase + PCL812_AO_MSB_REG(chan)); + devpriv->ao_readback[chan] = data[i]; } + + return insn->n; } -/* -============================================================================== -*/ -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int pcl812_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - if (devpriv->ai_dma) - disable_dma(devpriv->dma); - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - /* Stop A/D */ - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - return 0; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int pcl812_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL812_DI_LSB_REG) | + (inb(dev->iobase + PCL812_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl812_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL812_DO_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL812_DO_MSB_REG); + } + + data[1] = s->state; + + return insn->n; } -/* -============================================================================== -*/ static void pcl812_reset(struct comedi_device *dev) { const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv = dev->private; + unsigned int chan; + + /* disable analog input trigger */ + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + + /* stop pacer */ + if (board->IRQbits) + pcl812_start_pacer(dev, false); + + /* + * Invalidate last_ai_chanspec then set analog input to + * known channel/range. + */ + devpriv->last_ai_chanspec = CR_PACK(16, 0, 0); + pcl812_ai_set_chan_range(dev, CR_PACK(0, 0, 0), 0); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL812_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL812_AO_MSB_REG(chan)); + } - outb(0, dev->iobase + PCL812_MUX); - outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN); - devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */ - devpriv->old_gain_reg = -1; + /* set all digital outputs low */ + if (board->has_dio) { + outb(0, dev->iobase + PCL812_DO_MSB_REG); + outb(0, dev->iobase + PCL812_DO_LSB_REG); + } +} +static void pcl812_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl812_board *board = comedi_board(dev); + struct pcl812_private *devpriv = dev->private; + + /* default to the range table from the boardinfo */ + s->range_table = board->rangelist_ai; + + /* now check the user config option based on the boardtype */ switch (board->board_type) { case boardPCL812PG: + if (it->options[4] == 1) + s->range_table = &range_pcl812pg2_ai; + break; case boardPCL812: - case boardACL8112: - case boardACL8216: - outb(0, dev->iobase + PCL812_DA2_LO); - outb(0, dev->iobase + PCL812_DA2_HI); - case boardA821: - outb(0, dev->iobase + PCL812_DA1_LO); - outb(0, dev->iobase + PCL812_DA1_HI); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_DO_HI); - outb(0, dev->iobase + PCL812_DO_LO); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - outb(0, dev->iobase + PCL812_CLRINT); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range812_bipolar1_25; + break; + case 4: + s->range_table = &range812_bipolar0_625; + break; + case 5: + s->range_table = &range812_bipolar0_3125; + break; + default: + s->range_table = &range_bipolar10; + break; + } break; case boardPCL813B: - case boardPCL813: + if (it->options[1] == 1) + s->range_table = &range_pcl813b2_ai; + break; case boardISO813: + switch (it->options[1]) { + case 0: + s->range_table = &range_iso813_1_ai; + break; + case 1: + s->range_table = &range_iso813_1_2_ai; + break; + case 2: + s->range_table = &range_iso813_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_iso813_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_iso813_1_ai; + break; + } + break; case boardACL8113: - udelay(5); + switch (it->options[1]) { + case 0: + s->range_table = &range_acl8113_1_ai; + break; + case 1: + s->range_table = &range_acl8113_1_2_ai; + break; + case 2: + s->range_table = &range_acl8113_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_acl8113_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_acl8113_1_ai; + break; + } break; } - udelay(5); } static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv; - int ret, subdev; - unsigned int irq; - unsigned int dma; - unsigned long pages; struct comedi_subdevice *s; int n_subdevices; + int subdev; + int ret; + int i; - ret = comedi_request_region(dev, it->options[0], board->io_range); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - irq = 0; - if (board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & board->IRQbits) == 0) { - printk - (", IRQ %u is out of allowed range, " - "DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq(irq, interrupt_pcl812, 0, - dev->board_name, dev)) { - printk - (", unable to allocate IRQ %u, " - "DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(KERN_INFO ", irq=%u", irq); - } - } - } + if ((1 << it->options[1]) & board->IRQbits) { + ret = request_irq(it->options[1], pcl812_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - dev->irq = irq; - - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (((1 << dma) & board->DMAbits) == 0) { - printk(", DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { - printk(KERN_ERR ", unable to allocate DMA %u, FAIL!\n", - dma); - return -EBUSY; /* DMA isn't free */ - } - devpriv->dma = dma; - printk(KERN_INFO ", dma=%u", dma); - pages = 1; /* we want 8KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) { - printk(", unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages); - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - printk(KERN_ERR ", unable to allocate DMA buffer, FAIL!\n"); + dev_err(dev->class_dev, + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages); + devpriv->dma = it->options[2]; + + devpriv->dmapages = 1; /* we want 8KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } } -no_dma: - n_subdevices = 0; - if (board->n_aichan > 0) - n_subdevices++; + /* differential analog inputs? */ + switch (board->board_type) { + case boardA821: + if (it->options[2] == 1) + devpriv->use_diff = 1; + break; + case boardACL8112: + case boardACL8216: + if (it->options[4] == 1) + devpriv->use_diff = 1; + break; + } + + n_subdevices = 1; /* all boardtypes have analog inputs */ if (board->n_aochan > 0) n_subdevices++; - if (board->n_dichan > 0) - n_subdevices++; - if (board->n_dochan > 0) - n_subdevices++; + if (board->has_dio) + n_subdevices += 2; ret = comedi_alloc_subdevices(dev, n_subdevices); if (ret) @@ -1198,159 +1297,47 @@ no_dma: subdev = 0; - /* analog input */ - if (board->n_aichan > 0) { - s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - switch (board->board_type) { - case boardA821: - if (it->options[2] == 1) { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - case boardACL8112: - case boardACL8216: - if (it->options[4] == 1) { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - default: - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - break; - } - s->maxdata = board->ai_maxdata; - s->len_chanlist = MAX_CHANLIST_LEN; - s->range_table = board->rangelist_ai; - if (board->board_type == boardACL8216) - s->insn_read = acl8216_ai_insn_read; - else - s->insn_read = pcl812_ai_insn_read; - - devpriv->use_MPC = board->haveMPC508; - s->cancel = pcl812_ai_cancel; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = pcl812_ai_cmdtest; - s->do_cmd = pcl812_ai_cmd; - s->poll = pcl812_ai_poll; - } - switch (board->board_type) { - case boardPCL812PG: - if (it->options[4] == 1) - s->range_table = &range_pcl812pg2_ai; - break; - case boardPCL812: - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range812_bipolar1_25; - break; - case 4: - s->range_table = &range812_bipolar0_625; - break; - case 5: - s->range_table = &range812_bipolar0_3125; - break; - default: - s->range_table = &range_bipolar10; - break; - printk - (", incorrect range number %d, changing " - "to 0 (+/-10V)", it->options[4]); - break; - } - break; - break; - case boardPCL813B: - if (it->options[1] == 1) - s->range_table = &range_pcl813b2_ai; - break; - case boardISO813: - switch (it->options[1]) { - case 0: - s->range_table = &range_iso813_1_ai; - break; - case 1: - s->range_table = &range_iso813_1_2_ai; - break; - case 2: - s->range_table = &range_iso813_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_iso813_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_iso813_1_ai; - break; - printk - (", incorrect range number %d, " - "changing to 0 ", it->options[1]); - break; - } - break; - case boardACL8113: - switch (it->options[1]) { - case 0: - s->range_table = &range_acl8113_1_ai; - break; - case 1: - s->range_table = &range_acl8113_1_2_ai; - break; - case 2: - s->range_table = &range_acl8113_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_acl8113_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_acl8113_1_ai; - break; - printk - (", incorrect range number %d, " - "changing to 0 ", it->options[1]); - break; - } - break; - } - subdev++; + /* Analog Input subdevice */ + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (devpriv->use_diff) { + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan / 2; + } else { + s->subdev_flags |= SDF_GROUND; + s->n_chan = board->n_aichan; } + s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff; + + pcl812_set_ai_range_table(dev, s, it); + + s->insn_read = pcl812_ai_insn_read; + + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = MAX_CHANLIST_LEN; + s->do_cmdtest = pcl812_ai_cmdtest; + s->do_cmd = pcl812_ai_cmd; + s->poll = pcl812_ai_poll; + s->cancel = pcl812_ai_cancel; + } + + devpriv->use_mpc508 = board->has_mpc508_mux; + + subdev++; /* analog output */ if (board->n_aochan > 0) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = board->rangelist_ao; - s->insn_read = pcl812_ao_insn_read; - s->insn_write = pcl812_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &range_unipolar5; + s->insn_read = pcl812_ao_insn_read; + s->insn_write = pcl812_ao_insn_write; switch (board->board_type) { case boardA821: if (it->options[3] == 1) @@ -1369,35 +1356,30 @@ no_dma: subdev++; } - /* digital input */ - if (board->n_dichan > 0) { + if (board->has_dio) { + /* Digital Input subdevice */ s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->len_chanlist = board->n_dichan; - s->range_table = &range_digital; - s->insn_bits = pcl812_di_insn_bits; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_di_insn_bits; subdev++; - } - /* digital output */ - if (board->n_dochan > 0) { + /* Digital Output subdevice */ s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->len_chanlist = board->n_dochan; - s->range_table = &range_digital; - s->insn_bits = pcl812_do_insn_bits; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_do_insn_bits; subdev++; } switch (board->board_type) { case boardACL8216: - devpriv->ai_is16b = 1; case boardPCL812PG: case boardPCL812: case boardACL8112: @@ -1405,9 +1387,10 @@ no_dma: if (it->options[3] > 0) /* we use external trigger */ devpriv->use_ext_trg = 1; + break; case boardA821: devpriv->max_812_ai_mode0_rangewait = 1; - devpriv->mode_reg_int = (irq << 4) & 0xf0; + devpriv->mode_reg_int = (dev->irq << 4) & 0xf0; break; case boardPCL813B: case boardPCL813: @@ -1418,9 +1401,6 @@ no_dma: break; } - printk(KERN_INFO "\n"); - devpriv->valid = 1; - pcl812_reset(dev); return 0; @@ -1432,72 +1412,15 @@ static void pcl812_detach(struct comedi_device *dev) if (devpriv) { if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); if (devpriv->dma) free_dma(devpriv->dma); } comedi_legacy_detach(dev); } -static const struct pcl812_board boardtypes[] = { - {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_bipolar10, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 10000, 500, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_pcl813b_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, - 10000, 500, &range_pcl813b_ai, NULL, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_a821pgh_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_acl8113_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_iso813_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, -}; - static struct comedi_driver pcl812_driver = { .driver_name = "pcl812", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index 91bd2071f57..d9ca7fe16c9 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -32,9 +32,9 @@ Configuration Options: */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/gfp.h> #include <linux/delay.h> #include <linux/io.h> @@ -44,393 +44,331 @@ Configuration Options: #include "comedi_fc.h" #include "8253.h" -#define DEBUG(x) x - -/* boards constants */ -/* IO space len */ -#define PCLx1x_RANGE 16 - -/* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */ - -/* INTEL 8254 counters */ -#define PCL816_CTR0 4 -#define PCL816_CTR1 5 -#define PCL816_CTR2 6 -/* R: counter read-back register W: counter control */ -#define PCL816_CTRCTL 7 - -/* R: A/D high byte W: A/D range control */ -#define PCL816_RANGE 9 -/* W: clear INT request */ -#define PCL816_CLRINT 10 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL816_MUX 11 -/* R/W: operation control register */ -#define PCL816_CONTROL 12 - -/* R: return status byte W: set DMA/IRQ */ -#define PCL816_STATUS 13 -#define PCL816_STATUS_DRDY_MASK 0x80 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL816_AD_LO 8 -/* R: high byte of A/D W: A/D range control */ -#define PCL816_AD_HI 9 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 +/* + * Register I/O map + */ +#define PCL816_DO_DI_LSB_REG 0x00 +#define PCL816_DO_DI_MSB_REG 0x01 +#define PCL816_TIMER_BASE 0x04 +#define PCL816_AI_LSB_REG 0x08 +#define PCL816_AI_MSB_REG 0x09 +#define PCL816_RANGE_REG 0x09 +#define PCL816_CLRINT_REG 0x0a +#define PCL816_MUX_REG 0x0b +#define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL816_CTRL_REG 0x0c +#define PCL816_CTRL_DISABLE_TRIG (0 << 0) +#define PCL816_CTRL_SOFT_TRIG (1 << 0) +#define PCL816_CTRL_PACER_TRIG (1 << 1) +#define PCL816_CTRL_EXT_TRIG (1 << 2) +#define PCL816_CTRL_POE (1 << 3) +#define PCL816_CTRL_DMAEN (1 << 4) +#define PCL816_CTRL_INTEN (1 << 5) +#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6) +#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6) +#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6) +#define PCL816_STATUS_REG 0x0d +#define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL816_STATUS_INTSRC_MASK (3 << 4) +#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4) +#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4) +#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4) +#define PCL816_STATUS_INTSRC_DMA (3 << 4) +#define PCL816_STATUS_INTACT (1 << 6) +#define PCL816_STATUS_DRDY (1 << 7) #define MAGIC_DMA_WORD 0x5a5a -static const struct comedi_lrange range_pcl816 = { 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_pcl816 = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; struct pcl816_board { + const char *name; + int ai_maxdata; + int ao_maxdata; + int ai_chanlist; +}; - const char *name; /* board name */ - int n_ranges; /* len of range list */ - int n_aichan; /* num of A/D chans in diferencial mode */ - unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - int ai_chanlist; /* allowed len of channel list A/D */ - int ao_chanlist; /* allowed len of channel list D/A */ - int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ +static const struct pcl816_board boardtypes[] = { + { + .name = "pcl816", + .ai_maxdata = 0xffff, + .ao_maxdata = 0xffff, + .ai_chanlist = 1024, + }, { + .name = "pcl814b", + .ai_maxdata = 0x3fff, + .ao_maxdata = 0x3fff, + .ai_chanlist = 1024, + }, }; struct pcl816_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ - unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - - unsigned int ai_scans; /* len of scanlist */ - unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */ - int irq_free; /* 1=have allocated IRQ */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */ - int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */ - unsigned int ai_act_chanlist_len; /* how long is actual MUX list */ - unsigned int ai_act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_n_chan; /* how many channels per scan */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -/* -============================================================================== -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int chanlen); -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int seglen); -static int pcl816_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); - -static int pcl816_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -/* -============================================================================== - ANALOG INPUT MODE0, 816 cards, slow version -*/ -static int pcl816_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; - - DPRINTK("mode 0 analog input\n"); - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL816_CONTROL); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Set the input channel */ - outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); - - for (n = 0; n < insn->n; n++) { - - outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */ - - timeout = 100; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) { - /* return read value */ - data[n] = - ((inb(dev->iobase + - PCL816_AD_HI) << 8) | - (inb(dev->iobase + PCL816_AD_LO))); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - break; - } - udelay(1); - } - /* Return timeout error */ - if (!timeout) { - comedi_error(dev, "A/D insn timeout\n"); - data[0] = 0; - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - return -EIO; - } + struct pcl816_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 0, I8254_MODE1 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x00ff); + udelay(1); + + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - return n; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) +static void pcl816_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl816_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - int low, hi; - int timeout = 50; /* wait max 50us */ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) - break; - udelay(1); - } - if (!timeout) { /* timeout, bail error */ - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + /* how many */ + bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + + /* how many DMA pages we must fill */ + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; + + /* on last dma transfer must be moved */ + devpriv->last_dma_run = bytes % devpriv->hwdmasize; + devpriv->dma_runs_to_end--; + if (devpriv->dma_runs_to_end >= 0) + bytes = devpriv->hwdmasize; + } else + devpriv->dma_runs_to_end = -1; + + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, bytes); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); +} +static void pcl816_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long dma_flags; + + disable_dma(devpriv->dma); + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, + devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->dma_runs_to_end) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else + set_dma_count(devpriv->dma, devpriv->last_dma_run); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } - /* get the sample */ - low = inb(dev->iobase + PCL816_AD_LO); - hi = inb(dev->iobase + PCL816_AD_HI); + devpriv->dma_runs_to_end--; +} - comedi_buf_put(s->async, (hi << 8) | low); +static void pcl816_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) +{ + outb(chan, dev->iobase + PCL816_MUX_REG); + outb(range, dev->iobase + PCL816_RANGE_REG); +} - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ +static void pcl816_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL816_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL816_MUX_REG); +} - if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len) - devpriv->ai_act_chanlist_pos = 0; +static void pcl816_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) +{ + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + unsigned int i; - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + pcl816_ai_set_chan_range(dev, last_chan, range); } - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); - return IRQ_HANDLED; + udelay(1); + + pcl816_ai_set_chan_scan(dev, first_chan, last_chan); } -/* -============================================================================== - analog input dma mode 1 & 3, 816 cards -*/ -static void transfer_from_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, short *ptr, - unsigned int bufptr, unsigned int len) +static void pcl816_ai_clear_eoc(struct comedi_device *dev) { - struct pcl816_private *devpriv = dev->private; - int i; - - s->async->events = 0; + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL816_CLRINT_REG); +} - for (i = 0; i < len; i++) { +static void pcl816_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL816_AI_LSB_REG); +} - comedi_buf_put(s->async, ptr[bufptr++]); +static unsigned int pcl816_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; - if (++devpriv->ai_act_chanlist_pos >= - devpriv->ai_act_chanlist_len) { - devpriv->ai_act_chanlist_pos = 0; - } + val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL816_AI_LSB_REG); - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - } + return val & s->maxdata; +} - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_BLOCK; - break; - } - } +static int pcl816_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; - comedi_event(dev, s); + status = inb(dev->iobase + PCL816_STATUS_REG); + if ((status & PCL816_STATUS_DRDY) == 0) + return 0; + return -EBUSY; } -static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) +static bool pcl816_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl816_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - int len, bufptr, this_dma_buf; - unsigned long dma_flags; - short *ptr; + struct comedi_cmd *cmd = &s->async->cmd; - disable_dma(devpriv->dma); - this_dma_buf = devpriv->next_dma_buf; + s->async->events |= COMEDI_CB_BLOCK; - /* switch dma bufs */ - if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; + } - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); -/* clear_dma_ff (devpriv->dma); */ - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ + return true; +} - ptr = (short *)devpriv->dmabuf[this_dma_buf]; +static void transfer_from_dma_buf(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned short *ptr, + unsigned int bufptr, unsigned int len) +{ + int i; - len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr; - bufptr = devpriv->ai_poll_ptr; - devpriv->ai_poll_ptr = 0; + for (i = 0; i < len; i++) { + comedi_buf_put(s, ptr[bufptr++]); - transfer_from_dma_buf(dev, s, ptr, bufptr, len); - return IRQ_HANDLED; + if (!pcl816_ai_next_chan(dev, s)) + return; + } } -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl816(int irq, void *d) +static irqreturn_t pcl816_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; struct pcl816_private *devpriv = dev->private; + unsigned short *ptr; + unsigned int bufptr; + unsigned int len; - DPRINTK("<I>"); - - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl816_ai_clear_eoc(dev); return IRQ_HANDLED; } - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl816_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl816_ai_mode13_int(irq, d); + if (devpriv->ai_cmd_canceled) { + devpriv->ai_cmd_canceled = 0; + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; } - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - if (!dev->irq || !devpriv->irq_free || !devpriv->irq_blocked || - !devpriv->int816_mode) { - if (devpriv->irq_was_now_closed) { - devpriv->irq_was_now_closed = 0; - /* comedi_error(dev,"last IRQ.."); */ - return IRQ_HANDLED; - } - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; -} + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; -/* -============================================================================== - COMMAND MODE -*/ -static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd) -{ - printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, - cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e, - cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e, - cmd->stop_src, cmd->scan_end_src); - printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", - e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); + pcl816_ai_setup_next_dma(dev, s); + + len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr; + bufptr = devpriv->ai_poll_ptr; + devpriv->ai_poll_ptr = 0; + + transfer_from_dma_buf(dev, s, ptr, bufptr, len); + + pcl816_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl816_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcl816_board *board = comedi_board(dev); + struct pcl816_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; - - DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n"); - pcl816_cmdtest_out(-1, cmd); - ); + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -460,8 +398,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); if (cmd->convert_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - board->ai_ns_min); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); else /* TRIG_EXT */ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); @@ -478,15 +415,12 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -506,131 +440,41 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl; unsigned int seglen; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; -/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */ - if (devpriv->irq_blocked) + if (devpriv->ai_cmd_running) return -EBUSY; - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - - i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - - /* PCL816 crash if any divisor is set to 1 */ - if (divisor1 == 1) { - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl816_start_pacer(dev, false); seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); if (seglen < 1) return -EINVAL; - setup_channel_list(dev, s, cmd->chanlist, seglen); + pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen); udelay(1); - devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->irq_blocked = 1; + devpriv->ai_cmd_running = 1; devpriv->ai_poll_ptr = 0; - devpriv->irq_was_now_closed = 0; + devpriv->ai_cmd_canceled = 0; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; - } - - /* don't we want wake up every scan? */ - if ((cmd->flags & TRIG_WAKE_EOS)) { - printk(KERN_INFO - "pl816: You wankt WAKE_EOS but I dont want handle it"); - /* devpriv->ai_eos=1; */ - /* if (devpriv->ai_n_chan==1) */ - /* devpriv->dma=0; // DMA is useless for this situation */ - } - - if (devpriv->dma) { - bytes = devpriv->hwdmasize[0]; - if (!devpriv->ai_neverending) { - /* how many */ - bytes = s->async->cmd.chanlist_len * - s->async->cmd.chanlist_len * - sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = bytes / - devpriv->hwdmasize[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } else - devpriv->dma_runs_to_end = -1; - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } - - start_pacer(dev, 1, divisor1, divisor2); - dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7); + pcl816_ai_setup_dma(dev, s); - switch (cmd->convert_src) { - case TRIG_TIMER: - devpriv->int816_mode = INT_TYPE_AI1_DMA; + pcl816_start_pacer(dev, true); - /* Pacer+IRQ+DMA */ - outb(0x32, dev->iobase + PCL816_CONTROL); - - /* write irq and DMA to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; - - default: - devpriv->int816_mode = INT_TYPE_AI3_DMA; - - /* Ext trig+IRQ+DMA */ - outb(0x34, dev->iobase + PCL816_CONTROL); + ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL816_CTRL_PACER_TRIG; + else /* TRIG_EXT */ + ctrl |= PCL816_CTRL_EXT_TRIG; - /* write irq to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; - } + outb(ctrl, dev->iobase + PCL816_CTRL_REG); + outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG); - DPRINTK("pcl816 END: pcl812_ai_cmd()\n"); return 0; } @@ -640,9 +484,6 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) unsigned long flags; unsigned int top1, top2, i; - if (!devpriv->dma) - return 0; /* poll is valid only for DMA transfer */ - spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < 20; i++) { @@ -657,7 +498,7 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) } /* where is now DMA in buffer */ - top1 = devpriv->hwdmasize[0] - top1; + top1 = devpriv->hwdmasize - top1; top1 >>= 1; /* sample position */ top2 = top1 - devpriv->ai_poll_ptr; if (top2 < 1) { /* no new samples */ @@ -666,144 +507,41 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) } transfer_from_dma_buf(dev, s, - (short *)devpriv->dmabuf[devpriv->next_dma_buf], + (unsigned short *)devpriv->dmabuf[devpriv-> + next_dma_buf], devpriv->ai_poll_ptr, top2); devpriv->ai_poll_ptr = top1; /* new buffer position */ spin_unlock_irqrestore(&dev->spinlock, flags); + cfc_handle_events(dev, s); + return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl816_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; -/* DEBUG(printk("pcl816_ai_cancel()\n");) */ - - if (devpriv->irq_blocked > 0) { - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, - dev->iobase + PCL816_CONTROL); /* Stop A/D */ - udelay(1); - outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ - - /* Stop pacer */ - outb(0xb0, dev->iobase + PCL816_CTRCTL); - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_HI); - - /* clear INT request */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Stop A/D */ - outb(0, dev->iobase + PCL816_CONTROL); - devpriv->irq_blocked = 0; - devpriv->irq_was_now_closed = devpriv->int816_mode; - devpriv->int816_mode = 0; - devpriv->last_int_sub = s; -/* s->busy = 0; */ - break; - } - } - - DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");) - return 0; -} - -/* -============================================================================== - chech for PCL816 -*/ -static int pcl816_check(unsigned long iobase) -{ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - outb(0x18, iobase + PCL816_CONTROL); - udelay(1); - if (inb(iobase + PCL816_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ -} - -/* -============================================================================== - reset whole PCL-816 cards -*/ -static void pcl816_reset(struct comedi_device *dev) -{ -/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */ -/* outb (0, dev->iobase + PCL818_DA_HI); */ -/* udelay (1); */ -/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */ -/* outb (0, dev->iobase + PCL818_DO_LO); */ -/* udelay (1); */ - outb(0, dev->iobase + PCL816_CONTROL); - outb(0, dev->iobase + PCL816_MUX); - outb(0, dev->iobase + PCL816_CLRINT); - outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0x30, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_RANGE); -} + if (!devpriv->ai_cmd_running) + return 0; -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void -start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, - unsigned int divisor2) -{ - outb(0x32, dev->iobase + PCL816_CTRCTL); - outb(0xff, dev->iobase + PCL816_CTR0); - outb(0x00, dev->iobase + PCL816_CTR0); - udelay(1); + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - /* set counter 2 as mode 3 */ - outb(0xb4, dev->iobase + PCL816_CTRCTL); - /* set counter 1 as mode 3 */ - outb(0x74, dev->iobase + PCL816_CTRCTL); - udelay(1); + /* Stop pacer */ + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 1, I8254_MODE0 | I8254_BINARY); - if (mode == 1) { - DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1, - divisor2); - outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1); - } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 1; - /* clear pending interrupts (just in case) */ -/* outb(0, dev->iobase + PCL816_CLRINT); */ + return 0; } -/* -============================================================================== - Check if channel list from user is built correctly - If it's ok, then return non-zero length of repeated segment of channel list -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, @@ -822,11 +560,6 @@ check_channel_list(struct comedi_device *dev, /* first channel is every time ok */ chansegment[0] = chanlist[0]; for (i = 1, seglen = 1; i < chanlen; i++, seglen++) { - /* build part of chanlist */ - DEBUG(printk(KERN_INFO "%d. %d %d\n", i, - CR_CHAN(chanlist[i]), - CR_RANGE(chanlist[i]));) - /* we detect loop, this must by finish */ if (chanlist[0] == chanlist[i]) break; @@ -834,12 +567,10 @@ check_channel_list(struct comedi_device *dev, (CR_CHAN(chansegment[i - 1]) + 1) % chanlen; if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ - printk(KERN_WARNING - "comedi%d: pcl816: channel list must " - "be continuous! chanlist[%i]=%d but " - "must be %d or %d!\n", dev->minor, - i, CR_CHAN(chanlist[i]), nowmustbechan, - CR_CHAN(chanlist[0])); + dev_dbg(dev->class_dev, + "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, CR_CHAN(chanlist[i]), nowmustbechan, + CR_CHAN(chanlist[0])); return 0; } /* well, this is next correct channel in list */ @@ -848,22 +579,15 @@ check_channel_list(struct comedi_device *dev, /* check whole chanlist */ for (i = 0, segpos = 0; i < chanlen; i++) { - DEBUG(printk("%d %d=%d %d\n", - CR_CHAN(chansegment[i % seglen]), - CR_RANGE(chansegment[i % seglen]), - CR_CHAN(chanlist[i]), - CR_RANGE(chanlist[i]));) if (chanlist[i] != chansegment[i % seglen]) { - printk(KERN_WARNING - "comedi%d: pcl816: bad channel or range" - " number! chanlist[%i]=%d,%d,%d and not" - " %d,%d,%d!\n", dev->minor, i, - CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); + dev_dbg(dev->class_dev, + "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(chanlist[i % seglen]), + CR_RANGE(chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); return 0; /* chan/gain list is strange */ } } @@ -874,208 +598,182 @@ check_channel_list(struct comedi_device *dev, return seglen; /* we can serve this with MUX logic */ } -/* -============================================================================== - Program scan/gain logic with channel list. -*/ -static void -setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int *chanlist, - unsigned int seglen) +static int pcl816_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pcl816_private *devpriv = dev->private; - unsigned int i; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; + + outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG); - devpriv->ai_act_chanlist_len = seglen; - devpriv->ai_act_chanlist_pos = 0; + pcl816_ai_set_chan_range(dev, chan, range); + pcl816_ai_set_chan_scan(dev, chan, chan); - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); + for (i = 0; i < insn->n; i++) { + pcl816_ai_clear_eoc(dev); + pcl816_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl816_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl816_ai_get_sample(dev, s); } + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - udelay(1); - /* select channel interval to scan */ - outb(devpriv->ai_act_chanlist[0] | - (devpriv->ai_act_chanlist[seglen - 1] << 4), - dev->iobase + PCL816_MUX); + return ret ? ret : insn->n; +} + +static int pcl816_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl816_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG); + } + + data[1] = s->state; + + return insn->n; +} + +static void pcl816_reset(struct comedi_device *dev) +{ + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_set_chan_range(dev, 0, 0); + pcl816_ai_clear_eoc(dev); + + /* Stop pacer */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL816_DO_DI_LSB_REG); + outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); } static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv; - int ret; - unsigned int irq, dma; - unsigned long pages; - /* int i; */ struct comedi_subdevice *s; + int ret; + int i; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = comedi_request_region(dev, it->options[0], board->io_range); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - if (pcl816_check(dev->iobase)) { - printk(KERN_ERR ", I cann't detect board. FAIL!\n"); - return -EIO; - } - - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - /* grab our IRQ */ - irq = 0; - if (board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & board->IRQbits) == 0) { - printk - (", IRQ %u is out of allowed range, " - "DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq(irq, interrupt_pcl816, 0, - dev->board_name, dev)) { - printk - (", unable to allocate IRQ %u, " - "DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(KERN_INFO ", irq=%u", irq); - } - } - } + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl816_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - dev->irq = irq; - if (irq) /* 1=we have allocated irq */ - devpriv->irq_free = 1; - else - devpriv->irq_free = 0; - - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->int816_mode = 0; /* mode of irq */ - - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!devpriv->irq_free) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - - if (((1 << dma) & board->DMAbits) == 0) { - printk(", DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { - printk(KERN_ERR - ", unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ - } - - devpriv->dma = dma; - printk(KERN_INFO ", dma=%u", dma); - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - - if (!devpriv->dmabuf[0]) { - printk(", unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ - - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - printk(KERN_ERR - ", unable to allocate DMA buffer, " - "FAIL!\n"); + dev_err(dev->class_dev, + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; - } + devpriv->dma = it->options[2]; -no_dma: + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; -/* if (board->n_aochan > 0) - subdevs[1] = COMEDI_SUBD_AO; - if (board->n_dichan > 0) - subdevs[2] = COMEDI_SUBD_DI; - if (board->n_dochan > 0) - subdevs[3] = COMEDI_SUBD_DO; -*/ + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } + } - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (board->n_aichan > 0) { - s->type = COMEDI_SUBD_AI; - devpriv->sub_ai = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_CMD_READ | SDF_DIFF; + s->n_chan = 16; + s->maxdata = board->ai_maxdata; + s->range_table = &range_pcl816; + s->insn_read = pcl816_ai_insn_read; + if (devpriv->dma) { dev->read_subdev = s; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_DIFF; - /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */ - s->maxdata = board->ai_maxdata; - s->len_chanlist = board->ai_chanlist; - s->range_table = board->ai_range_type; - s->cancel = pcl816_ai_cancel; - s->do_cmdtest = pcl816_ai_cmdtest; - s->do_cmd = pcl816_ai_cmd; - s->poll = pcl816_ai_poll; - s->insn_read = pcl816_ai_insn_read; - } else { - s->type = COMEDI_SUBD_UNUSED; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = board->ai_chanlist; + s->do_cmdtest = pcl816_ai_cmdtest; + s->do_cmd = pcl816_ai_cmd; + s->poll = pcl816_ai_poll; + s->cancel = pcl816_ai_cancel; } + /* Analog OUtput subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_UNUSED; #if 0 -case COMEDI_SUBD_AO: + subdevs[1] = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; + s->n_chan = 1; s->maxdata = board->ao_maxdata; - s->len_chanlist = board->ao_chanlist; - s->range_table = board->ao_range_type; - break; - -case COMEDI_SUBD_DI: - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->len_chanlist = board->n_dichan; - s->range_table = &range_digital; - break; - -case COMEDI_SUBD_DO: - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->len_chanlist = board->n_dochan; - s->range_table = &range_digital; - break; + s->range_table = &range_pcl816; #endif - pcl816_reset(dev); + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_do_insn_bits; - printk("\n"); + pcl816_reset(dev); return 0; } @@ -1085,39 +783,18 @@ static void pcl816_detach(struct comedi_device *dev) struct pcl816_private *devpriv = dev->private; if (dev->private) { - pcl816_ai_cancel(dev, devpriv->sub_ai); + pcl816_ai_cancel(dev, dev->read_subdev); pcl816_reset(dev); if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl816_board boardtypes[] = { - {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, /* IRQ mask */ - 0x0a, /* DMA mask */ - 0xffff, /* 16-bit card */ - 0xffff, /* D/A maxdata */ - 1024, - 1, /* ao chan list */ - 100}, - {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, - 0x0a, - 0x3fff, /* 14 bit card */ - 0x3fff, - 1024, - 1, - 100}, -}; - static struct comedi_driver pcl816_driver = { .driver_name = "pcl816", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index 91cb1bd6717..7d00ae639d3 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -98,7 +98,7 @@ A word or two about DMA. Driver support DMA operations at two ways: */ -#include <linux/ioport.h> +#include <linux/module.h> #include <linux/gfp.h> #include <linux/delay.h> #include <linux/io.h> @@ -110,8 +110,6 @@ A word or two about DMA. Driver support DMA operations at two ways: #include "comedi_fc.h" #include "8253.h" -/* #define PCL818_MODE13_AO 1 */ - /* boards constants */ #define boardPCL818L 0 @@ -121,46 +119,38 @@ A word or two about DMA. Driver support DMA operations at two ways: #define boardPCL818 4 #define boardPCL718 5 -/* IO space len */ -#define PCLx1x_RANGE 16 -/* IO space len if we use FIFO */ -#define PCLx1xFIFO_RANGE 32 - -/* W: clear INT request */ -#define PCL818_CLRINT 8 -/* R: return status byte */ -#define PCL818_STATUS 8 -/* R: A/D high byte W: A/D range control */ -#define PCL818_RANGE 1 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL818_MUX 2 -/* R/W: operation control register */ -#define PCL818_CONTROL 9 -/* W: counter enable */ -#define PCL818_CNTENABLE 10 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL818_AD_LO 0 -/* R: high byte of A/D W: A/D range control */ -#define PCL818_AD_HI 1 -/* W: D/A low&high byte */ -#define PCL818_DA_LO 4 -#define PCL818_DA_HI 5 -/* R: low&high byte of DI */ -#define PCL818_DI_LO 3 -#define PCL818_DI_HI 11 -/* W: low&high byte of DO */ -#define PCL818_DO_LO 3 -#define PCL818_DO_HI 11 -/* W: PCL718 second D/A */ -#define PCL718_DA2_LO 6 -#define PCL718_DA2_HI 7 -/* counters */ -#define PCL818_CTR0 12 -#define PCL818_CTR1 13 -#define PCL818_CTR2 14 -/* W: counter control */ -#define PCL818_CTRCTL 15 +/* + * Register I/O map + */ +#define PCL818_AI_LSB_REG 0x00 +#define PCL818_AI_MSB_REG 0x01 +#define PCL818_RANGE_REG 0x01 +#define PCL818_MUX_REG 0x02 +#define PCL818_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL818_DO_DI_LSB_REG 0x03 +#define PCL818_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL818_STATUS_REG 0x08 +#define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL818_STATUS_INT (1 << 4) +#define PCL818_STATUS_MUX (1 << 5) +#define PCL818_STATUS_UNI (1 << 6) +#define PCL818_STATUS_EOC (1 << 7) +#define PCL818_CTRL_REG 0x09 +#define PCL818_CTRL_DISABLE_TRIG (0 << 0) +#define PCL818_CTRL_SOFT_TRIG (1 << 0) +#define PCL818_CTRL_EXT_TRIG (2 << 0) +#define PCL818_CTRL_PACER_TRIG (3 << 0) +#define PCL818_CTRL_DMAE (1 << 2) +#define PCL818_CTRL_IRQ(x) ((x) << 4) +#define PCL818_CTRL_INTE (1 << 7) +#define PCL818_CNTENABLE_REG 0x0a +#define PCL818_CNTENABLE_PACER_ENA (0 << 0) +#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0) +#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1) +#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1) +#define PCL818_DO_DI_MSB_REG 0x0b +#define PCL818_TIMER_BASE 0x0c /* W: fifo enable/disable */ #define PCL818_FI_ENABLE 6 @@ -172,720 +162,517 @@ A word or two about DMA. Driver support DMA operations at two ways: #define PCL818_FI_STATUS 25 /* R: one record from FIFO */ #define PCL818_FI_DATALO 23 -#define PCL818_FI_DATAHI 23 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI1_FIFO 3 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 -#define INT_TYPE_AI3_FIFO 6 -#ifdef PCL818_MODE13_AO -#define INT_TYPE_AO1_INT 7 -#define INT_TYPE_AO3_INT 8 -#endif +#define PCL818_FI_DATAHI 24 #define MAGIC_DMA_WORD 0x5a5a -static const struct comedi_lrange range_pcl818h_ai = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10), - } +static const struct comedi_lrange range_pcl818h_ai = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; -static const struct comedi_lrange range_pcl818hg_ai = { 10, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - } +static const struct comedi_lrange range_pcl818hg_ai = { + 10, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_pcl818l_l_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_pcl818l_l_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_pcl818l_h_ai = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - } +static const struct comedi_lrange range_pcl818l_h_ai = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } +}; + +static const struct comedi_lrange range718_bipolar1 = { + 1, { + BIP_RANGE(1) + } }; -static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} }; static const struct comedi_lrange range718_bipolar0_5 = { - 1, {BIP_RANGE(0.5),} }; -static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} }; -static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} }; + 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) + } +}; struct pcl818_board { + const char *name; + unsigned int ns_min; + int n_aochan; + const struct comedi_lrange *ai_range_type; + unsigned int has_dma:1; + unsigned int has_fifo:1; + unsigned int is_818:1; +}; - const char *name; /* driver name */ - int n_ranges; /* len of range list */ - int n_aichan_se; /* num of A/D chans in single ended mode */ - int n_aichan_diff; /* num of A/D chans in diferencial mode */ - unsigned int ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - unsigned char fifo; /* 1=board has FIFO */ - int is_818; +static const struct pcl818_board boardtypes[] = { + { + .name = "pcl818l", + .ns_min = 25000, + .n_aochan = 1, + .ai_range_type = &range_pcl818l_l_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818h", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818hd", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818hg", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818hg_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818", + .ns_min = 10000, + .n_aochan = 2, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl718", + .ns_min = 16000, + .n_aochan = 2, + .ai_range_type = &range_unipolar5, + .has_dma = 1, + }, { + .name = "pcm3718", + .ns_min = 10000, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, }; struct pcl818_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ - unsigned int io_range; + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */ unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */ int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ - int irq_free; /* 1=have allocated IRQ */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */ - int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ int ai_act_chan; /* actual position in actual scan */ unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ unsigned int act_chanlist_len; /* how long is actual MUX list */ unsigned int act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; - struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ - unsigned char usefifo; /* 1=use fifo */ unsigned int ao_readback[2]; + unsigned int divisor1; + unsigned int divisor2; + unsigned int usefifo:1; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */ - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff -}; - -/* -============================================================================== -*/ -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen); -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); - -static int pcl818_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); - -/* -============================================================================== - ANALOG INPUT MODE0, 818 cards, slow version -*/ -static int pcl818_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; + struct pcl818_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL818_CONTROL); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); - /* select channel */ - outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX); + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + } +} - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE); +static void pcl818_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int flags; + unsigned int bytes; - for (n = 0; n < insn->n; n++) { + disable_dma(devpriv->dma); /* disable dma */ + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; + devpriv->last_dma_run = bytes % devpriv->hwdmasize; + devpriv->dma_runs_to_end--; + if (devpriv->dma_runs_to_end >= 0) + bytes = devpriv->hwdmasize; + } - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, bytes); + release_dma_lock(flags); + enable_dma(devpriv->dma); +} - /* start conversion */ - outb(0, dev->iobase + PCL818_AD_LO); +static void pcl818_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long flags; - timeout = 100; - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - comedi_error(dev, "A/D insn timeout"); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); - return -EIO; - -conv_finish: - data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) | - (inb(dev->iobase + PCL818_AD_LO) >> 4)); + disable_dma(devpriv->dma); + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ + set_dma_mode(devpriv->dma, DMA_MODE_READ); + flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, + devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else + set_dma_count(devpriv->dma, devpriv->last_dma_run); + release_dma_lock(flags); + enable_dma(devpriv->dma); } - return n; + devpriv->dma_runs_to_end--; } -/* -============================================================================== - ANALOG OUTPUT MODE0, 818 cards - only one sample per call is supported -*/ -static int pcl818_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) { - struct pcl818_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + outb(chan, dev->iobase + PCL818_MUX_REG); + outb(range, dev->iobase + PCL818_RANGE_REG); +} - return n; +static void pcl818_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL818_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL818_MUX_REG); } -static int pcl818_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) { struct pcl818_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - devpriv->ao_readback[chan] = data[n]; - outb((data[n] & 0x000f) << 4, dev->iobase + - (chan ? PCL718_DA2_LO : PCL818_DA_LO)); - outb((data[n] & 0x0ff0) >> 4, dev->iobase + - (chan ? PCL718_DA2_HI : PCL818_DA_HI)); + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + int i; + + devpriv->act_chanlist_len = seglen; + devpriv->act_chanlist_pos = 0; + + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + devpriv->act_chanlist[i] = last_chan; + + pcl818_ai_set_chan_range(dev, last_chan, range); } - return n; -} + udelay(1); -/* -============================================================================== - DIGITAL INPUT MODE0, 818 cards + pcl818_ai_set_chan_scan(dev, first_chan, last_chan); +} - only one sample per call is supported -*/ -static int pcl818_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_clear_eoc(struct comedi_device *dev) { - data[1] = inb(dev->iobase + PCL818_DI_LO) | - (inb(dev->iobase + PCL818_DI_HI) << 8); + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL818_STATUS_REG); +} - return insn->n; +static void pcl818_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL818_AI_LSB_REG); } -/* -============================================================================== - DIGITAL OUTPUT MODE0, 818 cards +static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) +{ + unsigned int val; - only one sample per call is supported -*/ -static int pcl818_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + val = inb(dev->iobase + PCL818_FI_DATALO); + val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8); + + if (chan) + *chan = val & 0xf; + + return (val >> 4) & s->maxdata; +} + +static unsigned int pcl818_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + unsigned int val; - outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); - outb((s->state >> 8), dev->iobase + PCL818_DO_HI); + val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL818_AI_LSB_REG); - data[1] = s->state; + if (chan) + *chan = val & 0xf; - return insn->n; + return (val >> 4) & s->maxdata; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) +static int pcl818_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - int low; - int timeout = 50; /* wait max 50us */ - - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + unsigned int status; -conv_finish: - low = inb(dev->iobase + PCL818_AD_LO); - comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */ - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - printk - ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n", - (low & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); + status = inb(dev->iobase + PCL818_STATUS_REG); + if (status & PCL818_STATUS_INT) + return 0; + return -EBUSY; +} + +static bool pcl818_ai_dropout(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int expected_chan; + + expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos]; + if (chan != expected_chan) { + dev_dbg(dev->class_dev, + "A/D mode1/3 %s - channel dropout %d!=%d !\n", + (devpriv->dma) ? "DMA" : + (devpriv->usefifo) ? "FIFO" : "IRQ", + chan, expected_chan); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return true; } + return false; +} + +static bool pcl818_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; + devpriv->act_chanlist_pos++; if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) devpriv->act_chanlist_pos = 0; s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - /* printk("E"); */ + if (s->async->cur_chan >= cmd->chanlist_len) { s->async->cur_chan = 0; devpriv->ai_act_scan--; + s->async->events |= COMEDI_CB_EOS; } - if (!devpriv->neverending_ai) { - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - comedi_event(dev, s); - return IRQ_HANDLED; + + return true; } -/* -============================================================================== - analog input dma mode 1 & 3, 818 cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) +static void pcl818_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int chan; + unsigned int val; + + if (pcl818_ai_eoc(dev, s, NULL, 0)) { + comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; + } + + val = pcl818_ai_get_sample(dev, s, &chan); + + if (pcl818_ai_dropout(dev, s, chan)) + return; + + comedi_buf_put(s, val); + + pcl818_ai_next_chan(dev, s); +} + +static void pcl818_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + unsigned short *ptr; + unsigned int chan; + unsigned int val; int i, len, bufptr; - unsigned long flags; - short *ptr; - disable_dma(devpriv->dma); - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */ - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end || devpriv->neverending_ai) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(flags); - enable_dma(devpriv->dma); - } - printk("comedi: A/D mode1/3 IRQ \n"); + pcl818_ai_setup_next_dma(dev, s); - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; + ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; - len = devpriv->hwdmasize[0] >> 1; + len = devpriv->hwdmasize >> 1; bufptr = 0; for (i = 0; i < len; i++) { - if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - printk - ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n", - (ptr[bufptr] & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos], - devpriv->act_chanlist_pos); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } + val = ptr[bufptr++]; + chan = val & 0xf; + val = (val >> 4) & s->maxdata; - comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ - - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; + if (pcl818_ai_dropout(dev, s, chan)) + break; - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } + comedi_buf_put(s, val); - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - /* printk("done int ai13 dma\n"); */ - return IRQ_HANDLED; - } + if (!pcl818_ai_next_chan(dev, s)) + break; } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818HD/HG cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) +static void pcl818_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - int i, len, lo; - - outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ + unsigned int status; + unsigned int chan; + unsigned int val; + int i, len; - lo = inb(dev->iobase + PCL818_FI_STATUS); + status = inb(dev->iobase + PCL818_FI_STATUS); - if (lo & 4) { + if (status & 4) { comedi_error(dev, "A/D mode1/3 FIFO overflow!"); - pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - if (lo & 1) { + if (status & 1) { comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); - pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - if (lo & 2) + if (status & 2) len = 512; else len = 0; for (i = 0; i < len; i++) { - lo = inb(dev->iobase + PCL818_FI_DATALO); - if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - printk - ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n", - (lo & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - - comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ + val = pcl818_ai_get_fifo_sample(dev, s, &chan); - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; + if (pcl818_ai_dropout(dev, s, chan)) + break; - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } + comedi_buf_put(s, val); - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } + if (!pcl818_ai_next_chan(dev, s)) + break; } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; } -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl818(int irq, void *d) +static irqreturn_t pcl818_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl818_ai_clear_eoc(dev); return IRQ_HANDLED; } - /* printk("I\n"); */ - - if (devpriv->irq_blocked && devpriv->irq_was_now_closed) { - if ((devpriv->neverending_ai || (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) && - (devpriv->ai_mode == INT_TYPE_AI1_DMA || - devpriv->ai_mode == INT_TYPE_AI3_DMA)) { - /* The cleanup from ai_cancel() has been delayed - until now because the card doesn't seem to like - being reprogrammed while a DMA transfer is in - progress. - */ - struct comedi_subdevice *s = &dev->subdevices[0]; - devpriv->ai_act_scan = 0; - devpriv->neverending_ai = 0; - pcl818_ai_cancel(dev, s); - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ + if (devpriv->ai_cmd_canceled) { + /* + * The cleanup from ai_cancel() has been delayed + * until now because the card doesn't seem to like + * being reprogrammed while a DMA transfer is in + * progress. + */ + devpriv->ai_act_scan = 0; + s->cancel(dev, s); return IRQ_HANDLED; } - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl818_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl818_ai_mode13_int(irq, d); - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: - return interrupt_pcl818_ai_mode13_fifo(irq, d); -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: - return interrupt_pcl818_ao_mode13_int(irq, d); -#endif - default: - break; - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked) - || (!devpriv->ai_mode)) { - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; -} - -/* -============================================================================== - ANALOG INPUT MODE 1 or 3 DMA , 818 cards -*/ -static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl818_private *devpriv = dev->private; - unsigned int flags; - unsigned int bytes; - - printk("mode13dma_int, mode: %d\n", mode); - disable_dma(devpriv->dma); /* disable dma */ - bytes = devpriv->hwdmasize[0]; - if (!devpriv->neverending_ai) { - bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */ - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(flags); - enable_dma(devpriv->dma); - - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_DMA; - outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */ - } else { - devpriv->ai_mode = INT_TYPE_AI3_DMA; - outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */ - }; -} - -/* -============================================================================== - ANALOG INPUT MODE 1 or 3, 818 cards -*/ -static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl818_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - int divisor1 = 0, divisor2 = 0; - unsigned int seglen; - - dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode()\n"); - if (!dev->irq) { - comedi_error(dev, "IRQ not defined!"); - return -EINVAL; - } - - if (devpriv->irq_blocked) - return -EBUSY; - - start_pacer(dev, -1, 0, 0); /* stop pacer */ - - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); - - udelay(1); - - devpriv->ai_act_scan = devpriv->ai_scans; - devpriv->ai_act_chan = 0; - devpriv->irq_blocked = 1; - devpriv->irq_was_now_closed = 0; - devpriv->neverending_ai = 0; - devpriv->act_chanlist_pos = 0; - devpriv->dma_runs_to_end = 0; - - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; /* well, user want neverending */ - - if (mode == 1) { - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - TRIG_ROUND_NEAREST); - if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */ - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ - - switch (devpriv->dma) { - case 1: /* DMA */ - case 3: - pcl818_ai_mode13dma_int(mode, dev, s); - break; - case 0: - if (!devpriv->usefifo) { - /* IRQ */ - /* printk("IRQ\n"); */ - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_INT; - /* Pacer+IRQ */ - outb(0x83 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_INT; - /* Ext trig+IRQ */ - outb(0x82 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } - } else { - /* FIFO */ - /* enable FIFO */ - outb(1, dev->iobase + PCL818_FI_ENABLE); - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_FIFO; - /* Pacer */ - outb(0x03, dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_FIFO; - outb(0x02, dev->iobase + PCL818_CONTROL); - } - } - } - - start_pacer(dev, mode, divisor1, divisor2); - - dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode() end\n"); - return 0; -} + if (devpriv->dma) + pcl818_handle_dma(dev, s); + else if (devpriv->usefifo) + pcl818_handle_fifo(dev, s); + else + pcl818_handle_eoc(dev, s); -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - outb(0xb4, dev->iobase + PCL818_CTRCTL); - outb(0x74, dev->iobase + PCL818_CTRCTL); - udelay(1); + pcl818_ai_clear_eoc(dev); - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1); - } + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== - Check if channel list from user is builded correctly - If it's ok, then program scan/gain logic -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) @@ -904,10 +691,6 @@ static int check_channel_list(struct comedi_device *dev, chansegment[0] = chanlist[0]; /* build part of chanlist */ for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { - - /* printk("%d. %d * %d\n",i, - * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/ - /* we detect loop, this must by finish */ if (chanlist[0] == chanlist[i]) @@ -915,10 +698,10 @@ static int check_channel_list(struct comedi_device *dev, nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ - printk - ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", - dev->minor, i, CR_CHAN(chanlist[i]), - nowmustbechan, CR_CHAN(chanlist[0])); + dev_dbg(dev->class_dev, + "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, CR_CHAN(chanlist[i]), nowmustbechan, + CR_CHAN(chanlist[0])); return 0; } /* well, this is next correct channel in list */ @@ -927,72 +710,38 @@ static int check_channel_list(struct comedi_device *dev, /* check whole chanlist */ for (i = 0, segpos = 0; i < n_chan; i++) { - /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */ if (chanlist[i] != chansegment[i % seglen]) { - printk - ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", - dev->minor, i, CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); + dev_dbg(dev->class_dev, + "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(chanlist[i % seglen]), + CR_RANGE(chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); return 0; /* chan/gain list is strange */ } } } else { seglen = 1; } - printk("check_channel_list: seglen %d\n", seglen); return seglen; } -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) -{ - struct pcl818_private *devpriv = dev->private; - int i; - - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */ - outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */ - } - - udelay(1); - - /* select channel interval to scan */ - outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen - - 1] << 4), - dev->iobase + PCL818_MUX); -} - -/* -============================================================================== - Check if board is switched to SE (1) or DIFF(0) mode -*/ static int check_single_ended(unsigned int port) { - if (inb(port + PCL818_STATUS) & 0x20) + if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX) return 1; return 0; } -/* -============================================================================== -*/ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcl818_board *board = comedi_board(dev); struct pcl818_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -1039,14 +788,12 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < board->ns_min) - cmd->convert_arg = board->ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -1063,157 +810,272 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* -============================================================================== -*/ -static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int pcl818_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int retval; + unsigned int ctrl = 0; + unsigned int seglen; + + if (devpriv->ai_cmd_running) + return -EBUSY; + + pcl818_start_pacer(dev, false); + + seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); + if (seglen < 1) + return -EINVAL; + pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen); - dev_dbg(dev->class_dev, "pcl818_ai_cmd()\n"); - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; + devpriv->ai_act_scan = cmd->stop_arg; + devpriv->ai_act_chan = 0; + devpriv->ai_cmd_running = 1; + devpriv->ai_cmd_canceled = 0; + devpriv->act_chanlist_pos = 0; + devpriv->dma_runs_to_end = 0; - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans = cmd->stop_arg; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL818_CTRL_PACER_TRIG; else - devpriv->ai_scans = 0; - - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ - devpriv->ai_timer1 = cmd->convert_arg; - retval = pcl818_ai_cmd_mode(1, dev, s); - dev_dbg(dev->class_dev, "pcl818_ai_cmd() end\n"); - return retval; - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pcl818_ai_cmd_mode(3, dev, s); - } + ctrl |= PCL818_CTRL_EXT_TRIG; + + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + + if (devpriv->dma) { + pcl818_ai_setup_dma(dev, s); + + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) | + PCL818_CTRL_DMAE; + } else if (devpriv->usefifo) { + /* enable FIFO */ + outb(1, dev->iobase + PCL818_FI_ENABLE); + } else { + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq); } + outb(ctrl, dev->iobase + PCL818_CTRL_REG); - return -1; + if (cmd->convert_src == TRIG_TIMER) + pcl818_start_pacer(dev, true); + + return 0; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (devpriv->irq_blocked > 0) { - dev_dbg(dev->class_dev, "pcl818_ai_cancel()\n"); - devpriv->irq_was_now_closed = 1; - - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - if (devpriv->neverending_ai || - (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) { - /* wait for running dma transfer to end, do cleanup in interrupt */ - goto end; - } - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: -#endif - outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - udelay(1); - start_pacer(dev, -1, 0, 0); - outb(0, dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_HI); - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - if (devpriv->usefifo) { /* FIFO shutdown */ - outb(0, dev->iobase + PCL818_FI_INTCLR); - outb(0, dev->iobase + PCL818_FI_FLUSH); - outb(0, dev->iobase + PCL818_FI_ENABLE); + if (!devpriv->ai_cmd_running) + return 0; + + if (devpriv->dma) { + if (cmd->stop_src == TRIG_NONE || + (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) { + if (!devpriv->ai_cmd_canceled) { + /* + * Wait for running dma transfer to end, + * do cleanup in interrupt. + */ + devpriv->ai_cmd_canceled = 1; + return 0; } - devpriv->irq_blocked = 0; - devpriv->last_int_sub = s; - devpriv->neverending_ai = 0; - devpriv->ai_mode = 0; - devpriv->irq_was_now_closed = 0; - break; } + disable_dma(devpriv->dma); } -end: - dev_dbg(dev->class_dev, "pcl818_ai_cancel() end\n"); + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_start_pacer(dev, false); + pcl818_ai_clear_eoc(dev); + + if (devpriv->usefifo) { /* FIFO shutdown */ + outb(0, dev->iobase + PCL818_FI_INTCLR); + outb(0, dev->iobase + PCL818_FI_FLUSH); + outb(0, dev->iobase + PCL818_FI_ENABLE); + } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 0; + return 0; } -/* -============================================================================== - chech for PCL818 -*/ -static int pcl818_check(unsigned long iobase) +static int pcl818_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - outb(0x00, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL818_MUX); - udelay(1); - outb(0x18, iobase + PCL818_CONTROL); - udelay(1); - if (inb(iobase + PCL818_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; + + outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG); + + pcl818_ai_set_chan_range(dev, chan, range); + pcl818_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl818_ai_clear_eoc(dev); + pcl818_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl818_ai_get_sample(dev, s, NULL); + } + pcl818_ai_clear_eoc(dev); + + return ret ? ret : insn->n; +} + +static int pcl818_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) { + devpriv->ao_readback[chan] = data[i]; + outb((data[i] & 0x000f) << 4, + dev->iobase + PCL818_AO_LSB_REG(chan)); + outb((data[i] & 0x0ff0) >> 4, + dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + return insn->n; +} + +static int pcl818_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int pcl818_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl818_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG); + } + + data[1] = s->state; + + return insn->n; } -/* -============================================================================== - reset whole PCL-818 cards -*/ static void pcl818_reset(struct comedi_device *dev) { const struct pcl818_board *board = comedi_board(dev); - struct pcl818_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; + unsigned int chan; - if (devpriv->usefifo) { /* FIFO shutdown */ + /* flush and disable the FIFO */ + if (board->has_fifo) { outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); } - outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */ - outb(0, dev->iobase + PCL818_DA_HI); - udelay(1); - outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */ - outb(0, dev->iobase + PCL818_DO_LO); - udelay(1); - outb(0, dev->iobase + PCL818_CONTROL); - outb(0, dev->iobase + PCL818_CNTENABLE); - outb(0, dev->iobase + PCL818_MUX); - outb(0, dev->iobase + PCL818_CLRINT); - outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL818_CTRCTL); - outb(0x30, dev->iobase + PCL818_CTRCTL); + + /* disable analog input trigger */ + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_ai_clear_eoc(dev); + + pcl818_ai_set_chan_range(dev, 0, 0); + + /* stop pacer */ + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL818_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL818_DO_DI_MSB_REG); + outb(0, dev->iobase + PCL818_DO_DI_LSB_REG); +} + +static void pcl818_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl818_board *board = comedi_board(dev); + + /* default to the range table from the boardinfo */ + s->range_table = board->ai_range_type; + + /* now check the user config option based on the boardtype */ if (board->is_818) { - outb(0, dev->iobase + PCL818_RANGE); + if (it->options[4] == 1 || it->options[4] == 10) { + /* secondary range list jumper selectable */ + s->range_table = &range_pcl818l_h_ai; + } } else { - outb(0, dev->iobase + PCL718_DA2_LO); - outb(0, dev->iobase + PCL718_DA2_HI); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range718_bipolar1; + break; + case 4: + s->range_table = &range718_bipolar0_5; + break; + case 6: + s->range_table = &range_unipolar10; + break; + case 7: + s->range_table = &range_unipolar5; + break; + case 8: + s->range_table = &range718_unipolar2; + break; + case 9: + s->range_table = &range718_unipolar1; + break; + default: + s->range_table = &range_unknown; + break; + } } } @@ -1221,183 +1083,96 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl818_board *board = comedi_board(dev); struct pcl818_private *devpriv; - int ret; - unsigned int irq; - int dma; - unsigned long pages; struct comedi_subdevice *s; + int ret; + int i; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; - devpriv->io_range = board->io_range; - if ((board->fifo) && (it->options[2] == -1)) { - /* we've board with FIFO and we want to use FIFO */ - devpriv->io_range = PCLx1xFIFO_RANGE; - devpriv->usefifo = 1; - } - ret = comedi_request_region(dev, it->options[0], devpriv->io_range); + ret = comedi_request_region(dev, it->options[0], + board->has_fifo ? 0x20 : 0x10); if (ret) return ret; - if (pcl818_check(dev->iobase)) { - comedi_error(dev, "I can't detect board. FAIL!\n"); - return -EIO; + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl818_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - /* grab our IRQ */ - irq = 0; - if (board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & board->IRQbits) == 0) { - printk - (", IRQ %u is out of allowed range, DISABLING IT", - irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq(irq, interrupt_pcl818, 0, - dev->board_name, dev)) { - printk - (", unable to allocate IRQ %u, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(KERN_DEBUG "irq=%u", irq); - } - } + /* should we use the FIFO? */ + if (dev->irq && board->has_fifo && it->options[2] == -1) + devpriv->usefifo = 1; + + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); + if (ret) { + dev_err(dev->class_dev, + "unable to request DMA channel %d\n", + it->options[2]); + return -EBUSY; } - } + devpriv->dma = it->options[2]; - dev->irq = irq; - if (irq) - devpriv->irq_free = 1; /* 1=we have allocated irq */ - else - devpriv->irq_free = 0; - - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->ai_mode = 0; /* mode of irq */ - - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!devpriv->irq_free) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - if (((1 << dma) & board->DMAbits) == 0) { - printk(KERN_ERR "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); } - ret = request_dma(dma, dev->board_name); - if (ret) - return -EBUSY; /* DMA isn't free */ - devpriv->dma = dma; - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) - /* maybe experiment with try_to_free_pages() will help .... */ - return -EBUSY; /* no buffer :-( */ - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) - return -EBUSY; - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; } -no_dma: - ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (!board->n_aichan_se) { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (check_single_ended(dev->iobase)) { + s->n_chan = 16; + s->subdev_flags |= SDF_COMMON | SDF_GROUND; } else { - s->type = COMEDI_SUBD_AI; - devpriv->sub_ai = s; - s->subdev_flags = SDF_READABLE; - if (check_single_ended(dev->iobase)) { - s->n_chan = board->n_aichan_se; - s->subdev_flags |= SDF_COMMON | SDF_GROUND; - printk(", %dchans S.E. DAC", s->n_chan); - } else { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - printk(", %dchans DIFF DAC", s->n_chan); - } - s->maxdata = board->ai_maxdata; - s->len_chanlist = s->n_chan; - s->range_table = board->ai_range_type; - s->cancel = pcl818_ai_cancel; - s->insn_read = pcl818_ai_insn_read; - if (irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = ai_cmdtest; - s->do_cmd = ai_cmd; - } - if (board->is_818) { - if ((it->options[4] == 1) || (it->options[4] == 10)) - s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */ - } else { - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range718_bipolar1; - break; - case 4: - s->range_table = &range718_bipolar0_5; - break; - case 6: - s->range_table = &range_unipolar10; - break; - case 7: - s->range_table = &range_unipolar5; - break; - case 8: - s->range_table = &range718_unipolar2; - break; - case 9: - s->range_table = &range718_unipolar1; - break; - default: - s->range_table = &range_unknown; - break; - } - } + s->n_chan = 8; + s->subdev_flags |= SDF_DIFF; + } + s->maxdata = 0x0fff; + + pcl818_set_ai_range_table(dev, s, it); + + s->insn_read = pcl818_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = ai_cmdtest; + s->do_cmd = pcl818_ai_cmd; + s->cancel = pcl818_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (!board->n_aochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = board->ao_maxdata; - s->len_chanlist = board->n_aochan; - s->range_table = board->ao_range_type; - s->insn_read = pcl818_ao_insn_read; - s->insn_write = pcl818_ao_insn_write; + if (board->n_aochan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0x0fff; + s->range_table = &range_unipolar5; + s->insn_read = pcl818_ao_insn_read; + s->insn_write = pcl818_ao_insn_write; if (board->is_818) { if ((it->options[4] == 1) || (it->options[4] == 10)) s->range_table = &range_unipolar10; @@ -1409,39 +1184,33 @@ no_dma: if (it->options[5] == 2) s->range_table = &range_unknown; } - } - - s = &dev->subdevices[2]; - if (!board->n_dichan) { - s->type = COMEDI_SUBD_UNUSED; } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->len_chanlist = board->n_dichan; - s->range_table = &range_digital; - s->insn_bits = pcl818_di_insn_bits; + s->type = COMEDI_SUBD_UNUSED; } + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - if (!board->n_dochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->len_chanlist = board->n_dochan; - s->range_table = &range_digital; - s->insn_bits = pcl818_do_insn_bits; - } + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_do_insn_bits; /* select 1/10MHz oscilator */ if ((it->options[3] == 0) || (it->options[3] == 10)) - devpriv->i8253_osc_base = 100; + devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ; else - devpriv->i8253_osc_base = 1000; + devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ; /* max sampling speed */ devpriv->ns_min = board->ns_min; @@ -1453,8 +1222,6 @@ no_dma: pcl818_reset(dev); - printk("\n"); - return 0; } @@ -1463,43 +1230,18 @@ static void pcl818_detach(struct comedi_device *dev) struct pcl818_private *devpriv = dev->private; if (devpriv) { - pcl818_ai_cancel(dev, devpriv->sub_ai); + pcl818_ai_cancel(dev, dev->read_subdev); pcl818_reset(dev); if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl818_board boardtypes[] = { - {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 0}, - /* pcm3718 */ - {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, -}; - static struct comedi_driver pcl818_driver = { .driver_name = "pcl818", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index 5a9cd38e15f..53e73737a90 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -28,11 +28,9 @@ Copy/pasted/hacked from pcm724.c * struct comedi_insn */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/delay.h> - #include "8255.h" #define PCM3724_SIZE 16 @@ -72,14 +70,11 @@ static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) { unsigned long iobase = arg; unsigned char inbres; - /* printk("8255cb %d %d %d %lx\n", dir,port,data,arg); */ if (dir) { - /* printk("8255 cb outb(%x, %lx)\n", data, iobase+port); */ outb(data, iobase + port); return 0; } else { inbres = inb(iobase + port); - /* printk("8255 cb inb(%lx) = %x\n", iobase+port, inbres); */ return inbres; } } @@ -139,8 +134,6 @@ static void do_3724_config(struct comedi_device *dev, port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR; outb(buffer_config, dev->iobase + 8); /* update buffer register */ - /* printk("pcm3724 buffer_config (%lx) %d, %x\n", - dev->iobase + _8255_CR, chanspec, buffer_config); */ outb(config, port_8255_cfg); } @@ -179,46 +172,36 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s, if (priv->dio_2 & 0xff) gatecfg |= GATE_A1; - /* printk("gate control %x\n", gatecfg); */ outb(gatecfg, dev->iobase + 9); } /* overriding the 8255 insn config */ static int subdev_3724_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int mask; - unsigned int bits; - - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x0000ff) - bits = 0x0000ff; - else if (mask & 0x00ff00) - bits = 0x00ff00; - else if (mask & 0x0f0000) - bits = 0x0f0000; + int ret; + + if (chan < 8) + mask = 0x0000ff; + else if (chan < 16) + mask = 0x00ff00; + else if (chan < 20) + mask = 0x0f0000; else - bits = 0xf00000; - - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + mask = 0xf00000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; do_3724_config(dev, s, insn->chanspec); enable_chan(dev, s, insn->chanspec); - return 1; + + return insn->n; } static int pcm3724_attach(struct comedi_device *dev, @@ -228,10 +211,9 @@ static int pcm3724_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret, i; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = comedi_alloc_devpriv(dev, sizeof(*priv)); if (!priv) return -ENOMEM; - dev->private = priv; ret = comedi_request_region(dev, it->options[0], PCM3724_SIZE); if (ret) @@ -243,8 +225,10 @@ static int pcm3724_attach(struct comedi_device *dev, for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; - subdev_8255_init(dev, s, subdev_8255_cb, - (unsigned long)(dev->iobase + SIZE_8255 * i)); + ret = subdev_8255_init(dev, s, subdev_8255_cb, + dev->iobase + SIZE_8255 * i); + if (ret) + return ret; s->insn_config = subdev_3724_insn_config; } return 0; diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index d5c728dc619..87c61d9b11d 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -38,6 +38,7 @@ * 1 = two's complement (+-10V input range) */ +#include <linux/module.h> #include "../comedidev.h" #define PCMAD_STATUS 0 @@ -60,24 +61,17 @@ static const struct pcmad_board_struct pcmad_boards[] = { }, }; -#define TIMEOUT 100 - -static int pcmad_ai_wait_for_eoc(struct comedi_device *dev, - int timeout) +static int pcmad_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; - - for (i = 0; i < timeout; i++) { - if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) - return 0; - } - return -ETIME; -} + unsigned int status; -static bool pcmad_range_is_bipolar(struct comedi_subdevice *s, - unsigned int range) -{ - return s->range_table->range[range].min < 0; + status = inb(dev->iobase + PCMAD_STATUS); + if ((status & 0x3) == 0x3) + return 0; + return -EBUSY; } static int pcmad_ai_insn_read(struct comedi_device *dev, @@ -94,7 +88,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + PCMAD_CONVERT); - ret = pcmad_ai_wait_for_eoc(dev, TIMEOUT); + ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0); if (ret) return ret; @@ -105,7 +99,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev, if (s->maxdata == 0x0fff) val >>= 4; - if (pcmad_range_is_bipolar(s, range)) { + if (comedi_range_is_bipolar(s, range)) { /* munge the two's complement value */ val ^= ((s->maxdata + 1) >> 1); } diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 774a63dfe04..1c7a135c91d 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -48,6 +48,7 @@ * [1] - Do Simultaneous Xfer (see description) */ +#include <linux/module.h> #include "../comedidev.h" /* AI range is not configurable, it's set by jumpers on the board */ @@ -138,10 +139,9 @@ static int pcmda12_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->simultaneous_xfer_mode = it->options[1]; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 9f76b1f5998..fed7e77e030 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -1,77 +1,78 @@ /* - comedi/drivers/pcmmio.c - Driver for Winsystems PC-104 based multifunction IO board. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * pcmmio.c + * Driver for Winsystems PC-104 based multifunction IO board. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* -Driver: pcmmio -Description: A driver for the PCM-MIO multifunction board -Devices: [Winsystems] PCM-MIO (pcmmio) -Author: Calin Culianu <calin@ajvar.org> -Updated: Wed, May 16 2007 16:21:10 -0500 -Status: works - -A driver for the relatively new PCM-MIO multifunction board from -Winsystems. This board is a PC-104 based I/O board. It contains -four subdevices: - subdevice 0 - 16 channels of 16-bit AI - subdevice 1 - 8 channels of 16-bit AO - subdevice 2 - first 24 channels of the 48 channel of DIO - (with edge-triggered interrupt support) - subdevice 3 - last 24 channels of the 48 channel DIO - (no interrupt support for this bank of channels) - - Some notes: - - Synchronous reads and writes are the only things implemented for AI and AO, - even though the hardware itself can do streaming acquisition, etc. Anyone - want to add asynchronous I/O for AI/AO as a feature? Be my guest... - - Asynchronous I/O for the DIO subdevices *is* implemented, however! They are - basically edge-triggered interrupts for any configuration of the first - 24 DIO-lines. - - Also note that this interrupt support is untested. - - A few words about edge-detection IRQ support (commands on DIO): - - * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ - of the board to the comedi_config command. The board IRQ is not jumpered - but rather configured through software, so any IRQ from 1-15 is OK. - - * Due to the genericity of the comedi API, you need to create a special - comedi_command in order to use edge-triggered interrupts for DIO. - - * Use comedi_commands with TRIG_NOW. Your callback will be called each - time an edge is detected on the specified DIO line(s), and the data - values will be two sample_t's, which should be concatenated to form - one 32-bit unsigned int. This value is the mask of channels that had - edges detected from your channel list. Note that the bits positions - in the mask correspond to positions in your chanlist when you - specified the command and *not* channel id's! - - * To set the polarity of the edge-detection interrupts pass a nonzero value - for either CR_RANGE or CR_AREF for edge-up polarity, or a zero - value for both CR_RANGE and CR_AREF if you want edge-down polarity. - -Configuration Options: - [0] - I/O port base address - [1] - IRQ (optional -- for edge-detect interrupt support only, - leave out if you don't need this feature) -*/ + * Driver: pcmmio + * Description: A driver for the PCM-MIO multifunction board + * Devices: (Winsystems) PCM-MIO [pcmmio] + * Author: Calin Culianu <calin@ajvar.org> + * Updated: Wed, May 16 2007 16:21:10 -0500 + * Status: works + * + * A driver for the PCM-MIO multifunction board from Winsystems. This + * is a PC-104 based I/O board. It contains four subdevices: + * + * subdevice 0 - 16 channels of 16-bit AI + * subdevice 1 - 8 channels of 16-bit AO + * subdevice 2 - first 24 channels of the 48 channel of DIO + * (with edge-triggered interrupt support) + * subdevice 3 - last 24 channels of the 48 channel DIO + * (no interrupt support for this bank of channels) + * + * Some notes: + * + * Synchronous reads and writes are the only things implemented for analog + * input and output. The hardware itself can do streaming acquisition, etc. + * + * Asynchronous I/O for the DIO subdevices *is* implemented, however! They + * are basically edge-triggered interrupts for any configuration of the + * channels in subdevice 2. + * + * Also note that this interrupt support is untested. + * + * A few words about edge-detection IRQ support (commands on DIO): + * + * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ + * of the board to the comedi_config command. The board IRQ is not jumpered + * but rather configured through software, so any IRQ from 1-15 is OK. + * + * Due to the genericity of the comedi API, you need to create a special + * comedi_command in order to use edge-triggered interrupts for DIO. + * + * Use comedi_commands with TRIG_NOW. Your callback will be called each + * time an edge is detected on the specified DIO line(s), and the data + * values will be two sample_t's, which should be concatenated to form + * one 32-bit unsigned int. This value is the mask of channels that had + * edges detected from your channel list. Note that the bits positions + * in the mask correspond to positions in your chanlist when you + * specified the command and *not* channel id's! + * + * To set the polarity of the edge-detection interrupts pass a nonzero value + * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero + * value for both CR_RANGE and CR_AREF if you want edge-down polarity. + * + * Configuration Options: + * [0] - I/O port base address + * [1] - IRQ (optional -- for edge-detect interrupt support only, + * leave out if you don't need this feature) + */ +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -79,675 +80,403 @@ Configuration Options: #include "comedi_fc.h" -/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */ -#define CHANS_PER_PORT 8 -#define PORTS_PER_ASIC 6 -#define INTR_PORTS_PER_ASIC 3 -#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */ -#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT) -#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC) -#define INTR_CHANS_PER_ASIC 24 -#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) -#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT) -#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) -#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) -/* IO Memory sizes */ -#define ASIC_IOSIZE (0x0B) -#define PCMMIO48_IOSIZE ASIC_IOSIZE - -/* Some offsets - these are all in the 16byte IO memory offset from - the base address. Note that there is a paging scheme to swap out - offsets 0x8-0xA using the PAGELOCK register. See the table below. - - Register(s) Pages R/W? Description - -------------------------------------------------------------- - REG_PORTx All R/W Read/Write/Configure IO - REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int. - REG_PAGELOCK All WriteOnly Select a page - REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity - REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int. - REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints. +/* + * Register I/O map */ -#define REG_PORT0 0x0 -#define REG_PORT1 0x1 -#define REG_PORT2 0x2 -#define REG_PORT3 0x3 -#define REG_PORT4 0x4 -#define REG_PORT5 0x5 -#define REG_INT_PENDING 0x6 -#define REG_PAGELOCK 0x7 /* - * page selector register, upper 2 bits select - * a page and bits 0-5 are used to 'lock down' - * a particular port above to make it readonly. - */ -#define REG_POL0 0x8 -#define REG_POL1 0x9 -#define REG_POL2 0xA -#define REG_ENAB0 0x8 -#define REG_ENAB1 0x9 -#define REG_ENAB2 0xA -#define REG_INT_ID0 0x8 -#define REG_INT_ID1 0x9 -#define REG_INT_ID2 0xA - -#define NUM_PAGED_REGS 3 -#define NUM_PAGES 4 -#define FIRST_PAGED_REG 0x8 -#define REG_PAGE_BITOFFSET 6 -#define REG_LOCK_BITOFFSET 0 -#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1)) -#define REG_LOCK_MASK (~(REG_PAGE_MASK)) -#define PAGE_POL 1 -#define PAGE_ENAB 2 -#define PAGE_INT_ID 3 - -static const struct comedi_lrange ranges_ai = { - 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)} -}; +#define PCMMIO_AI_LSB_REG 0x00 +#define PCMMIO_AI_MSB_REG 0x01 +#define PCMMIO_AI_CMD_REG 0x02 +#define PCMMIO_AI_CMD_SE (1 << 7) +#define PCMMIO_AI_CMD_ODD_CHAN (1 << 6) +#define PCMMIO_AI_CMD_CHAN_SEL(x) (((x) & 0x3) << 4) +#define PCMMIO_AI_CMD_RANGE(x) (((x) & 0x3) << 2) +#define PCMMIO_RESOURCE_REG 0x02 +#define PCMMIO_RESOURCE_IRQ(x) (((x) & 0xf) << 0) +#define PCMMIO_AI_STATUS_REG 0x03 +#define PCMMIO_AI_STATUS_DATA_READY (1 << 7) +#define PCMMIO_AI_STATUS_DATA_DMA_PEND (1 << 6) +#define PCMMIO_AI_STATUS_CMD_DMA_PEND (1 << 5) +#define PCMMIO_AI_STATUS_IRQ_PEND (1 << 4) +#define PCMMIO_AI_STATUS_DATA_DRQ_ENA (1 << 2) +#define PCMMIO_AI_STATUS_REG_SEL (1 << 3) +#define PCMMIO_AI_STATUS_CMD_DRQ_ENA (1 << 1) +#define PCMMIO_AI_STATUS_IRQ_ENA (1 << 0) +#define PCMMIO_AI_RES_ENA_REG 0x03 +#define PCMMIO_AI_RES_ENA_CMD_REG_ACCESS (0 << 3) +#define PCMMIO_AI_RES_ENA_AI_RES_ACCESS (1 << 3) +#define PCMMIO_AI_RES_ENA_DIO_RES_ACCESS (1 << 4) +#define PCMMIO_AI_2ND_ADC_OFFSET 0x04 + +#define PCMMIO_AO_LSB_REG 0x08 +#define PCMMIO_AO_LSB_SPAN(x) (((x) & 0xf) << 0) +#define PCMMIO_AO_MSB_REG 0x09 +#define PCMMIO_AO_CMD_REG 0x0a +#define PCMMIO_AO_CMD_WR_SPAN (0x2 << 4) +#define PCMMIO_AO_CMD_WR_CODE (0x3 << 4) +#define PCMMIO_AO_CMD_UPDATE (0x4 << 4) +#define PCMMIO_AO_CMD_UPDATE_ALL (0x5 << 4) +#define PCMMIO_AO_CMD_WR_SPAN_UPDATE (0x6 << 4) +#define PCMMIO_AO_CMD_WR_CODE_UPDATE (0x7 << 4) +#define PCMMIO_AO_CMD_WR_SPAN_UPDATE_ALL (0x8 << 4) +#define PCMMIO_AO_CMD_WR_CODE_UPDATE_ALL (0x9 << 4) +#define PCMMIO_AO_CMD_RD_B1_SPAN (0xa << 4) +#define PCMMIO_AO_CMD_RD_B1_CODE (0xb << 4) +#define PCMMIO_AO_CMD_RD_B2_SPAN (0xc << 4) +#define PCMMIO_AO_CMD_RD_B2_CODE (0xd << 4) +#define PCMMIO_AO_CMD_NOP (0xf << 4) +#define PCMMIO_AO_CMD_CHAN_SEL(x) (((x) & 0x03) << 1) +#define PCMMIO_AO_CMD_CHAN_SEL_ALL (0x0f << 0) +#define PCMMIO_AO_STATUS_REG 0x0b +#define PCMMIO_AO_STATUS_DATA_READY (1 << 7) +#define PCMMIO_AO_STATUS_DATA_DMA_PEND (1 << 6) +#define PCMMIO_AO_STATUS_CMD_DMA_PEND (1 << 5) +#define PCMMIO_AO_STATUS_IRQ_PEND (1 << 4) +#define PCMMIO_AO_STATUS_DATA_DRQ_ENA (1 << 2) +#define PCMMIO_AO_STATUS_REG_SEL (1 << 3) +#define PCMMIO_AO_STATUS_CMD_DRQ_ENA (1 << 1) +#define PCMMIO_AO_STATUS_IRQ_ENA (1 << 0) +#define PCMMIO_AO_RESOURCE_ENA_REG 0x0b +#define PCMMIO_AO_2ND_DAC_OFFSET 0x04 -static const struct comedi_lrange ranges_ao = { - 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.), - RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)} +/* + * WinSystems WS16C48 + * + * Offset Page 0 Page 1 Page 2 Page 3 + * ------ ----------- ----------- ----------- ----------- + * 0x10 Port 0 I/O Port 0 I/O Port 0 I/O Port 0 I/O + * 0x11 Port 1 I/O Port 1 I/O Port 1 I/O Port 1 I/O + * 0x12 Port 2 I/O Port 2 I/O Port 2 I/O Port 2 I/O + * 0x13 Port 3 I/O Port 3 I/O Port 3 I/O Port 3 I/O + * 0x14 Port 4 I/O Port 4 I/O Port 4 I/O Port 4 I/O + * 0x15 Port 5 I/O Port 5 I/O Port 5 I/O Port 5 I/O + * 0x16 INT_PENDING INT_PENDING INT_PENDING INT_PENDING + * 0x17 Page/Lock Page/Lock Page/Lock Page/Lock + * 0x18 N/A POL_0 ENAB_0 INT_ID0 + * 0x19 N/A POL_1 ENAB_1 INT_ID1 + * 0x1a N/A POL_2 ENAB_2 INT_ID2 + */ +#define PCMMIO_PORT_REG(x) (0x10 + (x)) +#define PCMMIO_INT_PENDING_REG 0x16 +#define PCMMIO_PAGE_LOCK_REG 0x17 +#define PCMMIO_LOCK_PORT(x) ((1 << (x)) & 0x3f) +#define PCMMIO_PAGE(x) (((x) & 0x3) << 6) +#define PCMMIO_PAGE_MASK PCMUIO_PAGE(3) +#define PCMMIO_PAGE_POL 1 +#define PCMMIO_PAGE_ENAB 2 +#define PCMMIO_PAGE_INT_ID 3 +#define PCMMIO_PAGE_REG(x) (0x18 + (x)) + +static const struct comedi_lrange pcmmio_ai_ranges = { + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } }; -/* this structure is for data unique to this subdevice. */ -struct pcmmio_subdev_private { - - union { - /* for DIO: mapping of halfwords (bytes) - in port/chanarray to iobase */ - unsigned long iobases[PORTS_PER_SUBDEV]; - - /* for AI/AO */ - unsigned long iobase; - }; - union { - struct { - - /* The below is only used for intr subdevices */ - struct { - /* - * if non-negative, this subdev has an - * interrupt asic - */ - int asic; - /* - * if nonnegative, the first channel id for - * interrupts. - */ - int first_chan; - /* - * the number of asic channels in this subdev - * that have interrutps - */ - int num_asic_chans; - /* - * if nonnegative, the first channel id with - * respect to the asic that has interrupts - */ - int asic_chan; - /* - * subdev-relative channel mask for channels - * we are interested in - */ - int enabled_mask; - int active; - int stop_count; - int continuous; - spinlock_t spinlock; - } intr; - } dio; - struct { - /* the last unsigned int data written */ - unsigned int shadow_samples[8]; - } ao; - }; +static const struct comedi_lrange pcmmio_ao_ranges = { + 6, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10), + BIP_RANGE(2.5), + RANGE(-2.5, 7.5) + } }; -/* - * this structure is for data unique to this hardware driver. If - * several hardware drivers keep similar information in this structure, - * feel free to suggest moving the variable to the struct comedi_device struct. - */ struct pcmmio_private { - /* stuff for DIO */ - struct { - unsigned char pagelock; /* current page and lock */ - /* shadow of POLx registers */ - unsigned char pol[NUM_PAGED_REGS]; - /* shadow of ENABx registers */ - unsigned char enab[NUM_PAGED_REGS]; - int num; - unsigned long iobase; - unsigned int irq; - spinlock_t spinlock; - } asics[MAX_ASICS]; - struct pcmmio_subdev_private *sprivs; + spinlock_t pagelock; /* protects the page registers */ + spinlock_t spinlock; /* protects the member variables */ + unsigned int enabled_mask; + unsigned int stop_count; + unsigned int active:1; + + unsigned int ao_readback[8]; }; -#define subpriv ((struct pcmmio_subdev_private *)s->private) +static void pcmmio_dio_write(struct comedi_device *dev, unsigned int val, + int page, int port) +{ + struct pcmmio_private *devpriv = dev->private; + unsigned long iobase = dev->iobase; + unsigned long flags; -/* DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ + spin_lock_irqsave(&devpriv->pagelock, flags); + if (page == 0) { + /* Port registers are valid for any page */ + outb(val & 0xff, iobase + PCMMIO_PORT_REG(port + 0)); + outb((val >> 8) & 0xff, iobase + PCMMIO_PORT_REG(port + 1)); + outb((val >> 16) & 0xff, iobase + PCMMIO_PORT_REG(port + 2)); + } else { + outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG); + outb(val & 0xff, iobase + PCMMIO_PAGE_REG(0)); + outb((val >> 8) & 0xff, iobase + PCMMIO_PAGE_REG(1)); + outb((val >> 16) & 0xff, iobase + PCMMIO_PAGE_REG(2)); + } + spin_unlock_irqrestore(&devpriv->pagelock, flags); +} + +static unsigned int pcmmio_dio_read(struct comedi_device *dev, + int page, int port) +{ + struct pcmmio_private *devpriv = dev->private; + unsigned long iobase = dev->iobase; + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&devpriv->pagelock, flags); + if (page == 0) { + /* Port registers are valid for any page */ + val = inb(iobase + PCMMIO_PORT_REG(port + 0)); + val |= (inb(iobase + PCMMIO_PORT_REG(port + 1)) << 8); + val |= (inb(iobase + PCMMIO_PORT_REG(port + 2)) << 16); + } else { + outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG); + val = inb(iobase + PCMMIO_PAGE_REG(0)); + val |= (inb(iobase + PCMMIO_PAGE_REG(1)) << 8); + val |= (inb(iobase + PCMMIO_PAGE_REG(2)) << 16); + } + spin_unlock_irqrestore(&devpriv->pagelock, flags); + + return val; +} + +/* + * Each channel can be individually programmed for input or output. + * Writing a '0' to a channel causes the corresponding output pin + * to go to a high-z state (pulled high by an external 10K resistor). + * This allows it to be used as an input. When used in the input mode, + * a read reflects the inverted state of the I/O pin, such that a + * high on the pin will read as a '0' in the register. Writing a '1' + * to a bit position causes the pin to sink current (up to 12mA), + * effectively pulling it low. + */ static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int byte_no; - - /* NOTE: - reading a 0 means this channel was high - writine a 0 sets the channel high - reading a 1 means this channel was low - writing a 1 means set this channel low - - Therefore everything is always inverted. */ - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk(KERN_DEBUG "write mask: %08x data: %08x\n", data[0], data[1]); -#endif - - s->state = 0; - - for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { - /* address of 8-bit port */ - unsigned long ioaddr = subpriv->iobases[byte_no], - /* bit offset of port in 32-bit doubleword */ - offset = byte_no * 8; - /* this 8-bit port's data */ - unsigned char byte = 0, - /* The write mask for this port (if any) */ - write_mask_byte = (data[0] >> offset) & 0xff, - /* The data byte for this port */ - data_byte = (data[1] >> offset) & 0xff; - - byte = inb(ioaddr); /* read all 8-bits for this port */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk - (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x," - " data_in %02x ", byte_no, (unsigned)write_mask_byte, - (unsigned)data_byte, offset, ioaddr, (unsigned)byte); -#endif - - if (write_mask_byte) { - /* - * this byte has some write_bits - * -- so set the output lines - */ - /* clear bits for write mask */ - byte &= ~write_mask_byte; - /* set to inverted data_byte */ - byte |= ~data_byte & write_mask_byte; - /* Write out the new digital output state */ - outb(byte, ioaddr); - } -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte); -#endif - /* save the digital input lines for this byte.. */ - s->state |= ((unsigned int)byte) << offset; + /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */ + int port = s->index == 2 ? 0 : 3; + unsigned int chanmask = (1 << s->n_chan) - 1; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* + * Outputs are inverted, invert the state and + * update the channels. + * + * The s->io_bits mask makes sure the input channels + * are '0' so that the outputs pins stay in a high + * z-state. + */ + val = ~s->state & chanmask; + val &= s->io_bits; + pcmmio_dio_write(dev, val, 0, port); } - /* now return the DIO lines to data[1] - note they came inverted! */ - data[1] = ~s->state; + /* get inverted state of the channels from the port */ + val = pcmmio_dio_read(dev, 0, port); -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]); -#endif + /* return the true state of the channels */ + data[1] = ~val & chanmask; return insn->n; } -/* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = - chan % 8; - unsigned long ioaddr; - unsigned char byte; - - /* Compute ioaddr for this channel */ - ioaddr = subpriv->iobases[byte_no]; - - /* NOTE: - writing a 0 an IO channel's bit sets the channel to INPUT - and pulls the line high as well - - writing a 1 to an IO channel's bit pulls the line low - - All channels are implicitly always in OUTPUT mode -- but when - they are high they can be considered to be in INPUT mode.. - - Thus, we only force channels low if the config request was INPUT, - otherwise we do nothing to the hardware. */ - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - /* save to io_bits -- don't actually do anything since - all input channels are also output channels... */ - s->io_bits |= 1 << chan; - break; - case INSN_CONFIG_DIO_INPUT: - /* write a 0 to the actual register representing the channel - to set it to 'input'. 0 means "float high". */ - byte = inb(ioaddr); - byte &= ~(1 << bit_no); - /**< set input channel to '0' */ - - /* - * write out byte -- this is the only time we actually affect - * the hardware as all channels are implicitly output - * -- but input channels are set to float-high - */ - outb(byte, ioaddr); - - /* save to io_bits */ - s->io_bits &= ~(1 << chan); - break; + /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */ + int port = s->index == 2 ? 0 : 3; + int ret; - case INSN_CONFIG_DIO_QUERY: - /* retrieve from shadow register */ - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - default: - return -EINVAL; - break; - } + if (data[0] == INSN_CONFIG_DIO_INPUT) + pcmmio_dio_write(dev, s->io_bits, 0, port); return insn->n; } -static void switch_page(struct comedi_device *dev, int asic, int page) +static void pcmmio_reset(struct comedi_device *dev) { - struct pcmmio_private *devpriv = dev->private; - - if (asic < 0 || asic >= 1) - return; /* paranoia */ - if (page < 0 || page >= NUM_PAGES) - return; /* more paranoia */ - - devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; - devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; - - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - devpriv->asics[asic].iobase + REG_PAGELOCK); + /* Clear all the DIO port bits */ + pcmmio_dio_write(dev, 0, 0, 0); + pcmmio_dio_write(dev, 0, 0, 3); + + /* Clear all the paged registers */ + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_POL, 0); + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0); + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0); } -static void init_asics(struct comedi_device *dev) -{ /* sets up an - ASIC chip to defaults */ +/* devpriv->spinlock is already locked */ +static void pcmmio_stop_intr(struct comedi_device *dev, + struct comedi_subdevice *s) +{ struct pcmmio_private *devpriv = dev->private; - int asic; - - for (asic = 0; asic < 1; ++asic) { - int port, page; - unsigned long baseaddr = devpriv->asics[asic].iobase; - - switch_page(dev, asic, 0); /* switch back to page 0 */ - - /* first, clear all the DIO port bits */ - for (port = 0; port < PORTS_PER_ASIC; ++port) - outb(0, baseaddr + REG_PORT0 + port); - - /* Next, clear all the paged registers for each page */ - for (page = 1; page < NUM_PAGES; ++page) { - int reg; - /* now clear all the paged registers */ - switch_page(dev, asic, page); - for (reg = FIRST_PAGED_REG; - reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg) - outb(0, baseaddr + reg); - } - /* DEBUG set rising edge interrupts on port0 of both asics */ - /*switch_page(dev, asic, PAGE_POL); - outb(0xff, baseaddr + REG_POL0); - switch_page(dev, asic, PAGE_ENAB); - outb(0xff, baseaddr + REG_ENAB0); */ - /* END DEBUG */ + devpriv->enabled_mask = 0; + devpriv->active = 0; + s->async->inttrig = NULL; - /* switch back to default page 0 */ - switch_page(dev, asic, 0); - } + /* disable all dio interrupts */ + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0); } -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port) +static void pcmmio_handle_dio_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int triggered) { struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int oldevents = s->async->events; + unsigned int val = 0; + unsigned long flags; + int i; - if (asic < 0 || asic >= 1) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ + spin_lock_irqsave(&devpriv->spinlock, flags); - devpriv->asics[asic].pagelock |= 0x1 << port; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - devpriv->asics[asic].iobase + REG_PAGELOCK); - return; -} + if (!devpriv->active) + goto done; -static void unlock_port(struct comedi_device *dev, int asic, int port) -{ - struct pcmmio_private *devpriv = dev->private; + if (!(triggered & devpriv->enabled_mask)) + goto done; - if (asic < 0 || asic >= 1) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ - devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - devpriv->asics[asic].iobase + REG_PAGELOCK); -} -#endif /* notused */ + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); -static void pcmmio_stop_intr(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcmmio_private *devpriv = dev->private; - int nports, firstport, asic, port; + if (triggered & (1 << chan)) + val |= (1 << i); + } - asic = subpriv->dio.intr.asic; - if (asic < 0) - return; /* not an interrupt subdev */ + /* Write the scan to the buffer. */ + if (comedi_buf_put(s, val) && + comedi_buf_put(s, val >> 16)) { + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + } else { + /* Overflow! Stop acquisition!! */ + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmmio_stop_intr(dev, s); + } - subpriv->dio.intr.enabled_mask = 0; - subpriv->dio.intr.active = 0; - s->async->inttrig = NULL; - nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - /* disable all intrs for this subdev.. */ - outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); + /* Check for end of acquisition. */ + if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count > 0) { + devpriv->stop_count--; + if (devpriv->stop_count == 0) { + s->async->events |= COMEDI_CB_EOA; + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmmio_stop_intr(dev, s); + } } + +done: + spin_unlock_irqrestore(&devpriv->spinlock, flags); + + if (oldevents != s->async->events) + comedi_event(dev, s); } static irqreturn_t interrupt_pcmmio(int irq, void *d) { - int asic, got1 = 0; - struct comedi_device *dev = (struct comedi_device *)d; - struct pcmmio_private *devpriv = dev->private; - int i; + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int triggered; + unsigned char int_pend; - for (asic = 0; asic < MAX_ASICS; ++asic) { - if (irq == devpriv->asics[asic].irq) { - unsigned long flags; - unsigned triggered = 0; - unsigned long iobase = devpriv->asics[asic].iobase; - /* it is an interrupt for ASIC #asic */ - unsigned char int_pend; - - spin_lock_irqsave(&devpriv->asics[asic].spinlock, - flags); - - int_pend = inb(iobase + REG_INT_PENDING) & 0x07; - - if (int_pend) { - int port; - for (port = 0; port < INTR_PORTS_PER_ASIC; - ++port) { - if (int_pend & (0x1 << port)) { - unsigned char - io_lines_with_edges = 0; - switch_page(dev, asic, - PAGE_INT_ID); - io_lines_with_edges = - inb(iobase + - REG_INT_ID0 + port); - - if (io_lines_with_edges) - /* - * clear pending - * interrupt - */ - outb(0, iobase + - REG_INT_ID0 + - port); - - triggered |= - io_lines_with_edges << - port * 8; - } - } - - ++got1; - } - - spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, - flags); - - if (triggered) { - struct comedi_subdevice *s; - /* - * TODO here: dispatch io lines to subdevs - * with commands.. - */ - printk - (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n", - irq, asic, triggered); - for (i = 2; i < dev->n_subdevices; i++) { - s = &dev->subdevices[i]; - /* - * this is an interrupt subdev, - * and it matches this asic! - */ - if (subpriv->dio.intr.asic == asic) { - unsigned long flags; - unsigned oldevents; - - spin_lock_irqsave(&subpriv->dio. - intr.spinlock, - flags); - - oldevents = s->async->events; - - if (subpriv->dio.intr.active) { - unsigned mytrig = - ((triggered >> - subpriv->dio.intr.asic_chan) - & - ((0x1 << subpriv-> - dio.intr. - num_asic_chans) - - 1)) << subpriv-> - dio.intr.first_chan; - if (mytrig & - subpriv->dio. - intr.enabled_mask) { - unsigned int val - = 0; - unsigned int n, - ch, len; - - len = - s-> - async->cmd.chanlist_len; - for (n = 0; - n < len; - n++) { - ch = CR_CHAN(s->async->cmd.chanlist[n]); - if (mytrig & (1U << ch)) - val |= (1U << n); - } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *)&val)[0]) - && - comedi_buf_put - (s->async, - ((short *) - &val)[1])) { - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - } else { - /* Overflow! Stop acquisition!! */ - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmmio_stop_intr - (dev, - s); - } - - /* Check for end of acquisition. */ - if (!subpriv->dio.intr.continuous) { - /* stop_src == TRIG_COUNT */ - if (subpriv->dio.intr.stop_count > 0) { - subpriv->dio.intr.stop_count--; - if (subpriv->dio.intr.stop_count == 0) { - s->async->events |= COMEDI_CB_EOA; - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmmio_stop_intr - (dev, - s); - } - } - } - } - } - - spin_unlock_irqrestore - (&subpriv->dio.intr. - spinlock, flags); - - if (oldevents != - s->async->events) { - comedi_event(dev, s); - } - - } - - } - } + /* are there any interrupts pending */ + int_pend = inb(dev->iobase + PCMMIO_INT_PENDING_REG) & 0x07; + if (!int_pend) + return IRQ_NONE; + + /* get, and clear, the pending interrupts */ + triggered = pcmmio_dio_read(dev, PCMMIO_PAGE_INT_ID, 0); + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0); + + pcmmio_handle_dio_intr(dev, s, triggered); - } - } - if (!got1) - return IRQ_NONE; /* interrupt from other source */ return IRQ_HANDLED; } +/* devpriv->spinlock is already locked */ static int pcmmio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int bits = 0; + unsigned int pol_bits = 0; + int i; - if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; - subpriv->dio.intr.active = 0; + devpriv->active = 0; return 1; - } else { - unsigned bits = 0, pol_bits = 0, n; - int nports, firstport, asic, port; - struct comedi_cmd *cmd = &s->async->cmd; - - asic = subpriv->dio.intr.asic; - if (asic < 0) - return 1; /* not an interrupt - subdev */ - subpriv->dio.intr.enabled_mask = 0; - subpriv->dio.intr.active = 1; - nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; - if (cmd->chanlist) { - for (n = 0; n < cmd->chanlist_len; n++) { - bits |= (1U << CR_CHAN(cmd->chanlist[n])); - pol_bits |= (CR_AREF(cmd->chanlist[n]) - || CR_RANGE(cmd-> - chanlist[n]) ? 1U : 0U) - << CR_CHAN(cmd->chanlist[n]); - } - } - bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) - - 1) << subpriv->dio.intr.first_chan; - subpriv->dio.intr.enabled_mask = bits; - - { - /* - * the below code configures the board - * to use a specific IRQ from 0-15. - */ - unsigned char b; - /* - * set resource enable register - * to enable IRQ operation - */ - outb(1 << 4, dev->iobase + 3); - /* set bits 0-3 of b to the irq number from 0-15 */ - b = dev->irq & ((1 << 4) - 1); - outb(b, dev->iobase + 2); - /* done, we told the board what irq to use */ - } + } - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - unsigned enab = - bits >> (subpriv->dio.intr.first_chan + (port - - firstport) - * 8) & 0xff, pol = - pol_bits >> (subpriv->dio.intr.first_chan + - (port - firstport) * 8) & 0xff; - /* set enab intrs for this subdev.. */ - outb(enab, - devpriv->asics[asic].iobase + REG_ENAB0 + port); - switch_page(dev, asic, PAGE_POL); - outb(pol, - devpriv->asics[asic].iobase + REG_ENAB0 + port); + devpriv->enabled_mask = 0; + devpriv->active = 1; + if (cmd->chanlist) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + + bits |= (1 << chan); + pol_bits |= (((aref || range) ? 1 : 0) << chan); } } + bits &= ((1 << s->n_chan) - 1); + devpriv->enabled_mask = bits; + + /* set polarity and enable interrupts */ + pcmmio_dio_write(dev, pol_bits, PCMMIO_PAGE_POL, 0); + pcmmio_dio_write(dev, bits, PCMMIO_PAGE_ENAB, 0); + return 0; } static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmmio_private *devpriv = dev->private; unsigned long flags; - spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); - if (subpriv->dio.intr.active) + spin_lock_irqsave(&devpriv->spinlock, flags); + if (devpriv->active) pcmmio_stop_intr(dev, s); - spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + spin_unlock_irqrestore(&devpriv->spinlock, flags); return 0; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pcmmio_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { + struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; - spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); + spin_lock_irqsave(&devpriv->spinlock, flags); s->async->inttrig = NULL; - if (subpriv->dio.intr.active) + if (devpriv->active) event = pcmmio_start_intr(dev, s); - spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + spin_unlock_irqrestore(&devpriv->spinlock, flags); if (event) comedi_event(dev, s); @@ -760,37 +489,27 @@ pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, */ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmmio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); - subpriv->dio.intr.active = 1; + spin_lock_irqsave(&devpriv->spinlock, flags); + devpriv->active = 1; /* Set up end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - subpriv->dio.intr.continuous = 0; - subpriv->dio.intr.stop_count = cmd->stop_arg; - break; - default: - /* TRIG_NONE */ - subpriv->dio.intr.continuous = 1; - subpriv->dio.intr.stop_count = 0; - break; - } + if (cmd->stop_src == TRIG_COUNT) + devpriv->stop_count = cmd->stop_arg; + else /* TRIG_NONE */ + devpriv->stop_count = 0; /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmmio_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = pcmmio_start_intr(dev, s); - break; - } - spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + + spin_unlock_irqrestore(&devpriv->spinlock, flags); if (event) comedi_event(dev, s); @@ -853,367 +572,278 @@ static int pcmmio_cmdtest(struct comedi_device *dev, return 0; } -static int adc_wait_ready(unsigned long iobase) +static int pcmmio_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned long retry = 100000; - while (retry--) - if (inb(iobase + 3) & 0x80) - return 0; - return 1; + unsigned char status; + + status = inb(dev->iobase + PCMMIO_AI_STATUS_REG); + if (status & PCMMIO_AI_STATUS_DATA_READY) + return 0; + return -EBUSY; } -/* All this is for AI and AO */ -static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmmio_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - unsigned long iobase = subpriv->iobase; + unsigned long iobase = dev->iobase; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned char cmd = 0; + unsigned int val; + int ret; + int i; /* - 1. write the CMD byte (to BASE+2) - 2. read junk lo byte (BASE+0) - 3. read junk hi byte (BASE+1) - 4. (mux settled so) write CMD byte again (BASE+2) - 5. read valid lo byte(BASE+0) - 6. read valid hi byte(BASE+1) - - Additionally note that the BASE += 4 if the channel >= 8 + * The PCM-MIO uses two Linear Tech LTC1859CG 8-channel A/D converters. + * The devices use a full duplex serial interface which transmits and + * receives data simultaneously. An 8-bit command is shifted into the + * ADC interface to configure it for the next conversion. At the same + * time, the data from the previous conversion is shifted out of the + * device. Consequently, the conversion result is delayed by one + * conversion from the command word. + * + * Setup the cmd for the conversions then do a dummy conversion to + * flush the junk data. Then do each conversion requested by the + * comedi_insn. Note that the last conversion will leave junk data + * in ADC which will get flushed on the next comedi_insn. */ - /* convert n samples */ - for (n = 0; n < insn->n; n++) { - unsigned chan = CR_CHAN(insn->chanspec), range = - CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec); - unsigned char command_byte = 0; - unsigned iooffset = 0; - short sample, adc_adjust = 0; - - if (chan > 7) - chan -= 8, iooffset = 4; /* - * use the second dword - * for channels > 7 - */ - - if (aref != AREF_DIFF) { - aref = AREF_GROUND; - command_byte |= 1 << 7; /* - * set bit 7 to indicate - * single-ended - */ - } - if (range < 2) - adc_adjust = 0x8000; /* - * bipolar ranges - * (-5,5 .. -10,10 need to be - * adjusted -- that is.. they - * need to wrap around by - * adding 0x8000 - */ - - if (chan % 2) { - command_byte |= 1 << 6; /* - * odd-numbered channels - * have bit 6 set - */ - } + if (chan > 7) { + chan -= 8; + iobase += PCMMIO_AI_2ND_ADC_OFFSET; + } - /* select the channel, bits 4-5 == chan/2 */ - command_byte |= ((chan / 2) & 0x3) << 4; + if (aref == AREF_GROUND) + cmd |= PCMMIO_AI_CMD_SE; + if (chan % 2) + cmd |= PCMMIO_AI_CMD_ODD_CHAN; + cmd |= PCMMIO_AI_CMD_CHAN_SEL(chan / 2); + cmd |= PCMMIO_AI_CMD_RANGE(range); - /* set the range, bits 2-3 */ - command_byte |= (range & 0x3) << 2; + outb(cmd, iobase + PCMMIO_AI_CMD_REG); - /* need to do this twice to make sure mux settled */ - /* chan/range/aref select */ - outb(command_byte, iobase + iooffset + 2); + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); + if (ret) + return ret; - /* wait for the adc to say it finised the conversion */ - adc_wait_ready(iobase + iooffset); + val = inb(iobase + PCMMIO_AI_LSB_REG); + val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8; - /* select the chan/range/aref AGAIN */ - outb(command_byte, iobase + iooffset + 2); + for (i = 0; i < insn->n; i++) { + outb(cmd, iobase + PCMMIO_AI_CMD_REG); - adc_wait_ready(iobase + iooffset); + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); + if (ret) + return ret; - /* read data lo byte */ - sample = inb(iobase + iooffset + 0); + val = inb(iobase + PCMMIO_AI_LSB_REG); + val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8; - /* read data hi byte */ - sample |= inb(iobase + iooffset + 1) << 8; - sample += adc_adjust; /* adjustment .. munge data */ - data[n] = sample; + /* bipolar data is two's complement */ + if (comedi_range_is_bipolar(s, range)) + val = comedi_offset_munge(s, val); + + data[i] = val; } - /* return the number of samples read/written */ - return n; + + return insn->n; } -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmmio_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - for (n = 0; n < insn->n; n++) { - unsigned chan = CR_CHAN(insn->chanspec); - if (chan < s->n_chan) - data[n] = subpriv->ao.shadow_samples[chan]; - } - return n; + struct pcmmio_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; } -static int wait_dac_ready(unsigned long iobase) +static int pcmmio_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned long retry = 100000L; + unsigned char status; + + status = inb(dev->iobase + PCMMIO_AO_STATUS_REG); + if (status & PCMMIO_AO_STATUS_DATA_READY) + return 0; + return -EBUSY; +} - /* This may seem like an absurd way to handle waiting and violates the - "no busy waiting" policy. The fact is that the hardware is - normally so fast that we usually only need one time through the loop - anyway. The longer timeout is for rare occasions and for detecting - non-existent hardware. */ +static int pcmmio_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcmmio_private *devpriv = dev->private; + unsigned long iobase = dev->iobase; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + unsigned char cmd = 0; + int ret; + int i; - while (retry--) { - if (inb(iobase + 3) & 0x80) - return 0; + /* + * The PCM-MIO has two Linear Tech LTC2704 DAC devices. Each device + * is a 4-channel converter with software-selectable output range. + */ + if (chan > 3) { + cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan - 4); + iobase += PCMMIO_AO_2ND_DAC_OFFSET; + } else { + cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan); } - return 1; -} -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int n; - unsigned iobase = subpriv->iobase, iooffset = 0; - - for (n = 0; n < insn->n; n++) { - unsigned chan = CR_CHAN(insn->chanspec), range = - CR_RANGE(insn->chanspec); - if (chan < s->n_chan) { - unsigned char command_byte = 0, range_byte = - range & ((1 << 4) - 1); - if (chan >= 4) - chan -= 4, iooffset += 4; - /* set the range.. */ - outb(range_byte, iobase + iooffset + 0); - outb(0, iobase + iooffset + 1); - - /* tell it to begin */ - command_byte = (chan << 1) | 0x60; - outb(command_byte, iobase + iooffset + 2); - - wait_dac_ready(iobase + iooffset); - - /* low order byte */ - outb(data[n] & 0xff, iobase + iooffset + 0); - - /* high order byte */ - outb((data[n] >> 8) & 0xff, iobase + iooffset + 1); - - /* - * set bit 4 of command byte to indicate - * data is loaded and trigger conversion - */ - command_byte = 0x70 | (chan << 1); - /* trigger converion */ - outb(command_byte, iobase + iooffset + 2); - - wait_dac_ready(iobase + iooffset); - - /* save to shadow register for ao_rinsn */ - subpriv->ao.shadow_samples[chan] = data[n]; - } + /* set the range for the channel */ + outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG); + outb(0, iobase + PCMMIO_AO_MSB_REG); + outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); + if (ret) + return ret; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* write the data to the channel */ + outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG); + outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG); + outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE, + iobase + PCMMIO_AO_CMD_REG); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); + if (ret) + return ret; + + devpriv->ao_readback[chan] = val; } - return n; + + return insn->n; } static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pcmmio_private *devpriv; struct comedi_subdevice *s; - int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic, - thisasic_chanct = 0; - unsigned int irq[MAX_ASICS]; int ret; - irq[0] = it->options[1]; - ret = comedi_request_region(dev, it->options[0], 32); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; - for (asic = 0; asic < MAX_ASICS; ++asic) { - devpriv->asics[asic].num = asic; - devpriv->asics[asic].iobase = - dev->iobase + 16 + asic * ASIC_IOSIZE; - /* - * this gets actually set at the end of this function when we - * request_irqs - */ - devpriv->asics[asic].irq = 0; - spin_lock_init(&devpriv->asics[asic].spinlock); - } + spin_lock_init(&devpriv->pagelock); + spin_lock_init(&devpriv->spinlock); - chans_left = CHANS_PER_ASIC * 1; - n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left); - n_subdevs = n_dio_subdevs + 2; - devpriv->sprivs = - kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), - GFP_KERNEL); - if (!devpriv->sprivs) { - printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n", - dev->minor); - return -ENOMEM; + pcmmio_reset(dev); + + if (it->options[1]) { + ret = request_irq(it->options[1], interrupt_pcmmio, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = it->options[1]; + + /* configure the interrupt routing on the board */ + outb(PCMMIO_AI_RES_ENA_DIO_RES_ACCESS, + dev->iobase + PCMMIO_AI_RES_ENA_REG); + outb(PCMMIO_RESOURCE_IRQ(dev->irq), + dev->iobase + PCMMIO_RESOURCE_REG); + } } - ret = comedi_alloc_subdevices(dev, n_subdevs); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - /* First, AI */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - s->private = &devpriv->sprivs[0]; - s->maxdata = 0xffff; - s->range_table = &ranges_ai; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->type = COMEDI_SUBD_AI; - s->n_chan = 16; - s->len_chanlist = s->n_chan; - s->insn_read = ai_rinsn; - subpriv->iobase = dev->iobase + 0; - /* initialize the resource enable register by clearing it */ - outb(0, subpriv->iobase + 3); - outb(0, subpriv->iobase + 4 + 3); + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0xffff; + s->range_table = &pcmmio_ai_ranges; + s->insn_read = pcmmio_ai_insn_read; - /* Next, AO */ - s = &dev->subdevices[1]; - s->private = &devpriv->sprivs[1]; - s->maxdata = 0xffff; - s->range_table = &ranges_ao; - s->subdev_flags = SDF_READABLE; - s->type = COMEDI_SUBD_AO; - s->n_chan = 8; - s->len_chanlist = s->n_chan; - s->insn_read = ao_rinsn; - s->insn_write = ao_winsn; - subpriv->iobase = dev->iobase + 8; /* initialize the resource enable register by clearing it */ - outb(0, subpriv->iobase + 3); - outb(0, subpriv->iobase + 4 + 3); - - port = 0; - asic = 0; - for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) { - int byte_no; - - s = &dev->subdevices[sdev_no]; - s->private = &devpriv->sprivs[sdev_no]; - s->maxdata = 1; - s->range_table = &range_digital; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->type = COMEDI_SUBD_DIO; - s->insn_bits = pcmmio_dio_insn_bits; - s->insn_config = pcmmio_dio_insn_config; - s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); - subpriv->dio.intr.asic = -1; - subpriv->dio.intr.first_chan = -1; - subpriv->dio.intr.asic_chan = -1; - subpriv->dio.intr.num_asic_chans = -1; - subpriv->dio.intr.active = 0; - s->len_chanlist = 1; - - /* save the ioport address for each 'port' of 8 channels in the - subdevice */ - for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { - if (port >= PORTS_PER_ASIC) { - port = 0; - ++asic; - thisasic_chanct = 0; - } - subpriv->iobases[byte_no] = - devpriv->asics[asic].iobase + port; - - if (thisasic_chanct < - CHANS_PER_PORT * INTR_PORTS_PER_ASIC - && subpriv->dio.intr.asic < 0) { - /* - * this is an interrupt subdevice, - * so setup the struct - */ - subpriv->dio.intr.asic = asic; - subpriv->dio.intr.active = 0; - subpriv->dio.intr.stop_count = 0; - subpriv->dio.intr.first_chan = byte_no * 8; - subpriv->dio.intr.asic_chan = thisasic_chanct; - subpriv->dio.intr.num_asic_chans = - s->n_chan - subpriv->dio.intr.first_chan; - s->cancel = pcmmio_cancel; - s->do_cmd = pcmmio_cmd; - s->do_cmdtest = pcmmio_cmdtest; - s->len_chanlist = - subpriv->dio.intr.num_asic_chans; - } - thisasic_chanct += CHANS_PER_PORT; - } - spin_lock_init(&subpriv->dio.intr.spinlock); - - chans_left -= s->n_chan; + outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS, + dev->iobase + PCMMIO_AI_RES_ENA_REG); + outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS, + dev->iobase + PCMMIO_AI_RES_ENA_REG + PCMMIO_AI_2ND_ADC_OFFSET); - if (!chans_left) { - /* - * reset the asic to our first asic, - * to do intr subdevs - */ - asic = 0; - port = 0; - } - - } + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 0xffff; + s->range_table = &pcmmio_ao_ranges; + s->insn_read = pcmmio_ao_insn_read; + s->insn_write = pcmmio_ao_insn_write; - init_asics(dev); /* clear out all the registers, basically */ - - for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { - if (irq[asic] - && request_irq(irq[asic], interrupt_pcmmio, - IRQF_SHARED, dev->board_name, dev)) { - int i; - /* unroll the allocated irqs.. */ - for (i = asic - 1; i >= 0; --i) { - free_irq(irq[i], dev); - devpriv->asics[i].irq = irq[i] = 0; - } - irq[asic] = 0; - } - devpriv->asics[asic].irq = irq[asic]; + /* initialize the resource enable register by clearing it */ + outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG); + outb(0, dev->iobase + PCMMIO_AO_2ND_DAC_OFFSET + + PCMMIO_AO_RESOURCE_ENA_REG); + + /* Digital I/O subdevice with interrupt support */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_bits = pcmmio_dio_insn_bits; + s->insn_config = pcmmio_dio_insn_config; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->cancel = pcmmio_cancel; + s->do_cmd = pcmmio_cmd; + s->do_cmdtest = pcmmio_cmdtest; } - return 1; -} + /* Digital I/O subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcmmio_dio_insn_bits; + s->insn_config = pcmmio_dio_insn_config; -static void pcmmio_detach(struct comedi_device *dev) -{ - struct pcmmio_private *devpriv = dev->private; - int i; - - for (i = 0; i < MAX_ASICS; ++i) { - if (devpriv && devpriv->asics[i].irq) - free_irq(devpriv->asics[i].irq, dev); - } - if (devpriv && devpriv->sprivs) - kfree(devpriv->sprivs); - comedi_legacy_detach(dev); + return 0; } static struct comedi_driver pcmmio_driver = { .driver_name = "pcmmio", .module = THIS_MODULE, .attach = pcmmio_attach, - .detach = pcmmio_detach, + .detach = comedi_legacy_detach, }; module_comedi_driver(pcmmio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Winsystems PCM-MIO PC/104 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index c43b6334cea..62914bb342d 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -73,8 +73,8 @@ * can be the same as first irq!) */ +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include "../comedidev.h" @@ -126,36 +126,53 @@ static const struct pcmuio_board pcmuio_boards[] = { }, }; -struct pcmuio_subdev_private { - /* The below is only used for intr subdevices */ - struct { - /* if non-negative, this subdev has an interrupt asic */ - int asic; - /* - * subdev-relative channel mask for channels - * we are interested in - */ - int enabled_mask; - int active; - int stop_count; - int continuous; - spinlock_t spinlock; - } intr; +struct pcmuio_asic { + spinlock_t pagelock; /* protects the page registers */ + spinlock_t spinlock; /* protects member variables */ + unsigned int enabled_mask; + unsigned int stop_count; + unsigned int active:1; + unsigned int continuous:1; }; struct pcmuio_private { - struct { - unsigned int irq; - spinlock_t spinlock; - } asics[PCMUIO_MAX_ASICS]; - struct pcmuio_subdev_private *sprivs; + struct pcmuio_asic asics[PCMUIO_MAX_ASICS]; + unsigned int irq2; }; +static inline unsigned long pcmuio_asic_iobase(struct comedi_device *dev, + int asic) +{ + return dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); +} + +static inline int pcmuio_subdevice_to_asic(struct comedi_subdevice *s) +{ + /* + * subdevice 0 and 1 are handled by the first asic + * subdevice 2 and 3 are handled by the second asic + */ + return s->index / 2; +} + +static inline int pcmuio_subdevice_to_port(struct comedi_subdevice *s) +{ + /* + * subdevice 0 and 2 use port registers 0-2 + * subdevice 1 and 3 use port registers 3-5 + */ + return (s->index % 2) ? 3 : 0; +} + static void pcmuio_write(struct comedi_device *dev, unsigned int val, int asic, int page, int port) { - unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); + struct pcmuio_private *devpriv = dev->private; + struct pcmuio_asic *chip = &devpriv->asics[asic]; + unsigned long iobase = pcmuio_asic_iobase(dev, asic); + unsigned long flags; + spin_lock_irqsave(&chip->pagelock, flags); if (page == 0) { /* Port registers are valid for any page */ outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0)); @@ -167,14 +184,19 @@ static void pcmuio_write(struct comedi_device *dev, unsigned int val, outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1)); outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2)); } + spin_unlock_irqrestore(&chip->pagelock, flags); } static unsigned int pcmuio_read(struct comedi_device *dev, int asic, int page, int port) { - unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); + struct pcmuio_private *devpriv = dev->private; + struct pcmuio_asic *chip = &devpriv->asics[asic]; + unsigned long iobase = pcmuio_asic_iobase(dev, asic); + unsigned long flags; unsigned int val; + spin_lock_irqsave(&chip->pagelock, flags); if (page == 0) { /* Port registers are valid for any page */ val = inb(iobase + PCMUIO_PORT_REG(port + 0)); @@ -186,6 +208,7 @@ static unsigned int pcmuio_read(struct comedi_device *dev, val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8); val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16); } + spin_unlock_irqrestore(&chip->pagelock, flags); return val; } @@ -202,57 +225,54 @@ static unsigned int pcmuio_read(struct comedi_device *dev, */ static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int mask = data[0] & s->io_bits; /* outputs only */ - unsigned int bits = data[1]; - int asic = s->index / 2; - int port = (s->index % 2) ? 3 : 0; + int asic = pcmuio_subdevice_to_asic(s); + int port = pcmuio_subdevice_to_port(s); + unsigned int chanmask = (1 << s->n_chan) - 1; + unsigned int mask; unsigned int val; - /* get inverted state of the channels from the port */ - val = pcmuio_read(dev, asic, 0, port); - - /* get the true state of the channels */ - s->state = val ^ ((0x1 << s->n_chan) - 1); - + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (mask & bits); - - /* invert the state and update the channels */ - val = s->state ^ ((0x1 << s->n_chan) - 1); + /* + * Outputs are inverted, invert the state and + * update the channels. + * + * The s->io_bits mask makes sure the input channels + * are '0' so that the outputs pins stay in a high + * z-state. + */ + val = ~s->state & chanmask; + val &= s->io_bits; pcmuio_write(dev, val, asic, 0, port); } - data[1] = s->state; + /* get inverted state of the channels from the port */ + val = pcmuio_read(dev, asic, 0, port); + + /* return the true state of the channels */ + data[1] = ~val & chanmask; return insn->n; } static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); - int asic = s->index / 2; - int port = (s->index % 2) ? 3 : 0; + int asic = pcmuio_subdevice_to_asic(s); + int port = pcmuio_subdevice_to_port(s); + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= chan_mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~chan_mask; + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + + if (data[0] == INSN_CONFIG_DIO_INPUT) pcmuio_write(dev, s->io_bits, asic, 0, port); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & chan_mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - break; - default: - return -EINVAL; - break; - } return insn->n; } @@ -274,18 +294,16 @@ static void pcmuio_reset(struct comedi_device *dev) } } +/* chip->spinlock is already locked */ static void pcmuio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pcmuio_subdev_private *subpriv = s->private; - int asic; - - asic = subpriv->intr.asic; - if (asic < 0) - return; /* not an interrupt subdev */ + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; - subpriv->intr.enabled_mask = 0; - subpriv->intr.active = 0; + chip->enabled_mask = 0; + chip->active = 0; s->async->inttrig = NULL; /* disable all intrs for this subdev.. */ @@ -296,34 +314,32 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, struct comedi_subdevice *s, unsigned triggered) { - struct pcmuio_subdev_private *subpriv = s->private; - unsigned int len = s->async->cmd.chanlist_len; + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; + struct comedi_cmd *cmd = &s->async->cmd; unsigned oldevents = s->async->events; unsigned int val = 0; unsigned long flags; - unsigned mytrig; unsigned int i; - spin_lock_irqsave(&subpriv->intr.spinlock, flags); + spin_lock_irqsave(&chip->spinlock, flags); - if (!subpriv->intr.active) + if (!chip->active) goto done; - mytrig = triggered; - mytrig &= ((0x1 << s->n_chan) - 1); - - if (!(mytrig & subpriv->intr.enabled_mask)) + if (!(triggered & chip->enabled_mask)) goto done; - for (i = 0; i < len; i++) { - unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]); - if (mytrig & (1U << chan)) - val |= (1U << i); + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + if (triggered & (1 << chan)) + val |= (1 << i); } /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *)&val)[0]) && - comedi_buf_put(s->async, ((short *)&val)[1])) { + if (comedi_buf_put(s, val) && + comedi_buf_put(s, val >> 16)) { s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); } else { /* Overflow! Stop acquisition!! */ @@ -332,11 +348,11 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, } /* Check for end of acquisition. */ - if (!subpriv->intr.continuous) { + if (!chip->continuous) { /* stop_src == TRIG_COUNT */ - if (subpriv->intr.stop_count > 0) { - subpriv->intr.stop_count--; - if (subpriv->intr.stop_count == 0) { + if (chip->stop_count > 0) { + chip->stop_count--; + if (chip->stop_count == 0) { s->async->events |= COMEDI_CB_EOA; /* TODO: STOP_ACQUISITION_CALL_HERE!! */ pcmuio_stop_intr(dev, s); @@ -345,7 +361,7 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, } done: - spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + spin_unlock_irqrestore(&chip->spinlock, flags); if (oldevents != s->async->events) comedi_event(dev, s); @@ -353,138 +369,117 @@ done: static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) { - struct pcmuio_private *devpriv = dev->private; - struct pcmuio_subdev_private *subpriv; - unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); - unsigned int triggered = 0; - int got1 = 0; - unsigned long flags; - unsigned char int_pend; - int i; + /* there are could be two asics so we can't use dev->read_subdev */ + struct comedi_subdevice *s = &dev->subdevices[asic * 2]; + unsigned long iobase = pcmuio_asic_iobase(dev, asic); + unsigned int val; - spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags); + /* are there any interrupts pending */ + val = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07; + if (!val) + return 0; - int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07; - if (int_pend) { - triggered = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0); - pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0); + /* get, and clear, the pending interrupts */ + val = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0); + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0); - ++got1; - } + /* handle the pending interrupts */ + pcmuio_handle_intr_subdev(dev, s, val); - spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags); - - if (triggered) { - struct comedi_subdevice *s; - /* TODO here: dispatch io lines to subdevs with commands.. */ - for (i = 0; i < dev->n_subdevices; i++) { - s = &dev->subdevices[i]; - subpriv = s->private; - if (subpriv->intr.asic == asic) { - /* - * This is an interrupt subdev, and it - * matches this asic! - */ - pcmuio_handle_intr_subdev(dev, s, - triggered); - } - } - } - return got1; + return 1; } static irqreturn_t pcmuio_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct pcmuio_private *devpriv = dev->private; - int got1 = 0; - int asic; + int handled = 0; - for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic) { - if (irq == devpriv->asics[asic].irq) { - /* it is an interrupt for ASIC #asic */ - if (pcmuio_handle_asic_interrupt(dev, asic)) - got1++; - } - } - if (!got1) - return IRQ_NONE; /* interrupt from other source */ - return IRQ_HANDLED; + if (irq == dev->irq) + handled += pcmuio_handle_asic_interrupt(dev, 0); + if (irq == devpriv->irq2) + handled += pcmuio_handle_asic_interrupt(dev, 1); + + return handled ? IRQ_HANDLED : IRQ_NONE; } +/* chip->spinlock is already locked */ static int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pcmuio_subdev_private *subpriv = s->private; + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int bits = 0; + unsigned int pol_bits = 0; + int i; - if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) { + if (!chip->continuous && chip->stop_count == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; - subpriv->intr.active = 0; + chip->active = 0; return 1; - } else { - unsigned bits = 0, pol_bits = 0, n; - int asic; - struct comedi_cmd *cmd = &s->async->cmd; - - asic = subpriv->intr.asic; - if (asic < 0) - return 1; /* not an interrupt - subdev */ - subpriv->intr.enabled_mask = 0; - subpriv->intr.active = 1; - if (cmd->chanlist) { - for (n = 0; n < cmd->chanlist_len; n++) { - bits |= (1U << CR_CHAN(cmd->chanlist[n])); - pol_bits |= (CR_AREF(cmd->chanlist[n]) - || CR_RANGE(cmd-> - chanlist[n]) ? 1U : 0U) - << CR_CHAN(cmd->chanlist[n]); - } - } - bits &= ((0x1 << s->n_chan) - 1); - subpriv->intr.enabled_mask = bits; + } - /* set pol and enab intrs for this subdev.. */ - pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0); - pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0); + chip->enabled_mask = 0; + chip->active = 1; + if (cmd->chanlist) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + + bits |= (1 << chan); + pol_bits |= ((aref || range) ? 1 : 0) << chan; + } } + bits &= ((1 << s->n_chan) - 1); + chip->enabled_mask = bits; + + /* set pol and enab intrs for this subdev.. */ + pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0); + pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0); + return 0; } static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pcmuio_subdev_private *subpriv = s->private; + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; - spin_lock_irqsave(&subpriv->intr.spinlock, flags); - if (subpriv->intr.active) + spin_lock_irqsave(&chip->spinlock, flags); + if (chip->active) pcmuio_stop_intr(dev, s); - spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pcmuio_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { - struct pcmuio_subdev_private *subpriv = s->private; + struct pcmuio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; - spin_lock_irqsave(&subpriv->intr.spinlock, flags); + spin_lock_irqsave(&chip->spinlock, flags); s->async->inttrig = NULL; - if (subpriv->intr.active) + if (chip->active) event = pcmuio_start_intr(dev, s); - spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + spin_unlock_irqrestore(&chip->spinlock, flags); if (event) comedi_event(dev, s); @@ -497,38 +492,36 @@ pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, */ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pcmuio_subdev_private *subpriv = s->private; + struct pcmuio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; int event = 0; - spin_lock_irqsave(&subpriv->intr.spinlock, flags); - subpriv->intr.active = 1; + spin_lock_irqsave(&chip->spinlock, flags); + chip->active = 1; /* Set up end of acquisition. */ switch (cmd->stop_src) { case TRIG_COUNT: - subpriv->intr.continuous = 0; - subpriv->intr.stop_count = cmd->stop_arg; + chip->continuous = 0; + chip->stop_count = cmd->stop_arg; break; default: /* TRIG_NONE */ - subpriv->intr.continuous = 1; - subpriv->intr.stop_count = 0; + chip->continuous = 1; + chip->stop_count = 0; break; } /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmuio_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = pcmuio_start_intr(dev, s); - break; - } - spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + + spin_unlock_irqrestore(&chip->spinlock, flags); if (event) comedi_event(dev, s); @@ -596,80 +589,72 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) const struct pcmuio_board *board = comedi_board(dev); struct comedi_subdevice *s; struct pcmuio_private *devpriv; - struct pcmuio_subdev_private *subpriv; - int sdev_no, n_subdevs, asic; - unsigned int irq[PCMUIO_MAX_ASICS]; int ret; - - irq[0] = it->options[1]; - irq[1] = it->options[2]; + int i; ret = comedi_request_region(dev, it->options[0], board->num_asics * PCMUIO_ASIC_IOSIZE); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; - for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic) - spin_lock_init(&devpriv->asics[asic].spinlock); + for (i = 0; i < PCMUIO_MAX_ASICS; ++i) { + struct pcmuio_asic *chip = &devpriv->asics[i]; - n_subdevs = board->num_asics * 2; - devpriv->sprivs = kcalloc(n_subdevs, sizeof(*subpriv), GFP_KERNEL); - if (!devpriv->sprivs) - return -ENOMEM; + spin_lock_init(&chip->pagelock); + spin_lock_init(&chip->spinlock); + } - ret = comedi_alloc_subdevices(dev, n_subdevs); - if (ret) - return ret; + pcmuio_reset(dev); - for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { - s = &dev->subdevices[sdev_no]; - subpriv = &devpriv->sprivs[sdev_no]; - s->private = subpriv; - s->maxdata = 1; - s->range_table = &range_digital; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->type = COMEDI_SUBD_DIO; - s->insn_bits = pcmuio_dio_insn_bits; - s->insn_config = pcmuio_dio_insn_config; - s->n_chan = 24; - - /* subdevices 0 and 2 suppport interrupts */ - if ((sdev_no % 2) == 0) { - /* setup the interrupt subdevice */ - subpriv->intr.asic = sdev_no / 2; - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = pcmuio_cancel; - s->do_cmd = pcmuio_cmd; - s->do_cmdtest = pcmuio_cmdtest; - s->len_chanlist = s->n_chan; - } else { - subpriv->intr.asic = -1; - s->len_chanlist = 1; + if (it->options[1]) { + /* request the irq for the 1st asic */ + ret = request_irq(it->options[1], pcmuio_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; + } + + if (board->num_asics == 2) { + if (it->options[2] == dev->irq) { + /* the same irq (or none) is used by both asics */ + devpriv->irq2 = it->options[2]; + } else if (it->options[2]) { + /* request the irq for the 2nd asic */ + ret = request_irq(it->options[2], pcmuio_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + devpriv->irq2 = it->options[2]; } - spin_lock_init(&subpriv->intr.spinlock); } - pcmuio_reset(dev); + ret = comedi_alloc_subdevices(dev, board->num_asics * 2); + if (ret) + return ret; - for (asic = 0; irq[0] && asic < PCMUIO_MAX_ASICS; ++asic) { - if (irq[asic] - && request_irq(irq[asic], pcmuio_interrupt, - IRQF_SHARED, board->name, dev)) { - int i; - /* unroll the allocated irqs.. */ - for (i = asic - 1; i >= 0; --i) { - free_irq(irq[i], dev); - devpriv->asics[i].irq = irq[i] = 0; - } - irq[asic] = 0; + for (i = 0; i < dev->n_subdevices; ++i) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcmuio_dio_insn_bits; + s->insn_config = pcmuio_dio_insn_config; + + /* subdevices 0 and 2 can suppport interrupts */ + if ((i == 0 && dev->irq) || (i == 2 && devpriv->irq2)) { + /* setup the interrupt subdevice */ + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->cancel = pcmuio_cancel; + s->do_cmd = pcmuio_cmd; + s->do_cmdtest = pcmuio_cmdtest; } - devpriv->asics[asic].irq = irq[asic]; } return 0; @@ -678,14 +663,14 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void pcmuio_detach(struct comedi_device *dev) { struct pcmuio_private *devpriv = dev->private; - int i; - for (i = 0; i < PCMUIO_MAX_ASICS; ++i) { - if (devpriv->asics[i].irq) - free_irq(devpriv->asics[i].irq, dev); + if (devpriv) { + pcmuio_reset(dev); + + /* free the 2nd irq if used, the core will free the 1st one */ + if (devpriv->irq2 && devpriv->irq2 != dev->irq) + free_irq(devpriv->irq2, dev); } - if (devpriv && devpriv->sprivs) - kfree(devpriv->sprivs); comedi_legacy_detach(dev); } diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 0d254a1b78a..25706531b88 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -29,13 +29,13 @@ /* descriptor block used for chained dma transfers */ struct plx_dma_desc { - volatile uint32_t pci_start_addr; - volatile uint32_t local_start_addr; + __le32 pci_start_addr; + __le32 local_start_addr; /* transfer_size is in bytes, only first 23 bits of register are used */ - volatile uint32_t transfer_size; + __le32 transfer_size; /* address of next descriptor (quad word aligned), plus some * additional bits (see PLX_DMA0_DESCRIPTOR_REG) */ - volatile uint32_t next; + __le32 next; }; /********************************************************************** @@ -402,12 +402,9 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) udelay(1); dma_status = readb(dma_cs_addr); } - if (i == timeout) { - printk - ("plx9080: cancel() timed out waiting for dma %i done clear\n", - channel); + if (i == timeout) return -ETIMEDOUT; - } + /* disable and abort channel */ writeb(PLX_DMA_ABORT_BIT, dma_cs_addr); /* wait for dma done bit */ @@ -416,12 +413,8 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) udelay(1); dma_status = readb(dma_cs_addr); } - if (i == timeout) { - printk - ("plx9080: cancel() timed out waiting for dma %i done set\n", - channel); + if (i == timeout) return -ETIMEDOUT; - } return 0; } diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c deleted file mode 100644 index 005fbefae29..00000000000 --- a/drivers/staging/comedi/drivers/poc.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - comedi/drivers/poc.c - Mini-drivers for POC (Piece of Crap) boards - Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: poc -Description: Generic driver for very simple devices -Author: ds -Devices: [Keithley Metrabyte] DAC-02 (dac02) -Updated: Sat, 16 Mar 2002 17:34:48 -0800 -Status: unknown - -This driver is indended to support very simple ISA-based devices, -including: - dac02 - Keithley DAC-02 analog output board - -Configuration options: - [0] - I/O port base -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -struct boarddef_struct { - const char *name; - unsigned int iosize; - int (*setup) (struct comedi_device *); - int type; - int n_chan; - int n_bits; - int (*winsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - const struct comedi_lrange *range; -}; - -struct poc_private { - unsigned int ao_readback[32]; -}; - -static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int chan; - - chan = CR_CHAN(insn->chanspec); - data[0] = devpriv->ao_readback[chan]; - - return 1; -} - -/* DAC-02 registers */ -#define DAC02_LSB(a) (2 * a) -#define DAC02_MSB(a) (2 * a + 1) - -static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int temp; - int chan; - int output; - - chan = CR_CHAN(insn->chanspec); - devpriv->ao_readback[chan] = data[0]; - output = data[0]; -#ifdef wrong - /* convert to complementary binary if range is bipolar */ - if ((CR_RANGE(insn->chanspec) & 0x2) == 0) - output = ~output; -#endif - temp = (output << 4) & 0xf0; - outb(temp, dev->iobase + DAC02_LSB(chan)); - temp = (output >> 4) & 0xff; - outb(temp, dev->iobase + DAC02_MSB(chan)); - - return 1; -} - -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct boarddef_struct *board = comedi_board(dev); - struct poc_private *devpriv; - struct comedi_subdevice *s; - int ret; - - ret = comedi_request_region(dev, it->options[0], board->iosize); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; - - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); - if (!devpriv) - return -ENOMEM; - dev->private = devpriv; - - /* analog output subdevice */ - s = &dev->subdevices[0]; - s->type = board->type; - s->n_chan = board->n_chan; - s->maxdata = (1 << board->n_bits) - 1; - s->range_table = board->range; - s->insn_write = board->winsn; - s->insn_read = board->rinsn; - s->insn_bits = board->insnbits; - if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) - s->subdev_flags = SDF_WRITABLE; - - return 0; -} - -static const struct boarddef_struct boards[] = { - { - .name = "dac02", - .iosize = 8, - /* .setup = dac02_setup, */ - .type = COMEDI_SUBD_AO, - .n_chan = 2, - .n_bits = 12, - .winsn = dac02_ao_winsn, - .rinsn = readback_insn, - .range = &range_unknown, - }, -}; - -static struct comedi_driver poc_driver = { - .driver_name = "poc", - .module = THIS_MODULE, - .attach = poc_attach, - .detach = comedi_legacy_detach, - .board_name = &boards[0].name, - .num_names = ARRAY_SIZE(boards), - .offset = sizeof(boards[0]), -}; -module_comedi_driver(poc_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index e092ce87722..b3bbec0a0d2 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -47,6 +47,7 @@ Status: works Devices: [Quatech] DAQP-208 (daqp), DAQP-308 */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/semaphore.h> @@ -207,14 +208,12 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) case buffer: while (!((status = inb(dev->iobase + DAQP_STATUS)) & DAQP_STATUS_FIFO_EMPTY)) { - - short data; + unsigned short data; if (status & DAQP_STATUS_DATA_LOST) { s->async->events |= COMEDI_CB_EOA | COMEDI_CB_OVERFLOW; dev_warn(dev->class_dev, "data lost\n"); - daqp_ai_cancel(dev, s); break; } @@ -222,7 +221,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) data |= inb(dev->iobase + DAQP_FIFO) << 8; data ^= 0x8000; - comedi_buf_put(s->async, data); + comedi_buf_put(s, data); /* If there's a limit, decrement it * and stop conversion if zero @@ -231,7 +230,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) if (devpriv->count > 0) { devpriv->count--; if (devpriv->count == 0) { - daqp_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; break; } @@ -244,13 +242,12 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) if (loop_limit <= 0) { dev_warn(dev->class_dev, "loop_limit reached in daqp_interrupt()\n"); - daqp_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } s->async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); } return IRQ_HANDLED; } @@ -376,7 +373,7 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -438,19 +435,15 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - daqp_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + daqp_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - daqp_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + daqp_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -689,18 +682,12 @@ static int daqp_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct daqp_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; if (devpriv->stop) return -EIO; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outb(s->state, dev->iobase + DAQP_DIGITAL_IO); - } data[1] = s->state; @@ -715,10 +702,9 @@ static int daqp_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; ret = comedi_pcmcia_enable(dev, NULL); diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 9b93a1fc4a5..d55c5893203 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -95,6 +95,7 @@ * Digital-IO and Analog-Out only support instruction mode. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -236,20 +237,6 @@ /* The board support a channel list up to the FIFO length (1K or 8K) */ #define RTD_MAX_CHANLIST 128 /* max channel list that we allow */ -/* tuning for ai/ao instruction done polling */ -#ifdef FAST_SPIN -#define WAIT_QUIETLY /* as nothing, spin on done bit */ -#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */ -#define RTD_DAC_TIMEOUT 66000 -#define RTD_DMA_TIMEOUT 33000 /* 1 msec */ -#else -/* by delaying, power and electrical noise are reduced somewhat */ -#define WAIT_QUIETLY udelay(1) -#define RTD_ADC_TIMEOUT 2000 /* in usec */ -#define RTD_DAC_TIMEOUT 2000 /* in usec */ -#define RTD_DMA_TIMEOUT 1000 /* in usec */ -#endif - /*====================================================================== Board specific stuff ======================================================================*/ @@ -393,11 +380,8 @@ struct rtd_private { long ai_count; /* total transfer size (samples) */ int xfer_count; /* # to transfer data. 0->1/2FIFO */ int flags; /* flag event modes */ - - unsigned char chan_is_bipolar[RTD_MAX_CHANLIST / 8]; /* bit array */ - + DECLARE_BITMAP(chan_is_bipolar, RTD_MAX_CHANLIST); unsigned int ao_readback[2]; - unsigned fifosz; }; @@ -406,14 +390,6 @@ struct rtd_private { #define DMA0_ACTIVE 0x02 /* DMA0 is active */ #define DMA1_ACTIVE 0x04 /* DMA1 is active */ -/* Macros for accessing channel list bit array */ -#define CHAN_ARRAY_TEST(array, index) \ - (((array)[(index)/8] >> ((index) & 0x7)) & 0x1) -#define CHAN_ARRAY_SET(array, index) \ - (((array)[(index)/8] |= 1 << ((index) & 0x7))) -#define CHAN_ARRAY_CLEAR(array, index) \ - (((array)[(index)/8] &= ~(1 << ((index) & 0x7)))) - /* Given a desired period and the clock period (both in ns), return the proper counter value (divider-1). @@ -477,17 +453,17 @@ static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, /* +-5 range */ r |= 0x000; r |= (range & 0x7) << 4; - CHAN_ARRAY_SET(devpriv->chan_is_bipolar, index); + __set_bit(index, devpriv->chan_is_bipolar); } else if (range < board->range_uni10) { /* +-10 range */ r |= 0x100; r |= ((range - board->range_bip10) & 0x7) << 4; - CHAN_ARRAY_SET(devpriv->chan_is_bipolar, index); + __set_bit(index, devpriv->chan_is_bipolar); } else { /* +10 range */ r |= 0x200; r |= ((range - board->range_uni10) & 0x7) << 4; - CHAN_ARRAY_CLEAR(devpriv->chan_is_bipolar, index); + __clear_bit(index, devpriv->chan_is_bipolar); } switch (aref) { @@ -505,8 +481,6 @@ static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, case AREF_OTHER: /* ??? */ break; } - /*printk ("chan=%d r=%d a=%d -> 0x%x\n", - chan, range, aref, r); */ return r; } @@ -574,21 +548,27 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) return fifo_size; } -/* - "instructions" read/write data in "one-shot" or "software-triggered" - mode (simplest case). - This doesn't use interrupts. +static int rtd_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & FS_ADC_NOT_EMPTY) + return 0; + return -EBUSY; +} - Note, we don't do any settling delays. Use a instruction list to - select, delay, then read. - */ static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct rtd_private *devpriv = dev->private; - int n, ii; - int stat; + int ret; + int n; /* clear any old fifo data */ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); @@ -601,28 +581,21 @@ static int rtd_ai_rinsn(struct comedi_device *dev, /* convert n samples */ for (n = 0; n < insn->n; n++) { - s16 d; + unsigned short d; /* trigger conversion */ writew(0, devpriv->las0 + LAS0_ADC); - for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) { - stat = readl(devpriv->las0 + LAS0_ADC); - if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */ - break; - WAIT_QUIETLY; - } - if (ii >= RTD_ADC_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0); + if (ret) + return ret; /* read data */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); - /*printk ("rtd520: Got 0x%x after %d usec\n", d, ii+1); */ d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, 0)) + if (test_bit(0, devpriv->chan_is_bipolar)) /* convert to comedi unsigned data */ - data[n] = d + 2048; - else - data[n] = d; + d = comedi_offset_munge(s, d); + data[n] = d & s->maxdata; } /* return the number of samples read/written */ @@ -642,8 +615,7 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, int ii; for (ii = 0; ii < count; ii++) { - short sample; - s16 d; + unsigned short d; if (0 == devpriv->ai_count) { /* done */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); @@ -652,14 +624,12 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, d = readw(devpriv->las1 + LAS1_ADC_FIFO); d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, - s->async->cur_chan)) { + if (test_bit(s->async->cur_chan, devpriv->chan_is_bipolar)) /* convert to comedi unsigned data */ - sample = d + 2048; - } else - sample = d; + d = comedi_offset_munge(s, d); + d &= s->maxdata; - if (!comedi_buf_put(s->async, sample)) + if (!comedi_buf_put(s, d)) return -1; if (devpriv->ai_count > 0) /* < 0, means read forever */ @@ -676,22 +646,19 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) struct rtd_private *devpriv = dev->private; while (readl(devpriv->las0 + LAS0_ADC) & FS_ADC_NOT_EMPTY) { - short sample; - s16 d = readw(devpriv->las1 + LAS1_ADC_FIFO); + unsigned short d = readw(devpriv->las1 + LAS1_ADC_FIFO); if (0 == devpriv->ai_count) { /* done */ continue; /* read rest */ } d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, - s->async->cur_chan)) { + if (test_bit(s->async->cur_chan, devpriv->chan_is_bipolar)) /* convert to comedi unsigned data */ - sample = d + 2048; - } else - sample = d; + d = comedi_offset_munge(s, d); + d &= s->maxdata; - if (!comedi_buf_put(s->async, sample)) + if (!comedi_buf_put(s, d)) return -1; if (devpriv->ai_count > 0) /* < 0, means read forever */ @@ -709,7 +676,7 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) static irqreturn_t rtd_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; struct rtd_private *devpriv = dev->private; u32 overrun; u16 status; @@ -812,7 +779,7 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -911,6 +878,8 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + if (cmd->stop_src == TRIG_COUNT) { /* TODO check for rounding error due to counter wrap */ } else { @@ -924,31 +893,21 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->chanlist_len > RTD_MAX_CHANLIST) { - cmd->chanlist_len = RTD_MAX_CHANLIST; - err++; - } if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - rtd_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; - + arg = cmd->scan_begin_arg; + rtd_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } + if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - rtd_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - - if (cmd->scan_begin_src == TRIG_TIMER - && (cmd->scan_begin_arg - < (cmd->convert_arg * cmd->scan_end_arg))) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + rtd_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -1136,9 +1095,22 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* - Output one (or more) analog values to a single port as fast as possible. -*/ +static int rtd_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int bit = (chan == 0) ? FS_DAC1_NOT_EMPTY : FS_DAC2_NOT_EMPTY; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & bit) + return 0; + return -EBUSY; +} + static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1147,6 +1119,7 @@ static int rtd_ao_winsn(struct comedi_device *dev, int i; int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); + int ret; /* Configure the output range (table index matches the range values) */ writew(range & 7, devpriv->las0 + @@ -1156,8 +1129,6 @@ static int rtd_ao_winsn(struct comedi_device *dev, * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; ++i) { int val = data[i] << 3; - int stat = 0; /* initialize to avoid bogus warning */ - int ii; /* VERIFY: comedi range and offset conversions */ @@ -1177,16 +1148,9 @@ static int rtd_ao_winsn(struct comedi_device *dev, devpriv->ao_readback[chan] = data[i]; - for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) { - stat = readl(devpriv->las0 + LAS0_ADC); - /* 1 -> not empty */ - if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY : - FS_DAC2_NOT_EMPTY)) - break; - WAIT_QUIETLY; - } - if (ii >= RTD_DAC_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0); + if (ret) + return ret; } /* return the number of samples read/written */ @@ -1216,15 +1180,9 @@ static int rtd_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { struct rtd_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) writew(s->state & 0xff, devpriv->las0 + LAS0_DIO0); - } data[1] = readw(devpriv->las0 + LAS0_DIO0) & 0xff; @@ -1237,23 +1195,11 @@ static int rtd_dio_insn_config(struct comedi_device *dev, unsigned int *data) { struct rtd_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask = 1 << chan; + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; /* TODO support digital match interrupts and strobes */ @@ -1338,10 +1284,9 @@ static int rtd_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -1421,8 +1366,6 @@ static int rtd_auto_attach(struct comedi_device *dev, if (dev->irq) writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } @@ -1463,7 +1406,7 @@ static int rtd520_pci_probe(struct pci_dev *dev, return comedi_pci_auto_config(dev, &rtd520_driver, id->driver_data); } -static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = { +static const struct pci_device_id rtd520_pci_table[] = { { PCI_VDEVICE(RTD, 0x7520), BOARD_DM7520 }, { PCI_VDEVICE(RTD, 0x4520), BOARD_PCI4520 }, { 0 } diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index f698c7fc572..bd447b2add7 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -49,11 +49,11 @@ * [8] - DAC 1 encoding (same as DAC 0) */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - /* * Register map */ @@ -83,8 +83,6 @@ #define RTI800_IOSIZE 0x10 -#define RTI800_AI_TIMEOUT 100 - static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, { BIP_RANGE(10), @@ -145,23 +143,21 @@ struct rti800_private { unsigned char muxgain_bits; }; -static int rti800_ai_wait_for_conversion(struct comedi_device *dev, - int timeout) +static int rti800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - int i; - for (i = 0; i < timeout; i++) { - status = inb(dev->iobase + RTI800_CSR); - if (status & RTI800_CSR_OVERRUN) { - outb(0, dev->iobase + RTI800_CLRFLAGS); - return -EIO; - } - if (status & RTI800_CSR_DONE) - return 0; - udelay(1); + status = inb(dev->iobase + RTI800_CSR); + if (status & RTI800_CSR_OVERRUN) { + outb(0, dev->iobase + RTI800_CLRFLAGS); + return -EOVERFLOW; } - return -ETIME; + if (status & RTI800_CSR_DONE) + return 0; + return -EBUSY; } static int rti800_ai_insn_read(struct comedi_device *dev, @@ -198,7 +194,8 @@ static int rti800_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(0, dev->iobase + RTI800_CONVERT); - ret = rti800_ai_wait_for_conversion(dev, RTI800_AI_TIMEOUT); + + ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0); if (ret) return ret; @@ -267,13 +264,7 @@ static int rti800_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) { /* Outputs are inverted... */ outb(s->state ^ 0xff, dev->iobase + RTI800_DO); } @@ -298,10 +289,9 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) inb(dev->iobase + RTI800_ADCHI); outb(0, dev->iobase + RTI800_CLRFLAGS); - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->adc_2comp = (it->options[4] == 0); devpriv->dac_2comp[0] = (it->options[6] == 0); diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index 9e744505548..605a31d702e 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -1,46 +1,44 @@ /* - comedi/drivers/rti802.c - Hardware driver for Analog Devices RTI-802 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * rti802.c + * Comedi driver for Analog Devices RTI-802 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: rti802 -Description: Analog Devices RTI-802 -Author: Anders Blomdell <anders.blomdell@control.lth.se> -Devices: [Analog Devices] RTI-802 (rti802) -Status: works - -Configuration Options: - [0] - i/o base - [1] - unused - [2] - dac#0 0=two's comp, 1=straight - [3] - dac#0 0=bipolar, 1=unipolar - [4] - dac#1 ... - ... - [17] - dac#7 ... -*/ + * Driver: rti802 + * Description: Analog Devices RTI-802 + * Author: Anders Blomdell <anders.blomdell@control.lth.se> + * Devices: (Analog Devices) RTI-802 [rti802] + * Status: works + * + * Configuration Options: + * [0] - i/o base + * [1] - unused + * [2,4,6,8,10,12,14,16] - dac#[0-7] 0=two's comp, 1=straight + * [3,5,7,9,11,13,15,17] - dac#[0-7] 0=bipolar, 1=unipolar + */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#define RTI802_SIZE 4 - -#define RTI802_SELECT 0 -#define RTI802_DATALOW 1 -#define RTI802_DATAHIGH 2 +/* + * Register I/O map + */ +#define RTI802_SELECT 0x00 +#define RTI802_DATALOW 0x01 +#define RTI802_DATAHIGH 0x02 struct rti802_private { enum { @@ -52,34 +50,45 @@ struct rti802_private { static int rti802_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; + data[i] = devpriv->ao_readback[chan]; - return i; + return insn->n; } static int rti802_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; - int i, d; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + RTI802_SELECT); for (i = 0; i < insn->n; i++) { - d = devpriv->ao_readback[chan] = data[i]; + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* munge offset binary to two's complement if needed */ if (devpriv->dac_coding[chan] == dac_2comp) - d ^= 0x800; - outb(chan, dev->iobase + RTI802_SELECT); - outb(d & 0xff, dev->iobase + RTI802_DATALOW); - outb(d >> 8, dev->iobase + RTI802_DATAHIGH); + val = comedi_offset_munge(s, val); + + outb(val & 0xff, dev->iobase + RTI802_DATALOW); + outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH); } - return i; + + return insn->n; } static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -89,35 +98,33 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) int i; int ret; - ret = comedi_request_region(dev, it->options[0], RTI802_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x04); if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; + /* Analog Output subdevice */ s = &dev->subdevices[0]; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 0xfff; - s->n_chan = 8; - s->insn_read = rti802_ao_insn_read; - s->insn_write = rti802_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->maxdata = 0xfff; + s->n_chan = 8; + s->insn_read = rti802_ao_insn_read; + s->insn_write = rti802_ao_insn_write; s->range_table_list = devpriv->range_type_list; for (i = 0; i < 8; i++) { devpriv->dac_coding[i] = (it->options[3 + 2 * i]) - ? (dac_straight) - : (dac_2comp); + ? (dac_straight) : (dac_2comp); devpriv->range_type_list[i] = (it->options[2 + 2 * i]) - ? &range_unipolar10 : &range_bipolar10; + ? &range_unipolar10 : &range_bipolar10; } return 0; @@ -132,5 +139,5 @@ static struct comedi_driver rti802_driver = { module_comedi_driver(rti802_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index e1587e58a73..85d2b7a3c12 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -36,8 +36,8 @@ comedi_config /dev/comedi0 s526 0x2C0,0x3 */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <asm/byteorder.h> #define S526_SIZE 64 @@ -420,15 +420,28 @@ static int s526_ai_insn_config(struct comedi_device *dev, return result; } +static int s526_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + REG_ISR); + if (status & ISR_ADC_DONE) + return 0; + return -EBUSY; +} + static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct s526_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - int n, i; + int n; unsigned short value; unsigned int d; - unsigned int status; + int ret; /* Set configured delay, enable channel for this channel only, * select "ADC read" channel, set "ADC start" bit. */ @@ -440,17 +453,12 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outw(value, dev->iobase + REG_ADC); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + REG_ISR); - if (status & ISR_ADC_DONE) { - outw(ISR_ADC_DONE, dev->iobase + REG_ISR); - break; - } - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0); + if (ret) + return ret; + + outw(ISR_ADC_DONE, dev->iobase + REG_ISR); /* read data */ d = inw(dev->iobase + REG_ADD); @@ -499,14 +507,11 @@ static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, static int s526_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + REG_DIO); - } data[1] = inw(dev->iobase + REG_DIO) & 0xff; @@ -515,32 +520,35 @@ static int s526_dio_insn_bits(struct comedi_device *dev, static int s526_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - int group, mask; + unsigned int mask; + int ret; + + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + /* bit 10/11 set the group 1/2's mode */ + if (s->io_bits & 0x0f) + s->state |= (1 << 10); + else + s->state &= ~(1 << 10); + if (s->io_bits & 0xf0) + s->state |= (1 << 11); + else + s->state &= ~(1 << 11); - group = chan >> 2; - mask = 0xF << (group << 2); - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - /* bit 10/11 set the group 1/2's mode */ - s->state |= 1 << (group + 10); - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->state &= ~(1 << (group + 10)); /* 1 is output, 0 is input. */ - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - default: - return -EINVAL; - } outw(s->state, dev->iobase + REG_DIO); - return 1; + return insn->n; } static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -553,10 +561,9 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_alloc_subdevices(dev, 4); if (ret) @@ -605,7 +612,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = s526_dio_insn_bits; s->insn_config = s526_dio_insn_config; - return 1; + return 0; } static struct comedi_driver s526_driver = { diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 48c4b70b736..0838f8aa695 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -1,64 +1,66 @@ /* - comedi/drivers/s626.c - Sensoray s626 Comedi driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - Based on Sensoray Model 626 Linux driver Version 0.2 - Copyright (C) 2002-2004 Sensoray Co., Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/s626.c + * Sensoray s626 Comedi driver + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * Based on Sensoray Model 626 Linux driver Version 0.2 + * Copyright (C) 2002-2004 Sensoray Co., Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: s626 -Description: Sensoray 626 driver -Devices: [Sensoray] 626 (s626) -Authors: Gianluca Palli <gpalli@deis.unibo.it>, -Updated: Fri, 15 Feb 2008 10:28:42 +0000 -Status: experimental - -Configuration options: not applicable, uses PCI auto config - -INSN_CONFIG instructions: - analog input: - none - - analog output: - none - - digital channel: - s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels - supported configuration options: - INSN_CONFIG_DIO_QUERY - COMEDI_INPUT - COMEDI_OUTPUT - - encoder: - Every channel must be configured before reading. - - Example code - - insn.insn=INSN_CONFIG; //configuration instruction - insn.n=1; //number of operation (must be 1) - insn.data=&initialvalue; //initial value loaded into encoder - //during configuration - insn.subdev=5; //encoder subdevice - insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel - //to configure - - comedi_do_insn(cf,&insn); //executing configuration -*/ + * Driver: s626 + * Description: Sensoray 626 driver + * Devices: [Sensoray] 626 (s626) + * Authors: Gianluca Palli <gpalli@deis.unibo.it>, + * Updated: Fri, 15 Feb 2008 10:28:42 +0000 + * Status: experimental + + * Configuration options: not applicable, uses PCI auto config + + * INSN_CONFIG instructions: + * analog input: + * none + * + * analog output: + * none + * + * digital channel: + * s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels + * supported configuration options: + * INSN_CONFIG_DIO_QUERY + * COMEDI_INPUT + * COMEDI_OUTPUT + * + * encoder: + * Every channel must be configured before reading. + * + * Example code + * + * insn.insn=INSN_CONFIG; //configuration instruction + * insn.n=1; //number of operation (must be 1) + * insn.data=&initialvalue; //initial value loaded into encoder + * //during configuration + * insn.subdev=5; //encoder subdevice + * insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel + * //to configure + * + * comedi_do_insn(cf,&insn); //executing configuration + */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -69,68 +71,91 @@ INSN_CONFIG instructions: #include "comedi_fc.h" #include "s626.h" -#define PCI_VENDOR_ID_S626 0x1131 -#define PCI_DEVICE_ID_S626 0x7146 -#define PCI_SUBVENDOR_ID_S626 0x6000 -#define PCI_SUBDEVICE_ID_S626 0x0272 +struct s626_buffer_dma { + dma_addr_t physical_base; + void *logical_base; +}; struct s626_private { void __iomem *mmio; - uint8_t ai_cmd_running; /* ai_cmd is running */ - uint8_t ai_continous; /* continous acquisition */ - int ai_sample_count; /* number of samples to acquire */ - unsigned int ai_sample_timer; - /* time between samples in units of the timer */ - int ai_convert_count; /* conversion counter */ - unsigned int ai_convert_timer; - /* time between conversion in units of the timer */ - uint16_t CounterIntEnabs; - /* Counter interrupt enable mask for MISC2 register. */ - uint8_t AdcItems; /* Number of items in ADC poll list. */ - struct bufferDMA RPSBuf; /* DMA buffer used to hold ADC (RPS1) program. */ - struct bufferDMA ANABuf; - /* DMA buffer used to receive ADC data and hold DAC data. */ - uint32_t *pDacWBuf; - /* Pointer to logical adrs of DMA buffer used to hold DAC data. */ - uint16_t Dacpol; /* Image of DAC polarity register. */ - uint8_t TrimSetpoint[12]; /* Images of TrimDAC setpoints */ - /* Charge Enabled (0 or WRMISC2_CHARGE_ENABLE). */ - uint32_t I2CAdrs; - /* I2C device address for onboard EEPROM (board rev dependent). */ - /* short I2Cards; */ + uint8_t ai_cmd_running; /* ai_cmd is running */ + uint8_t ai_continuous; /* continuous acquisition */ + int ai_sample_count; /* number of samples to acquire */ + unsigned int ai_sample_timer; /* time between samples in + * units of the timer */ + int ai_convert_count; /* conversion counter */ + unsigned int ai_convert_timer; /* time between conversion in + * units of the timer */ + uint16_t counter_int_enabs; /* counter interrupt enable mask + * for MISC2 register */ + uint8_t adc_items; /* number of items in ADC poll list */ + struct s626_buffer_dma rps_buf; /* DMA buffer used to hold ADC (RPS1) + * program */ + struct s626_buffer_dma ana_buf; /* DMA buffer used to receive ADC data + * and hold DAC data */ + uint32_t *dac_wbuf; /* pointer to logical adrs of DMA buffer + * used to hold DAC data */ + uint16_t dacpol; /* image of DAC polarity register */ + uint8_t trim_setpoint[12]; /* images of TrimDAC setpoints */ + uint32_t i2c_adrs; /* I2C device address for onboard EEPROM + * (board rev dependent) */ unsigned int ao_readback[S626_DAC_CHANNELS]; }; -/* COUNTER OBJECT ------------------------------------------------ */ -struct enc_private { - /* Pointers to functions that differ for A and B counters: */ - uint16_t(*GetEnable) (struct comedi_device *dev, struct enc_private *); /* Return clock enable. */ - uint16_t(*GetIntSrc) (struct comedi_device *dev, struct enc_private *); /* Return interrupt source. */ - uint16_t(*GetLoadTrig) (struct comedi_device *dev, struct enc_private *); /* Return preload trigger source. */ - uint16_t(*GetMode) (struct comedi_device *dev, struct enc_private *); /* Return standardized operating mode. */ - void (*PulseIndex) (struct comedi_device *dev, struct enc_private *); /* Generate soft index strobe. */ - void (*SetEnable) (struct comedi_device *dev, struct enc_private *, uint16_t enab); /* Program clock enable. */ - void (*SetIntSrc) (struct comedi_device *dev, struct enc_private *, uint16_t IntSource); /* Program interrupt source. */ - void (*SetLoadTrig) (struct comedi_device *dev, struct enc_private *, uint16_t Trig); /* Program preload trigger source. */ - void (*SetMode) (struct comedi_device *dev, struct enc_private *, uint16_t Setup, uint16_t DisableIntSrc); /* Program standardized operating mode. */ - void (*ResetCapFlags) (struct comedi_device *dev, struct enc_private *); /* Reset event capture flags. */ - - uint16_t MyCRA; /* Address of CRA register. */ - uint16_t MyCRB; /* Address of CRB register. */ - uint16_t MyLatchLsw; /* Address of Latch least-significant-word */ - /* register. */ - uint16_t MyEventBits[4]; /* Bit translations for IntSrc -->RDMISC2. */ +/* COUNTER OBJECT ------------------------------------------------ */ +struct s626_enc_info { + /* Pointers to functions that differ for A and B counters: */ + /* Return clock enable. */ + uint16_t (*get_enable)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return interrupt source. */ + uint16_t (*get_int_src)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return preload trigger source. */ + uint16_t (*get_load_trig)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return standardized operating mode. */ + uint16_t (*get_mode)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Generate soft index strobe. */ + void (*pulse_index)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Program clock enable. */ + void (*set_enable)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab); + /* Program interrupt source. */ + void (*set_int_src)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t int_source); + /* Program preload trigger source. */ + void (*set_load_trig)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig); + /* Program standardized operating mode. */ + void (*set_mode)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src); + /* Reset event capture flags. */ + void (*reset_cap_flags)(struct comedi_device *dev, + const struct s626_enc_info *k); + + uint16_t my_cra; /* address of CRA register */ + uint16_t my_crb; /* address of CRB register */ + uint16_t my_latch_lsw; /* address of Latch least-significant-word + * register */ + uint16_t my_event_bits[4]; /* bit translations for IntSrc -->RDMISC2 */ }; -#define encpriv ((struct enc_private *)(dev->subdevices+5)->private) +/* Counter overflow/index event flag masks for RDMISC2. */ +#define S626_INDXMASK(C) (1 << (((C) > 2) ? ((C) * 2 - 1) : ((C) * 2 + 4))) +#define S626_OVERMASK(C) (1 << (((C) > 2) ? ((C) * 2 + 5) : ((C) * 2 + 10))) +#define S626_EVBITS(C) { 0, S626_OVERMASK(C), S626_INDXMASK(C), \ + S626_OVERMASK(C) | S626_INDXMASK(C) } -/* Counter overflow/index event flag masks for RDMISC2. */ -#define INDXMASK(C) (1 << (((C) > 2) ? ((C) * 2 - 1) : ((C) * 2 + 4))) -#define OVERMASK(C) (1 << (((C) > 2) ? ((C) * 2 + 5) : ((C) * 2 + 10))) -#define EVBITS(C) { 0, OVERMASK(C), INDXMASK(C), OVERMASK(C) | INDXMASK(C) } - -/* Translation table to map IntSrc into equivalent RDMISC2 event flag bits. */ -/* static const uint16_t EventBits[][4] = { EVBITS(0), EVBITS(1), EVBITS(2), EVBITS(3), EVBITS(4), EVBITS(5) }; */ +/* + * Translation table to map IntSrc into equivalent RDMISC2 event flag bits. + * static const uint16_t s626_event_bits[][4] = + * { S626_EVBITS(0), S626_EVBITS(1), S626_EVBITS(2), S626_EVBITS(3), + * S626_EVBITS(4), S626_EVBITS(5) }; + */ /* * Enable/disable a function or test status bit(s) that are accessed @@ -142,6 +167,7 @@ static void s626_mc_enable(struct comedi_device *dev, struct s626_private *devpriv = dev->private; unsigned int val = (cmd << 16) | cmd; + mmiowb(); writel(val, devpriv->mmio + reg); } @@ -151,6 +177,7 @@ static void s626_mc_disable(struct comedi_device *dev, struct s626_private *devpriv = dev->private; writel(cmd << 16 , devpriv->mmio + reg); + mmiowb(); } static bool s626_mc_test(struct comedi_device *dev, @@ -164,195 +191,265 @@ static bool s626_mc_test(struct comedi_device *dev, return (val & cmd) ? true : false; } -#define BUGFIX_STREG(REGADRS) (REGADRS - 4) - -/* Write a time slot control record to TSL2. */ -#define VECTPORT(VECTNUM) (P_TSL2 + ((VECTNUM) << 2)) +#define S626_BUGFIX_STREG(REGADRS) ((REGADRS) - 4) -/* Code macros used for constructing I2C command bytes. */ -#define I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) -#define I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) -#define I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) +/* Write a time slot control record to TSL2. */ +#define S626_VECTPORT(VECTNUM) (S626_P_TSL2 + ((VECTNUM) << 2)) static const struct comedi_lrange s626_range_table = { 2, { BIP_RANGE(5), - BIP_RANGE(10), + BIP_RANGE(10) } }; -/* Execute a DEBI transfer. This must be called from within a */ -/* critical section. */ -static void DEBItransfer(struct comedi_device *dev) +/* + * Execute a DEBI transfer. This must be called from within a critical section. + */ +static void s626_debi_transfer(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; + static const int timeout = 10000; + int i; /* Initiate upload of shadow RAM to DEBI control register */ - s626_mc_enable(dev, MC2_UPLD_DEBI, P_MC2); + s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2); /* * Wait for completion of upload from shadow RAM to * DEBI control register. */ - while (!s626_mc_test(dev, MC2_UPLD_DEBI, P_MC2)) - ; + for (i = 0; i < timeout; i++) { + if (s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, + "Timeout while uploading to DEBI control register."); /* Wait until DEBI transfer is done */ - while (readl(devpriv->mmio + P_PSR) & PSR_DEBI_S) - ; + for (i = 0; i < timeout; i++) { + if (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, "DEBI transfer timeout."); } -/* Initialize the DEBI interface for all transfers. */ - -static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr) +/* + * Read a value from a gate array register. + */ +static uint16_t s626_debi_read(struct comedi_device *dev, uint16_t addr) { struct s626_private *devpriv = dev->private; /* Set up DEBI control register value in shadow RAM */ - writel(DEBI_CMD_RDWORD | addr, devpriv->mmio + P_DEBICMD); + writel(S626_DEBI_CMD_RDWORD | addr, devpriv->mmio + S626_P_DEBICMD); /* Execute the DEBI transfer. */ - DEBItransfer(dev); + s626_debi_transfer(dev); - return readl(devpriv->mmio + P_DEBIAD); + return readl(devpriv->mmio + S626_P_DEBIAD); } -/* Write a value to a gate array register. */ -static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata) +/* + * Write a value to a gate array register. + */ +static void s626_debi_write(struct comedi_device *dev, uint16_t addr, + uint16_t wdata) { struct s626_private *devpriv = dev->private; /* Set up DEBI control register value in shadow RAM */ - writel(DEBI_CMD_WRWORD | addr, devpriv->mmio + P_DEBICMD); - writel(wdata, devpriv->mmio + P_DEBIAD); + writel(S626_DEBI_CMD_WRWORD | addr, devpriv->mmio + S626_P_DEBICMD); + writel(wdata, devpriv->mmio + S626_P_DEBIAD); /* Execute the DEBI transfer. */ - DEBItransfer(dev); + s626_debi_transfer(dev); } -/* Replace the specified bits in a gate array register. Imports: mask +/* + * Replace the specified bits in a gate array register. Imports: mask * specifies bits that are to be preserved, wdata is new value to be * or'd with the masked original. */ -static void DEBIreplace(struct comedi_device *dev, unsigned int addr, - unsigned int mask, unsigned int wdata) +static void s626_debi_replace(struct comedi_device *dev, unsigned int addr, + unsigned int mask, unsigned int wdata) { struct s626_private *devpriv = dev->private; unsigned int val; addr &= 0xffff; - writel(DEBI_CMD_RDWORD | addr, devpriv->mmio + P_DEBICMD); - DEBItransfer(dev); + writel(S626_DEBI_CMD_RDWORD | addr, devpriv->mmio + S626_P_DEBICMD); + s626_debi_transfer(dev); - writel(DEBI_CMD_WRWORD | addr, devpriv->mmio + P_DEBICMD); - val = readl(devpriv->mmio + P_DEBIAD); + writel(S626_DEBI_CMD_WRWORD | addr, devpriv->mmio + S626_P_DEBICMD); + val = readl(devpriv->mmio + S626_P_DEBIAD); val &= mask; val |= wdata; - writel(val & 0xffff, devpriv->mmio + P_DEBIAD); - DEBItransfer(dev); + writel(val & 0xffff, devpriv->mmio + S626_P_DEBIAD); + s626_debi_transfer(dev); } /* ************** EEPROM ACCESS FUNCTIONS ************** */ -static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val) +static int s626_i2c_handshake_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + bool status; + + status = s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + if (status) + return 0; + return -EBUSY; +} + +static int s626_i2c_handshake(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; unsigned int ctrl; + int ret; /* Write I2C command to I2C Transfer Control shadow register */ - writel(val, devpriv->mmio + P_I2CCTRL); + writel(val, devpriv->mmio + S626_P_I2CCTRL); /* * Upload I2C shadow registers into working registers and * wait for upload confirmation. */ - s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2); - while (!s626_mc_test(dev, MC2_UPLD_IIC, P_MC2)) - ; + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; /* Wait until I2C bus transfer is finished or an error occurs */ do { - ctrl = readl(devpriv->mmio + P_I2CCTRL); - } while ((ctrl & (I2C_BUSY | I2C_ERR)) == I2C_BUSY); + ctrl = readl(devpriv->mmio + S626_P_I2CCTRL); + } while ((ctrl & (S626_I2C_BUSY | S626_I2C_ERR)) == S626_I2C_BUSY); /* Return non-zero if I2C error occurred */ - return ctrl & I2C_ERR; + return ctrl & S626_I2C_ERR; } -/* Read uint8_t from EEPROM. */ -static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr) +/* Read uint8_t from EEPROM. */ +static uint8_t s626_i2c_read(struct comedi_device *dev, uint8_t addr) { struct s626_private *devpriv = dev->private; - /* Send EEPROM target address. */ - if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW) - /* Byte2 = I2C command: write to I2C EEPROM device. */ - | I2C_B1(I2C_ATTRSTOP, addr) - /* Byte1 = EEPROM internal target address. */ - | I2C_B0(I2C_ATTRNOP, 0))) { /* Byte0 = Not sent. */ - /* Abort function and declare error if handshake failed. */ + /* + * Send EEPROM target address: + * Byte2 = I2C command: write to I2C EEPROM device. + * Byte1 = EEPROM internal target address. + * Byte0 = Not sent. + */ + if (s626_i2c_handshake(dev, S626_I2C_B2(S626_I2C_ATTRSTART, + devpriv->i2c_adrs) | + S626_I2C_B1(S626_I2C_ATTRSTOP, addr) | + S626_I2C_B0(S626_I2C_ATTRNOP, 0))) + /* Abort function and declare error if handshake failed. */ return 0; - } - /* Execute EEPROM read. */ - if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CR) - - /* Byte2 = I2C */ - /* command: read */ - /* from I2C EEPROM */ - /* device. */ - |I2C_B1(I2C_ATTRSTOP, 0) - - /* Byte1 receives */ - /* uint8_t from */ - /* EEPROM. */ - |I2C_B0(I2C_ATTRNOP, 0))) { /* Byte0 = Not sent. */ - /* Abort function and declare error if handshake failed. */ + /* + * Execute EEPROM read: + * Byte2 = I2C command: read from I2C EEPROM device. + * Byte1 receives uint8_t from EEPROM. + * Byte0 = Not sent. + */ + if (s626_i2c_handshake(dev, S626_I2C_B2(S626_I2C_ATTRSTART, + (devpriv->i2c_adrs | 1)) | + S626_I2C_B1(S626_I2C_ATTRSTOP, 0) | + S626_I2C_B0(S626_I2C_ATTRNOP, 0))) + /* Abort function and declare error if handshake failed. */ return 0; - } - return (readl(devpriv->mmio + P_I2CCTRL) >> 16) & 0xff; + return (readl(devpriv->mmio + S626_P_I2CCTRL) >> 16) & 0xff; } /* *********** DAC FUNCTIONS *********** */ -/* Slot 0 base settings. */ -#define VECT0 (XSD2 | RSD3 | SIB_A2) -/* Slot 0 always shifts in 0xFF and store it to FB_BUFFER2. */ +/* TrimDac LogicalChan-to-PhysicalChan mapping table. */ +static const uint8_t s626_trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 }; + +/* TrimDac LogicalChan-to-EepromAdrs mapping table. */ +static const uint8_t s626_trimadrs[] = { + 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 +}; + +enum { + s626_send_dac_wait_not_mc1_a2out, + s626_send_dac_wait_ssr_af2_out, + s626_send_dac_wait_fb_buffer2_msb_00, + s626_send_dac_wait_fb_buffer2_msb_ff +}; -/* TrimDac LogicalChan-to-PhysicalChan mapping table. */ -static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 }; +static int s626_send_dac_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; -/* TrimDac LogicalChan-to-EepromAdrs mapping table. */ -static uint8_t trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 }; + switch (context) { + case s626_send_dac_wait_not_mc1_a2out: + status = readl(devpriv->mmio + S626_P_MC1); + if (!(status & S626_MC1_A2OUT)) + return 0; + break; + case s626_send_dac_wait_ssr_af2_out: + status = readl(devpriv->mmio + S626_P_SSR); + if (status & S626_SSR_AF2_OUT) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_00: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (!(status & 0xff000000)) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_ff: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (status & 0xff000000) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} -/* Private helper function: Transmit serial data to DAC via Audio +/* + * Private helper function: Transmit serial data to DAC via Audio * channel 2. Assumes: (1) TSL2 slot records initialized, and (2) - * Dacpol contains valid target image. + * dacpol contains valid target image. */ -static void SendDAC(struct comedi_device *dev, uint32_t val) +static int s626_send_dac(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; + int ret; /* START THE SERIAL CLOCK RUNNING ------------- */ - /* Assert DAC polarity control and enable gating of DAC serial clock + /* + * Assert DAC polarity control and enable gating of DAC serial clock * and audio bit stream signals. At this point in time we must be * assured of being in time slot 0. If we are not in slot 0, the * serial clock and audio stream signals will be disabled; this is - * because the following DEBIwrite statement (which enables signals - * to be passed through the gate array) would execute before the - * trailing edge of WS1/WS3 (which turns off the signals), thus + * because the following s626_debi_write statement (which enables + * signals to be passed through the gate array) would execute before + * the trailing edge of WS1/WS3 (which turns off the signals), thus * causing the signals to be inactive during the DAC write. */ - DEBIwrite(dev, LP_DACPOL, devpriv->Dacpol); + s626_debi_write(dev, S626_LP_DACPOL, devpriv->dacpol); /* TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ---------------- */ /* Copy DAC setpoint value to DAC's output DMA buffer. */ - - /* writel(val, devpriv->mmio + (uint32_t)devpriv->pDacWBuf); */ - *devpriv->pDacWBuf = val; + /* writel(val, devpriv->mmio + (uint32_t)devpriv->dac_wbuf); */ + *devpriv->dac_wbuf = val; /* * Enable the output DMA transfer. This will cause the DMAC to copy @@ -360,56 +457,70 @@ static void SendDAC(struct comedi_device *dev, uint32_t val) * then immediately terminate because the protection address is * reached upon transfer of the first DWORD value. */ - s626_mc_enable(dev, MC1_A2OUT, P_MC1); + s626_mc_enable(dev, S626_MC1_A2OUT, S626_P_MC1); - /* While the DMA transfer is executing ... */ + /* While the DMA transfer is executing ... */ /* * Reset Audio2 output FIFO's underflow flag (along with any * other FIFO underflow/overflow flags). When set, this flag * will indicate that we have emerged from slot 0. */ - writel(ISR_AFOU, devpriv->mmio + P_ISR); + writel(S626_ISR_AFOU, devpriv->mmio + S626_P_ISR); - /* Wait for the DMA transfer to finish so that there will be data + /* + * Wait for the DMA transfer to finish so that there will be data * available in the FIFO when time slot 1 tries to transfer a DWORD * from the FIFO to the output buffer register. We test for DMA * Done by polling the DMAC enable flag; this flag is automatically * cleared when the transfer has finished. */ - while (readl(devpriv->mmio + P_MC1) & MC1_A2OUT) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_not_mc1_a2out); + if (ret) { + comedi_error(dev, "DMA transfer timeout."); + return ret; + } /* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */ - /* FIFO data is now available, so we enable execution of time slots + /* + * FIFO data is now available, so we enable execution of time slots * 1 and higher by clearing the EOS flag in slot 0. Note that SD3 * will be shifted in and stored in FB_BUFFER2 for end-of-slot-list * detection. */ - writel(XSD2 | RSD3 | SIB_A2, devpriv->mmio + VECTPORT(0)); + writel(S626_XSD2 | S626_RSD3 | S626_SIB_A2, + devpriv->mmio + S626_VECTPORT(0)); - /* Wait for slot 1 to execute to ensure that the Packet will be + /* + * Wait for slot 1 to execute to ensure that the Packet will be * transmitted. This is detected by polling the Audio2 output FIFO * underflow flag, which will be set when slot 1 execution has * finished transferring the DAC's data DWORD from the output FIFO * to the output buffer register. */ - while (!(readl(devpriv->mmio + P_SSR) & SSR_AF2_OUT)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_ssr_af2_out); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 1 to execute."); + return ret; + } - /* Set up to trap execution at slot 0 when the TSL sequencer cycles + /* + * Set up to trap execution at slot 0 when the TSL sequencer cycles * back to slot 0 after executing the EOS in slot 5. Also, * simultaneously shift out and in the 0x00 that is ALWAYS the value * stored in the last byte to be shifted out of the FIFO's DWORD * buffer register. */ - writel(XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS, - devpriv->mmio + VECTPORT(0)); + writel(S626_XSD2 | S626_XFIFO_2 | S626_RSD2 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); /* WAIT FOR THE TRANSACTION TO FINISH ----------------------- */ - /* Wait for the TSL to finish executing all time slots before + /* + * Wait for the TSL to finish executing all time slots before * exiting this function. We must do this so that the next DAC * write doesn't start, thereby enabling clock/chip select signals: * @@ -426,17 +537,24 @@ static void SendDAC(struct comedi_device *dev, uint32_t val) * we test for the FB_BUFFER2 MSB contents to be equal to 0xFF. If * the TSL has not yet finished executing slot 5 ... */ - if (readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000) { - /* The trap was set on time and we are still executing somewhere + if (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000) { + /* + * The trap was set on time and we are still executing somewhere * in slots 2-5, so we now wait for slot 0 to execute and trap * TSL execution. This is detected when FB_BUFFER2 MSB changes * from 0xFF to 0x00, which slot 0 causes to happen by shifting * out/in on SD2 the 0x00 that is always referenced by slot 5. */ - while (readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_00); + if (ret) { + comedi_error(dev, + "TSL timeout waiting for slot 0 to execute."); + return ret; + } } - /* Either (1) we were too late setting the slot 0 trap; the TSL + /* + * Either (1) we were too late setting the slot 0 trap; the TSL * sequencer restarted slot 0 before we could set the EOS trap flag, * or (2) we were not late and execution is now trapped at slot 0. * In either case, we must now change slot 0 so that it will store @@ -444,37 +562,51 @@ static void SendDAC(struct comedi_device *dev, uint32_t val) * In order to do this, we reprogram slot 0 so that it will shift in * SD3, which is driven only by a pull-up resistor. */ - writel(RSD3 | SIB_A2 | EOS, devpriv->mmio + VECTPORT(0)); + writel(S626_RSD3 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); - /* Wait for slot 0 to execute, at which time the TSL is setup for + /* + * Wait for slot 0 to execute, at which time the TSL is setup for * the next DAC write. This is detected when FB_BUFFER2 MSB changes * from 0x00 to 0xFF. */ - while (!(readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_ff); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 0 to execute."); + return ret; + } + return 0; } -/* Private helper function: Write setpoint to an application DAC channel. */ -static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata) +/* + * Private helper function: Write setpoint to an application DAC channel. + */ +static int s626_set_dac(struct comedi_device *dev, uint16_t chan, + int16_t dacdata) { struct s626_private *devpriv = dev->private; - register uint16_t signmask; - register uint32_t WSImage; + uint16_t signmask; + uint32_t ws_image; + uint32_t val; - /* Adjust DAC data polarity and set up Polarity Control Register */ - /* image. */ + /* + * Adjust DAC data polarity and set up Polarity Control Register image. + */ signmask = 1 << chan; if (dacdata < 0) { dacdata = -dacdata; - devpriv->Dacpol |= signmask; - } else - devpriv->Dacpol &= ~signmask; + devpriv->dacpol |= signmask; + } else { + devpriv->dacpol &= ~signmask; + } - /* Limit DAC setpoint value to valid range. */ - if ((uint16_t) dacdata > 0x1FFF) + /* Limit DAC setpoint value to valid range. */ + if ((uint16_t)dacdata > 0x1FFF) dacdata = 0x1FFF; - /* Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 + /* + * Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 * and V3 transmit the setpoint to the target DAC. V4 and V5 send * data to a non-existent TrimDac channel just to keep the clock * running after sending data to the target DAC. This is necessary @@ -485,140 +617,797 @@ static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata) */ /* Choose DAC chip select to be asserted */ - WSImage = (chan & 2) ? WS1 : WS2; + ws_image = (chan & 2) ? S626_WS1 : S626_WS2; /* Slot 2: Transmit high data byte to target DAC */ - writel(XSD2 | XFIFO_1 | WSImage, devpriv->mmio + VECTPORT(2)); + writel(S626_XSD2 | S626_XFIFO_1 | ws_image, + devpriv->mmio + S626_VECTPORT(2)); /* Slot 3: Transmit low data byte to target DAC */ - writel(XSD2 | XFIFO_0 | WSImage, devpriv->mmio + VECTPORT(3)); + writel(S626_XSD2 | S626_XFIFO_0 | ws_image, + devpriv->mmio + S626_VECTPORT(3)); /* Slot 4: Transmit to non-existent TrimDac channel to keep clock */ - writel(XSD2 | XFIFO_3 | WS3, devpriv->mmio + VECTPORT(4)); + writel(S626_XSD2 | S626_XFIFO_3 | S626_WS3, + devpriv->mmio + S626_VECTPORT(4)); /* Slot 5: running after writing target DAC's low data byte */ - writel(XSD2 | XFIFO_2 | WS3 | EOS, devpriv->mmio + VECTPORT(5)); + writel(S626_XSD2 | S626_XFIFO_2 | S626_WS3 | S626_EOS, + devpriv->mmio + S626_VECTPORT(5)); - /* Construct and transmit target DAC's serial packet: - * ( A10D DDDD ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>, + /* + * Construct and transmit target DAC's serial packet: + * (A10D DDDD), (DDDD DDDD), (0x0F), (0x00) where A is chan<0>, * and D<12:0> is the DAC setpoint. Append a WORD value (that writes * to a non-existent TrimDac channel) that serves to keep the clock * running after the packet has been sent to the target DAC. */ - SendDAC(dev, 0x0F000000 - /* Continue clock after target DAC data (write to non-existent trimdac). */ - | 0x00004000 - /* Address the two main dual-DAC devices (TSL's chip select enables - * target device). */ - | ((uint32_t) (chan & 1) << 15) - /* Address the DAC channel within the device. */ - | (uint32_t) dacdata); /* Include DAC setpoint data. */ - + val = 0x0F000000; /* Continue clock after target DAC data + * (write to non-existent trimdac). */ + val |= 0x00004000; /* Address the two main dual-DAC devices + * (TSL's chip select enables target device). */ + val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel + * within the device. */ + val |= (uint32_t)dacdata; /* Include DAC setpoint data. */ + return s626_send_dac(dev, val); } -static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan, - uint8_t DacData) +static int s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, + uint8_t dac_data) { struct s626_private *devpriv = dev->private; uint32_t chan; - /* Save the new setpoint in case the application needs to read it back later. */ - devpriv->TrimSetpoint[LogicalChan] = (uint8_t) DacData; + /* + * Save the new setpoint in case the application needs to read it back + * later. + */ + devpriv->trim_setpoint[logical_chan] = (uint8_t)dac_data; - /* Map logical channel number to physical channel number. */ - chan = (uint32_t) trimchan[LogicalChan]; + /* Map logical channel number to physical channel number. */ + chan = s626_trimchan[logical_chan]; - /* Set up TSL2 records for TrimDac write operation. All slots shift + /* + * Set up TSL2 records for TrimDac write operation. All slots shift * 0xFF in from pulled-up SD3 so that the end of the slot sequence * can be detected. */ /* Slot 2: Send high uint8_t to target TrimDac */ - writel(XSD2 | XFIFO_1 | WS3, devpriv->mmio + VECTPORT(2)); + writel(S626_XSD2 | S626_XFIFO_1 | S626_WS3, + devpriv->mmio + S626_VECTPORT(2)); /* Slot 3: Send low uint8_t to target TrimDac */ - writel(XSD2 | XFIFO_0 | WS3, devpriv->mmio + VECTPORT(3)); + writel(S626_XSD2 | S626_XFIFO_0 | S626_WS3, + devpriv->mmio + S626_VECTPORT(3)); /* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running */ - writel(XSD2 | XFIFO_3 | WS1, devpriv->mmio + VECTPORT(4)); + writel(S626_XSD2 | S626_XFIFO_3 | S626_WS1, + devpriv->mmio + S626_VECTPORT(4)); /* Slot 5: Send NOP low uint8_t to DAC0 */ - writel(XSD2 | XFIFO_2 | WS1 | EOS, devpriv->mmio + VECTPORT(5)); + writel(S626_XSD2 | S626_XFIFO_2 | S626_WS1 | S626_EOS, + devpriv->mmio + S626_VECTPORT(5)); - /* Construct and transmit target DAC's serial packet: - * ( 0000 AAAA ), ( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the + /* + * Construct and transmit target DAC's serial packet: + * (0000 AAAA), (DDDD DDDD), (0x00), (0x00) where A<3:0> is the * DAC channel's address, and D<7:0> is the DAC setpoint. Append a * WORD value (that writes a channel 0 NOP command to a non-existent * main DAC channel) that serves to keep the clock running after the * packet has been sent to the target DAC. */ - /* Address the DAC channel within the trimdac device. */ - SendDAC(dev, ((uint32_t) chan << 8) - | (uint32_t) DacData); /* Include DAC setpoint data. */ + /* + * Address the DAC channel within the trimdac device. + * Include DAC setpoint data. + */ + return s626_send_dac(dev, (chan << 8) | dac_data); } -static void LoadTrimDACs(struct comedi_device *dev) +static int s626_load_trim_dacs(struct comedi_device *dev) { - register uint8_t i; + uint8_t i; + int ret; - /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ - for (i = 0; i < ARRAY_SIZE(trimchan); i++) - WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i])); + /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ + for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) { + ret = s626_write_trim_dac(dev, i, + s626_i2c_read(dev, s626_trimadrs[i])); + if (ret) + return ret; + } + return 0; } /* ****** COUNTER FUNCTIONS ******* */ -/* All counter functions address a specific counter by means of the + +/* + * All counter functions address a specific counter by means of the * "Counter" argument, which is a logical counter number. The Counter * argument may have any of the following legal values: 0=0A, 1=1A, * 2=2A, 3=0B, 4=1B, 5=2B. */ -/* Read a counter's output latch. */ -static uint32_t ReadLatch(struct comedi_device *dev, struct enc_private *k) +/* + * Read a counter's output latch. + */ +static uint32_t s626_read_latch(struct comedi_device *dev, + const struct s626_enc_info *k) { - register uint32_t value; + uint32_t value; - /* Latch counts and fetch LSW of latched counts value. */ - value = (uint32_t) DEBIread(dev, k->MyLatchLsw); + /* Latch counts and fetch LSW of latched counts value. */ + value = s626_debi_read(dev, k->my_latch_lsw); - /* Fetch MSW of latched counts and combine with LSW. */ - value |= ((uint32_t) DEBIread(dev, k->MyLatchLsw + 2) << 16); + /* Fetch MSW of latched counts and combine with LSW. */ + value |= ((uint32_t)s626_debi_read(dev, k->my_latch_lsw + 2) << 16); - /* Return latched counts. */ + /* Return latched counts. */ return value; } -/* Return/set a counter pair's latch trigger source. 0: On read +/* + * Return/set a counter pair's latch trigger source. 0: On read * access, 1: A index latches A, 2: B index latches B, 3: A overflow * latches B. */ -static void SetLatchSource(struct comedi_device *dev, struct enc_private *k, - uint16_t value) +static void s626_set_latch_source(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_LATCHSRC), + S626_SET_CRB_LATCHSRC(value)); +} + +/* + * Write value into counter preload register. + */ +static void s626_preload(struct comedi_device *dev, + const struct s626_enc_info *k, uint32_t value) { - DEBIreplace(dev, k->MyCRB, - ~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC), - value << CRBBIT_LATCHSRC); + s626_debi_write(dev, k->my_latch_lsw, value); + s626_debi_write(dev, k->my_latch_lsw + 2, value >> 16); } -/* Write value into counter preload register. */ -static void Preload(struct comedi_device *dev, struct enc_private *k, - uint32_t value) +/* ****** PRIVATE COUNTER FUNCTIONS ****** */ + +/* + * Reset a counter's index and overflow event capture flags. + */ +static void s626_reset_cap_flags_a(struct comedi_device *dev, + const struct s626_enc_info *k) { - DEBIwrite(dev, (uint16_t) (k->MyLatchLsw), (uint16_t) value); - DEBIwrite(dev, (uint16_t) (k->MyLatchLsw + 2), - (uint16_t) (value >> 16)); + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + (S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_A(1))); } -static unsigned int s626_ai_reg_to_uint(int data) +static void s626_reset_cap_flags_b(struct comedi_device *dev, + const struct s626_enc_info *k) { - unsigned int tempdata; + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + (S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_B(1))); +} - tempdata = (data >> 18); - if (tempdata & 0x2000) - tempdata &= 0x1fff; - else - tempdata += (1 << 13); +/* + * Return counter setup in a format (COUNTER_SETUP) that is consistent + * for both A and B counters. + */ +static uint16_t s626_get_mode_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; + uint16_t crb; + uint16_t setup; + unsigned cntsrc, clkmult, clkpol, encmode; + + /* Fetch CRA and CRB register images. */ + cra = s626_debi_read(dev, k->my_cra); + crb = s626_debi_read(dev, k->my_crb); + + /* + * Populate the standardized counter setup bit fields. + */ + setup = + /* LoadSrc = LoadSrcA. */ + S626_SET_STD_LOADSRC(S626_GET_CRA_LOADSRC_A(cra)) | + /* LatchSrc = LatchSrcA. */ + S626_SET_STD_LATCHSRC(S626_GET_CRB_LATCHSRC(crb)) | + /* IntSrc = IntSrcA. */ + S626_SET_STD_INTSRC(S626_GET_CRA_INTSRC_A(cra)) | + /* IndxSrc = IndxSrcA. */ + S626_SET_STD_INDXSRC(S626_GET_CRA_INDXSRC_A(cra)) | + /* IndxPol = IndxPolA. */ + S626_SET_STD_INDXPOL(S626_GET_CRA_INDXPOL_A(cra)) | + /* ClkEnab = ClkEnabA. */ + S626_SET_STD_CLKENAB(S626_GET_CRB_CLKENAB_A(crb)); + + /* Adjust mode-dependent parameters. */ + cntsrc = S626_GET_CRA_CNTSRC_A(cra); + if (cntsrc & S626_CNTSRC_SYSCLK) { + /* Timer mode (CntSrcA<1> == 1): */ + encmode = S626_ENCMODE_TIMER; + /* Set ClkPol to indicate count direction (CntSrcA<0>). */ + clkpol = cntsrc & 1; + /* ClkMult must be 1x in Timer mode. */ + clkmult = S626_CLKMULT_1X; + } else { + /* Counter mode (CntSrcA<1> == 0): */ + encmode = S626_ENCMODE_COUNTER; + /* Pass through ClkPol. */ + clkpol = S626_GET_CRA_CLKPOL_A(cra); + /* Force ClkMult to 1x if not legal, else pass through. */ + clkmult = S626_GET_CRA_CLKMULT_A(cra); + if (clkmult == S626_CLKMULT_SPECIAL) + clkmult = S626_CLKMULT_1X; + } + setup |= S626_SET_STD_ENCMODE(encmode) | S626_SET_STD_CLKMULT(clkmult) | + S626_SET_STD_CLKPOL(clkpol); + + /* Return adjusted counter setup. */ + return setup; +} + +static uint16_t s626_get_mode_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; + uint16_t crb; + uint16_t setup; + unsigned cntsrc, clkmult, clkpol, encmode; + + /* Fetch CRA and CRB register images. */ + cra = s626_debi_read(dev, k->my_cra); + crb = s626_debi_read(dev, k->my_crb); + + /* + * Populate the standardized counter setup bit fields. + */ + setup = + /* IntSrc = IntSrcB. */ + S626_SET_STD_INTSRC(S626_GET_CRB_INTSRC_B(crb)) | + /* LatchSrc = LatchSrcB. */ + S626_SET_STD_LATCHSRC(S626_GET_CRB_LATCHSRC(crb)) | + /* LoadSrc = LoadSrcB. */ + S626_SET_STD_LOADSRC(S626_GET_CRB_LOADSRC_B(crb)) | + /* IndxPol = IndxPolB. */ + S626_SET_STD_INDXPOL(S626_GET_CRB_INDXPOL_B(crb)) | + /* ClkEnab = ClkEnabB. */ + S626_SET_STD_CLKENAB(S626_GET_CRB_CLKENAB_B(crb)) | + /* IndxSrc = IndxSrcB. */ + S626_SET_STD_INDXSRC(S626_GET_CRA_INDXSRC_B(cra)); + + /* Adjust mode-dependent parameters. */ + cntsrc = S626_GET_CRA_CNTSRC_B(cra); + clkmult = S626_GET_CRB_CLKMULT_B(crb); + if (clkmult == S626_CLKMULT_SPECIAL) { + /* Extender mode (ClkMultB == S626_CLKMULT_SPECIAL): */ + encmode = S626_ENCMODE_EXTENDER; + /* Indicate multiplier is 1x. */ + clkmult = S626_CLKMULT_1X; + /* Set ClkPol equal to Timer count direction (CntSrcB<0>). */ + clkpol = cntsrc & 1; + } else if (cntsrc & S626_CNTSRC_SYSCLK) { + /* Timer mode (CntSrcB<1> == 1): */ + encmode = S626_ENCMODE_TIMER; + /* Indicate multiplier is 1x. */ + clkmult = S626_CLKMULT_1X; + /* Set ClkPol equal to Timer count direction (CntSrcB<0>). */ + clkpol = cntsrc & 1; + } else { + /* If Counter mode (CntSrcB<1> == 0): */ + encmode = S626_ENCMODE_COUNTER; + /* Clock multiplier is passed through. */ + /* Clock polarity is passed through. */ + clkpol = S626_GET_CRB_CLKPOL_B(crb); + } + setup |= S626_SET_STD_ENCMODE(encmode) | S626_SET_STD_CLKMULT(clkmult) | + S626_SET_STD_CLKPOL(clkpol); + + /* Return adjusted counter setup. */ + return setup; +} + +/* + * Set the operating mode for the specified counter. The setup + * parameter is treated as a COUNTER_SETUP data type. The following + * parameters are programmable (all other parms are ignored): ClkMult, + * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc. + */ +static void s626_set_mode_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src) +{ + struct s626_private *devpriv = dev->private; + uint16_t cra; + uint16_t crb; + unsigned cntsrc, clkmult, clkpol; + + /* Initialize CRA and CRB images. */ + /* Preload trigger is passed through. */ + cra = S626_SET_CRA_LOADSRC_A(S626_GET_STD_LOADSRC(setup)); + /* IndexSrc is passed through. */ + cra |= S626_SET_CRA_INDXSRC_A(S626_GET_STD_INDXSRC(setup)); + + /* Reset any pending CounterA event captures. */ + crb = S626_SET_CRB_INTRESETCMD(1) | S626_SET_CRB_INTRESET_A(1); + /* Clock enable is passed through. */ + crb |= S626_SET_CRB_CLKENAB_A(S626_GET_STD_CLKENAB(setup)); + + /* Force IntSrc to Disabled if disable_int_src is asserted. */ + if (!disable_int_src) + cra |= S626_SET_CRA_INTSRC_A(S626_GET_STD_INTSRC(setup)); + + /* Populate all mode-dependent attributes of CRA & CRB images. */ + clkpol = S626_GET_STD_CLKPOL(setup); + switch (S626_GET_STD_ENCMODE(setup)) { + case S626_ENCMODE_EXTENDER: /* Extender Mode: */ + /* Force to Timer mode (Extender valid only for B counters). */ + /* Fall through to case S626_ENCMODE_TIMER: */ + case S626_ENCMODE_TIMER: /* Timer Mode: */ + /* CntSrcA<1> selects system clock */ + cntsrc = S626_CNTSRC_SYSCLK; + /* Count direction (CntSrcA<0>) obtained from ClkPol. */ + cntsrc |= clkpol; + /* ClkPolA behaves as always-on clock enable. */ + clkpol = 1; + /* ClkMult must be 1x. */ + clkmult = S626_CLKMULT_1X; + break; + default: /* Counter Mode: */ + /* Select ENC_C and ENC_D as clock/direction inputs. */ + cntsrc = S626_CNTSRC_ENCODER; + /* Clock polarity is passed through. */ + /* Force multiplier to x1 if not legal, else pass through. */ + clkmult = S626_GET_STD_CLKMULT(setup); + if (clkmult == S626_CLKMULT_SPECIAL) + clkmult = S626_CLKMULT_1X; + break; + } + cra |= S626_SET_CRA_CNTSRC_A(cntsrc) | S626_SET_CRA_CLKPOL_A(clkpol) | + S626_SET_CRA_CLKMULT_A(clkmult); + + /* + * Force positive index polarity if IndxSrc is software-driven only, + * otherwise pass it through. + */ + if (S626_GET_STD_INDXSRC(setup) != S626_INDXSRC_SOFT) + cra |= S626_SET_CRA_INDXPOL_A(S626_GET_STD_INDXPOL(setup)); + + /* + * If IntSrc has been forced to Disabled, update the MISC2 interrupt + * enable mask to indicate the counter interrupt is disabled. + */ + if (disable_int_src) + devpriv->counter_int_enabs &= ~k->my_event_bits[3]; + + /* + * While retaining CounterB and LatchSrc configurations, program the + * new counter operating mode. + */ + s626_debi_replace(dev, k->my_cra, + S626_CRAMSK_INDXSRC_B | S626_CRAMSK_CNTSRC_B, cra); + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_A), crb); +} + +static void s626_set_mode_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src) +{ + struct s626_private *devpriv = dev->private; + uint16_t cra; + uint16_t crb; + unsigned cntsrc, clkmult, clkpol; + + /* Initialize CRA and CRB images. */ + /* IndexSrc is passed through. */ + cra = S626_SET_CRA_INDXSRC_B(S626_GET_STD_INDXSRC(setup)); + + /* Reset event captures and disable interrupts. */ + crb = S626_SET_CRB_INTRESETCMD(1) | S626_SET_CRB_INTRESET_B(1); + /* Clock enable is passed through. */ + crb |= S626_SET_CRB_CLKENAB_B(S626_GET_STD_CLKENAB(setup)); + /* Preload trigger source is passed through. */ + crb |= S626_SET_CRB_LOADSRC_B(S626_GET_STD_LOADSRC(setup)); + + /* Force IntSrc to Disabled if disable_int_src is asserted. */ + if (!disable_int_src) + crb |= S626_SET_CRB_INTSRC_B(S626_GET_STD_INTSRC(setup)); + + /* Populate all mode-dependent attributes of CRA & CRB images. */ + clkpol = S626_GET_STD_CLKPOL(setup); + switch (S626_GET_STD_ENCMODE(setup)) { + case S626_ENCMODE_TIMER: /* Timer Mode: */ + /* CntSrcB<1> selects system clock */ + cntsrc = S626_CNTSRC_SYSCLK; + /* with direction (CntSrcB<0>) obtained from ClkPol. */ + cntsrc |= clkpol; + /* ClkPolB behaves as always-on clock enable. */ + clkpol = 1; + /* ClkMultB must be 1x. */ + clkmult = S626_CLKMULT_1X; + break; + case S626_ENCMODE_EXTENDER: /* Extender Mode: */ + /* CntSrcB source is OverflowA (same as "timer") */ + cntsrc = S626_CNTSRC_SYSCLK; + /* with direction obtained from ClkPol. */ + cntsrc |= clkpol; + /* ClkPolB controls IndexB -- always set to active. */ + clkpol = 1; + /* ClkMultB selects OverflowA as the clock source. */ + clkmult = S626_CLKMULT_SPECIAL; + break; + default: /* Counter Mode: */ + /* Select ENC_C and ENC_D as clock/direction inputs. */ + cntsrc = S626_CNTSRC_ENCODER; + /* ClkPol is passed through. */ + /* Force ClkMult to x1 if not legal, otherwise pass through. */ + clkmult = S626_GET_STD_CLKMULT(setup); + if (clkmult == S626_CLKMULT_SPECIAL) + clkmult = S626_CLKMULT_1X; + break; + } + cra |= S626_SET_CRA_CNTSRC_B(cntsrc); + crb |= S626_SET_CRB_CLKPOL_B(clkpol) | S626_SET_CRB_CLKMULT_B(clkmult); + + /* + * Force positive index polarity if IndxSrc is software-driven only, + * otherwise pass it through. + */ + if (S626_GET_STD_INDXSRC(setup) != S626_INDXSRC_SOFT) + crb |= S626_SET_CRB_INDXPOL_B(S626_GET_STD_INDXPOL(setup)); + + /* + * If IntSrc has been forced to Disabled, update the MISC2 interrupt + * enable mask to indicate the counter interrupt is disabled. + */ + if (disable_int_src) + devpriv->counter_int_enabs &= ~k->my_event_bits[3]; + + /* + * While retaining CounterA and LatchSrc configurations, program the + * new counter operating mode. + */ + s626_debi_replace(dev, k->my_cra, + ~(S626_CRAMSK_INDXSRC_B | S626_CRAMSK_CNTSRC_B), cra); + s626_debi_replace(dev, k->my_crb, + S626_CRBMSK_CLKENAB_A | S626_CRBMSK_LATCHSRC, crb); +} + +/* + * Return/set a counter's enable. enab: 0=always enabled, 1=enabled by index. + */ +static void s626_set_enable_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_A), + S626_SET_CRB_CLKENAB_A(enab)); +} + +static void s626_set_enable_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_B), + S626_SET_CRB_CLKENAB_B(enab)); +} + +static uint16_t s626_get_enable_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_CLKENAB_A(s626_debi_read(dev, k->my_crb)); +} + +static uint16_t s626_get_enable_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_CLKENAB_B(s626_debi_read(dev, k->my_crb)); +} + +#ifdef unused +static uint16_t s626_get_latch_source(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_LATCHSRC(s626_debi_read(dev, k->my_crb)); +} +#endif + +/* + * Return/set the event that will trigger transfer of the preload + * register into the counter. 0=ThisCntr_Index, 1=ThisCntr_Overflow, + * 2=OverflowA (B counters only), 3=disabled. + */ +static void s626_set_load_trig_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig) +{ + s626_debi_replace(dev, k->my_cra, ~S626_CRAMSK_LOADSRC_A, + S626_SET_CRA_LOADSRC_A(trig)); +} + +static void s626_set_load_trig_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_LOADSRC_B | S626_CRBMSK_INTCTRL), + S626_SET_CRB_LOADSRC_B(trig)); +} + +static uint16_t s626_get_load_trig_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRA_LOADSRC_A(s626_debi_read(dev, k->my_cra)); +} + +static uint16_t s626_get_load_trig_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_LOADSRC_B(s626_debi_read(dev, k->my_crb)); +} + +/* + * Return/set counter interrupt source and clear any captured + * index/overflow events. int_source: 0=Disabled, 1=OverflowOnly, + * 2=IndexOnly, 3=IndexAndOverflow. + */ +static void s626_set_int_src_a(struct comedi_device *dev, + const struct s626_enc_info *k, + uint16_t int_source) +{ + struct s626_private *devpriv = dev->private; + + /* Reset any pending counter overflow or index captures. */ + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + (S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_A(1))); + + /* Program counter interrupt source. */ + s626_debi_replace(dev, k->my_cra, ~S626_CRAMSK_INTSRC_A, + S626_SET_CRA_INTSRC_A(int_source)); + + /* Update MISC2 interrupt enable mask. */ + devpriv->counter_int_enabs = + (devpriv->counter_int_enabs & ~k->my_event_bits[3]) | + k->my_event_bits[int_source]; +} + +static void s626_set_int_src_b(struct comedi_device *dev, + const struct s626_enc_info *k, + uint16_t int_source) +{ + struct s626_private *devpriv = dev->private; + uint16_t crb; + + /* Cache writeable CRB register image. */ + crb = s626_debi_read(dev, k->my_crb) & ~S626_CRBMSK_INTCTRL; + + /* Reset any pending counter overflow or index captures. */ + s626_debi_write(dev, k->my_crb, (crb | S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_B(1))); + + /* Program counter interrupt source. */ + s626_debi_write(dev, k->my_crb, ((crb & ~S626_CRBMSK_INTSRC_B) | + S626_SET_CRB_INTSRC_B(int_source))); + + /* Update MISC2 interrupt enable mask. */ + devpriv->counter_int_enabs = + (devpriv->counter_int_enabs & ~k->my_event_bits[3]) | + k->my_event_bits[int_source]; +} + +static uint16_t s626_get_int_src_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRA_INTSRC_A(s626_debi_read(dev, k->my_cra)); +} + +static uint16_t s626_get_int_src_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_INTSRC_B(s626_debi_read(dev, k->my_crb)); +} + +#ifdef unused +/* + * Return/set the clock multiplier. + */ +static void s626_set_clk_mult(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_CLKMULT) | + S626_SET_STD_CLKMULT(value)), false); +} + +static uint16_t s626_get_clk_mult(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_CLKMULT(k->get_mode(dev, k)); +} + +/* + * Return/set the clock polarity. + */ +static void s626_set_clk_pol(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_CLKPOL) | + S626_SET_STD_CLKPOL(value)), false); +} + +static uint16_t s626_get_clk_pol(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_CLKPOL(k->get_mode(dev, k)); +} + +/* + * Return/set the encoder mode. + */ +static void s626_set_enc_mode(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_ENCMODE) | + S626_SET_STD_ENCMODE(value)), false); +} + +static uint16_t s626_get_enc_mode(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_ENCMODE(k->get_mode(dev, k)); +} + +/* + * Return/set the index polarity. + */ +static void s626_set_index_pol(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_INDXPOL) | + S626_SET_STD_INDXPOL(value != 0)), false); +} + +static uint16_t s626_get_index_pol(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_INDXPOL(k->get_mode(dev, k)); +} + +/* + * Return/set the index source. + */ +static void s626_set_index_src(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_INDXSRC) | + S626_SET_STD_INDXSRC(value != 0)), false); +} + +static uint16_t s626_get_index_src(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_INDXSRC(k->get_mode(dev, k)); +} +#endif + +/* + * Generate an index pulse. + */ +static void s626_pulse_index_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; - return tempdata; + cra = s626_debi_read(dev, k->my_cra); + /* Pulse index. */ + s626_debi_write(dev, k->my_cra, (cra ^ S626_CRAMSK_INDXPOL_A)); + s626_debi_write(dev, k->my_cra, cra); } -/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data){ */ -/* return 0; */ -/* } */ +static void s626_pulse_index_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t crb; + + crb = s626_debi_read(dev, k->my_crb) & ~S626_CRBMSK_INTCTRL; + /* Pulse index. */ + s626_debi_write(dev, k->my_crb, (crb ^ S626_CRBMSK_INDXPOL_B)); + s626_debi_write(dev, k->my_crb, crb); +} + +static const struct s626_enc_info s626_enc_chan_info[] = { + { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR0A, + .my_crb = S626_LP_CR0B, + .my_latch_lsw = S626_LP_CNTR0ALSW, + .my_event_bits = S626_EVBITS(0), + }, { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR1A, + .my_crb = S626_LP_CR1B, + .my_latch_lsw = S626_LP_CNTR1ALSW, + .my_event_bits = S626_EVBITS(1), + }, { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR2A, + .my_crb = S626_LP_CR2B, + .my_latch_lsw = S626_LP_CNTR2ALSW, + .my_event_bits = S626_EVBITS(2), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR0A, + .my_crb = S626_LP_CR0B, + .my_latch_lsw = S626_LP_CNTR0BLSW, + .my_event_bits = S626_EVBITS(3), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR1A, + .my_crb = S626_LP_CR1B, + .my_latch_lsw = S626_LP_CNTR1BLSW, + .my_event_bits = S626_EVBITS(4), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR2A, + .my_crb = S626_LP_CR2B, + .my_latch_lsw = S626_LP_CNTR2BLSW, + .my_event_bits = S626_EVBITS(5), + }, +}; + +static unsigned int s626_ai_reg_to_uint(unsigned int data) +{ + return ((data >> 18) & 0x3fff) ^ 0x2000; +} static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan) { @@ -627,19 +1416,19 @@ static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan) unsigned int status; /* set channel to capture positive edge */ - status = DEBIread(dev, LP_RDEDGSEL(group)); - DEBIwrite(dev, LP_WREDGSEL(group), mask | status); + status = s626_debi_read(dev, S626_LP_RDEDGSEL(group)); + s626_debi_write(dev, S626_LP_WREDGSEL(group), mask | status); /* enable interrupt on selected channel */ - status = DEBIread(dev, LP_RDINTSEL(group)); - DEBIwrite(dev, LP_WRINTSEL(group), mask | status); + status = s626_debi_read(dev, S626_LP_RDINTSEL(group)); + s626_debi_write(dev, S626_LP_WRINTSEL(group), mask | status); /* enable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_EDCAP); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_EDCAP); /* enable edge capture on selected channel */ - status = DEBIread(dev, LP_RDCAPSEL(group)); - DEBIwrite(dev, LP_WRCAPSEL(group), mask | status); + status = s626_debi_read(dev, S626_LP_RDCAPSEL(group)); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), mask | status); return 0; } @@ -648,10 +1437,10 @@ static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int group, unsigned int mask) { /* disable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); /* enable edge capture on selected channel */ - DEBIwrite(dev, LP_WRCAPSEL(group), mask); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), mask); return 0; } @@ -661,17 +1450,17 @@ static int s626_dio_clear_irq(struct comedi_device *dev) unsigned int group; /* disable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); /* clear all dio pending events and interrupt */ for (group = 0; group < S626_DIO_BANKS; group++) - DEBIwrite(dev, LP_WRCAPSEL(group), 0xffff); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), 0xffff); return 0; } -static void handle_dio_interrupt(struct comedi_device *dev, - uint16_t irqbit, uint8_t group) +static void s626_handle_dio_interrupt(struct comedi_device *dev, + uint16_t irqbit, uint8_t group) { struct s626_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -684,7 +1473,7 @@ static void handle_dio_interrupt(struct comedi_device *dev, if ((irqbit >> (cmd->start_arg - (16 * group))) == 1 && cmd->start_src == TRIG_EXT) { /* Start executing the RPS program */ - s626_mc_enable(dev, MC1_ERPS1, P_MC1); + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); if (cmd->scan_begin_src == TRIG_EXT) s626_dio_set_irq(dev, cmd->scan_begin_arg); @@ -692,7 +1481,7 @@ static void handle_dio_interrupt(struct comedi_device *dev, if ((irqbit >> (cmd->scan_begin_arg - (16 * group))) == 1 && cmd->scan_begin_src == TRIG_EXT) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); if (cmd->convert_src == TRIG_EXT) { devpriv->ai_convert_count = cmd->chanlist_len; @@ -701,16 +1490,17 @@ static void handle_dio_interrupt(struct comedi_device *dev, } if (cmd->convert_src == TRIG_TIMER) { - struct enc_private *k = &encpriv[5]; + const struct s626_enc_info *k = + &s626_enc_chan_info[5]; devpriv->ai_convert_count = cmd->chanlist_len; - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); } } if ((irqbit >> (cmd->convert_arg - (16 * group))) == 1 && cmd->convert_src == TRIG_EXT) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); devpriv->ai_convert_count--; if (devpriv->ai_convert_count > 0) @@ -719,7 +1509,7 @@ static void handle_dio_interrupt(struct comedi_device *dev, } } -static void check_dio_interrupts(struct comedi_device *dev) +static void s626_check_dio_interrupts(struct comedi_device *dev) { uint16_t irqbit; uint8_t group; @@ -727,90 +1517,91 @@ static void check_dio_interrupts(struct comedi_device *dev) for (group = 0; group < S626_DIO_BANKS; group++) { irqbit = 0; /* read interrupt type */ - irqbit = DEBIread(dev, LP_RDCAPFLG(group)); + irqbit = s626_debi_read(dev, S626_LP_RDCAPFLG(group)); /* check if interrupt is generated from dio channels */ if (irqbit) { - handle_dio_interrupt(dev, irqbit, group); + s626_handle_dio_interrupt(dev, irqbit, group); return; } } } -static void check_counter_interrupts(struct comedi_device *dev) +static void s626_check_counter_interrupts(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - struct enc_private *k; + const struct s626_enc_info *k; uint16_t irqbit; /* read interrupt type */ - irqbit = DEBIread(dev, LP_RDMISC2); + irqbit = s626_debi_read(dev, S626_LP_RDMISC2); /* check interrupt on counters */ - if (irqbit & IRQ_COINT1A) { - k = &encpriv[0]; + if (irqbit & S626_IRQ_COINT1A) { + k = &s626_enc_chan_info[0]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT2A) { - k = &encpriv[1]; + if (irqbit & S626_IRQ_COINT2A) { + k = &s626_enc_chan_info[1]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT3A) { - k = &encpriv[2]; + if (irqbit & S626_IRQ_COINT3A) { + k = &s626_enc_chan_info[2]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT1B) { - k = &encpriv[3]; + if (irqbit & S626_IRQ_COINT1B) { + k = &s626_enc_chan_info[3]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT2B) { - k = &encpriv[4]; + if (irqbit & S626_IRQ_COINT2B) { + k = &s626_enc_chan_info[4]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); if (devpriv->ai_convert_count > 0) { devpriv->ai_convert_count--; if (devpriv->ai_convert_count == 0) - k->SetEnable(dev, k, CLKENAB_INDEX); + k->set_enable(dev, k, S626_CLKENAB_INDEX); if (cmd->convert_src == TRIG_TIMER) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, + S626_P_MC2); } } } - if (irqbit & IRQ_COINT3B) { - k = &encpriv[5]; + if (irqbit & S626_IRQ_COINT3B) { + k = &s626_enc_chan_info[5]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); if (cmd->scan_begin_src == TRIG_TIMER) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); } if (cmd->convert_src == TRIG_TIMER) { - k = &encpriv[4]; + k = &s626_enc_chan_info[4]; devpriv->ai_convert_count = cmd->chanlist_len; - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); } } } -static bool handle_eos_interrupt(struct comedi_device *dev) +static bool s626_handle_eos_interrupt(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -821,36 +1612,35 @@ static bool handle_eos_interrupt(struct comedi_device *dev) * first uint16_t in the buffer because it contains junk data * from the final ADC of the previous poll list scan. */ - int32_t *readaddr = (int32_t *)devpriv->ANABuf.LogicalBase + 1; + uint32_t *readaddr = (uint32_t *)devpriv->ana_buf.logical_base + 1; bool finished = false; int i; /* get the data and hand it over to comedi */ for (i = 0; i < cmd->chanlist_len; i++) { - short tempdata; + unsigned short tempdata; /* * Convert ADC data to 16-bit integer values and copy * to application buffer. */ - tempdata = s626_ai_reg_to_uint((int)*readaddr); + tempdata = s626_ai_reg_to_uint(*readaddr); readaddr++; /* put data into read buffer */ - /* comedi_buf_put(async, tempdata); */ cfc_write_to_buffer(s, tempdata); } /* end of scan occurs */ async->events |= COMEDI_CB_EOS; - if (!devpriv->ai_continous) + if (!devpriv->ai_continuous) devpriv->ai_sample_count--; if (devpriv->ai_sample_count <= 0) { devpriv->ai_cmd_running = 0; /* Stop RPS program */ - s626_mc_disable(dev, MC1_ERPS1, P_MC1); + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); /* send end of acquisition */ async->events |= COMEDI_CB_EOA; @@ -877,229 +1667,239 @@ static irqreturn_t s626_irq_handler(int irq, void *d) if (!dev->attached) return IRQ_NONE; - /* lock to avoid race with comedi_poll */ + /* lock to avoid race with comedi_poll */ spin_lock_irqsave(&dev->spinlock, flags); /* save interrupt enable register state */ - irqstatus = readl(devpriv->mmio + P_IER); + irqstatus = readl(devpriv->mmio + S626_P_IER); /* read interrupt type */ - irqtype = readl(devpriv->mmio + P_ISR); + irqtype = readl(devpriv->mmio + S626_P_ISR); /* disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* clear interrupt */ - writel(irqtype, devpriv->mmio + P_ISR); + writel(irqtype, devpriv->mmio + S626_P_ISR); switch (irqtype) { - case IRQ_RPS1: /* end_of_scan occurs */ - if (handle_eos_interrupt(dev)) + case S626_IRQ_RPS1: /* end_of_scan occurs */ + if (s626_handle_eos_interrupt(dev)) irqstatus = 0; break; - case IRQ_GPIO3: /* check dio and conter interrupt */ + case S626_IRQ_GPIO3: /* check dio and counter interrupt */ /* s626_dio_clear_irq(dev); */ - check_dio_interrupts(dev); - check_counter_interrupts(dev); + s626_check_dio_interrupts(dev); + s626_check_counter_interrupts(dev); break; } /* enable interrupt */ - writel(irqstatus, devpriv->mmio + P_IER); + writel(irqstatus, devpriv->mmio + S626_P_IER); spin_unlock_irqrestore(&dev->spinlock, flags); return IRQ_HANDLED; } /* - * this functions build the RPS program for hardware driven acquistion + * This function builds the RPS program for hardware driven acquisition. */ -static void ResetADC(struct comedi_device *dev, uint8_t *ppl) +static void s626_reset_adc(struct comedi_device *dev, uint8_t *ppl) { struct s626_private *devpriv = dev->private; - register uint32_t *pRPS; - uint32_t JmpAdrs; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + uint32_t *rps; + uint32_t jmp_adrs; uint16_t i; uint16_t n; - uint32_t LocalPPL; - struct comedi_cmd *cmd = &(dev->subdevices->async->cmd); + uint32_t local_ppl; /* Stop RPS program in case it is currently running */ - s626_mc_disable(dev, MC1_ERPS1, P_MC1); + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); - /* Set starting logical address to write RPS commands. */ - pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase; + /* Set starting logical address to write RPS commands. */ + rps = (uint32_t *)devpriv->rps_buf.logical_base; /* Initialize RPS instruction pointer */ - writel((uint32_t)devpriv->RPSBuf.PhysicalBase, - devpriv->mmio + P_RPSADDR1); - - /* Construct RPS program in RPSBuf DMA buffer */ + writel((uint32_t)devpriv->rps_buf.physical_base, + devpriv->mmio + S626_P_RPSADDR1); + /* Construct RPS program in rps_buf DMA buffer */ if (cmd != NULL && cmd->scan_begin_src != TRIG_FOLLOW) { - /* Wait for Start trigger. */ - *pRPS++ = RPS_PAUSE | RPS_SIGADC; - *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; + /* Wait for Start trigger. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_SIGADC; + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; } - /* SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary + /* + * SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary * because the first RPS DEBI Write following a non-RPS DEBI write * seems to always fail. If we don't do this dummy write, the ADC * gain might not be set to the value required for the first slot in * the poll list; the ADC gain would instead remain unchanged from * the previously programmed value. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); /* Write DEBI Write command and address to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_GSEL; + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + /* Write DEBI immediate data to shadow RAM: */ + *rps++ = S626_GSEL_BIPOLAR5V; /* arbitrary immediate data value. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Reset "shadow RAM uploaded" flag. */ + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; - *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); - /* Write DEBI immediate data to shadow RAM: */ - - *pRPS++ = GSEL_BIPOLAR5V; - /* arbitrary immediate data value. */ - - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; - /* Reset "shadow RAM uploaded" flag. */ - *pRPS++ = RPS_UPLOAD | RPS_DEBI; /* Invoke shadow RAM upload. */ - *pRPS++ = RPS_PAUSE | RPS_DEBI; /* Wait for shadow upload to finish. */ - - /* Digitize all slots in the poll list. This is implemented as a + /* + * Digitize all slots in the poll list. This is implemented as a * for loop to limit the slot count to 16 in case the application - * forgot to set the EOPL flag in the final slot. + * forgot to set the S626_EOPL flag in the final slot. */ - for (devpriv->AdcItems = 0; devpriv->AdcItems < 16; devpriv->AdcItems++) { - /* Convert application's poll list item to private board class + for (devpriv->adc_items = 0; devpriv->adc_items < 16; + devpriv->adc_items++) { + /* + * Convert application's poll list item to private board class * format. Each app poll list item is an uint8_t with form * (EOPL,x,x,RANGE,CHAN<3:0>), where RANGE code indicates 0 = * +-10V, 1 = +-5V, and EOPL = End of Poll List marker. */ - LocalPPL = - (*ppl << 8) | (*ppl & 0x10 ? GSEL_BIPOLAR5V : - GSEL_BIPOLAR10V); - - /* Switch ADC analog gain. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); /* Write DEBI command */ - /* and address to */ - /* shadow RAM. */ - *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); /* Write DEBI */ - /* immediate data to */ - /* shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; /* Reset "shadow RAM uploaded" */ - /* flag. */ - *pRPS++ = RPS_UPLOAD | RPS_DEBI; /* Invoke shadow RAM upload. */ - *pRPS++ = RPS_PAUSE | RPS_DEBI; /* Wait for shadow upload to */ - /* finish. */ - - /* Select ADC analog input channel. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); - /* Write DEBI command and address to shadow RAM. */ - *pRPS++ = DEBI_CMD_WRWORD | LP_ISEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); - /* Write DEBI immediate data to shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; - /* Reset "shadow RAM uploaded" flag. */ - - *pRPS++ = RPS_UPLOAD | RPS_DEBI; - /* Invoke shadow RAM upload. */ - - *pRPS++ = RPS_PAUSE | RPS_DEBI; - /* Wait for shadow upload to finish. */ - - /* Delay at least 10 microseconds for analog input settling. - * Instead of padding with NOPs, we use RPS_JUMP instructions - * here; this allows us to produce a longer delay than is - * possible with NOPs because each RPS_JUMP flushes the RPS' - * instruction prefetch pipeline. + local_ppl = (*ppl << 8) | (*ppl & 0x10 ? S626_GSEL_BIPOLAR5V : + S626_GSEL_BIPOLAR10V); + + /* Switch ADC analog gain. */ + /* Write DEBI command and address to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_GSEL; + /* Write DEBI immediate data to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + *rps++ = local_ppl; + /* Reset "shadow RAM uploaded" flag. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; + /* Select ADC analog input channel. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + /* Write DEBI command and address to shadow RAM. */ + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_ISEL; + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + /* Write DEBI immediate data to shadow RAM. */ + *rps++ = local_ppl; + /* Reset "shadow RAM uploaded" flag. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; + + /* + * Delay at least 10 microseconds for analog input settling. + * Instead of padding with NOPs, we use S626_RPS_JUMP + * instructions here; this allows us to produce a longer delay + * than is possible with NOPs because each S626_RPS_JUMP + * flushes the RPS' instruction prefetch pipeline. */ - JmpAdrs = - (uint32_t) devpriv->RPSBuf.PhysicalBase + - (uint32_t) ((unsigned long)pRPS - - (unsigned long)devpriv->RPSBuf.LogicalBase); - for (i = 0; i < (10 * RPSCLK_PER_US / 2); i++) { - JmpAdrs += 8; /* Repeat to implement time delay: */ - *pRPS++ = RPS_JUMP; /* Jump to next RPS instruction. */ - *pRPS++ = JmpAdrs; + jmp_adrs = + (uint32_t)devpriv->rps_buf.physical_base + + (uint32_t)((unsigned long)rps - + (unsigned long)devpriv-> + rps_buf.logical_base); + for (i = 0; i < (10 * S626_RPSCLK_PER_US / 2); i++) { + jmp_adrs += 8; /* Repeat to implement time delay: */ + /* Jump to next RPS instruction. */ + *rps++ = S626_RPS_JUMP; + *rps++ = jmp_adrs; } if (cmd != NULL && cmd->convert_src != TRIG_NOW) { - /* Wait for Start trigger. */ - *pRPS++ = RPS_PAUSE | RPS_SIGADC; - *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; + /* Wait for Start trigger. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_SIGADC; + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; } - /* Start ADC by pulsing GPIO1. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* Begin ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_LO; - *pRPS++ = RPS_NOP; - /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* End ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_HI; - - /* Wait for ADC to complete (GPIO2 is asserted high when ADC not + /* Start ADC by pulsing GPIO1. */ + /* Begin ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_LO; + *rps++ = S626_RPS_NOP; + /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ + /* End ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_HI; + /* + * Wait for ADC to complete (GPIO2 is asserted high when ADC not * busy) and for data from previous conversion to shift into FB * BUFFER 1 register. */ - *pRPS++ = RPS_PAUSE | RPS_GPIO2; /* Wait for ADC done. */ - - /* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); - *pRPS++ = - (uint32_t) devpriv->ANABuf.PhysicalBase + - (devpriv->AdcItems << 2); - - /* If this slot's EndOfPollList flag is set, all channels have */ - /* now been processed. */ - if (*ppl++ & EOPL) { - devpriv->AdcItems++; /* Adjust poll list item count. */ - break; /* Exit poll list processing loop. */ + /* Wait for ADC done. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_GPIO2; + + /* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ + *rps++ = S626_RPS_STREG | + (S626_BUGFIX_STREG(S626_P_FB_BUFFER1) >> 2); + *rps++ = (uint32_t)devpriv->ana_buf.physical_base + + (devpriv->adc_items << 2); + + /* + * If this slot's EndOfPollList flag is set, all channels have + * now been processed. + */ + if (*ppl++ & S626_EOPL) { + devpriv->adc_items++; /* Adjust poll list item count. */ + break; /* Exit poll list processing loop. */ } } - /* VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the + /* + * VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the * ADC to stabilize for 2 microseconds before starting the final * (dummy) conversion. This delay is necessary to allow sufficient * time between last conversion finished and the start of the dummy * conversion. Without this delay, the last conversion's data value * is sometimes set to the previous conversion's data value. */ - for (n = 0; n < (2 * RPSCLK_PER_US); n++) - *pRPS++ = RPS_NOP; + for (n = 0; n < (2 * S626_RPSCLK_PER_US); n++) + *rps++ = S626_RPS_NOP; - /* Start a dummy conversion to cause the data from the last + /* + * Start a dummy conversion to cause the data from the last * conversion of interest to be shifted in. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* Begin ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_LO; - *pRPS++ = RPS_NOP; + /* Begin ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_LO; + *rps++ = S626_RPS_NOP; /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* End ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_HI; + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); /* End ADC Start pulse. */ + *rps++ = S626_GPIO_BASE | S626_GPIO1_HI; - /* Wait for the data from the last conversion of interest to arrive + /* + * Wait for the data from the last conversion of interest to arrive * in FB BUFFER 1 register. */ - *pRPS++ = RPS_PAUSE | RPS_GPIO2; /* Wait for ADC done. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_GPIO2; /* Wait for ADC done. */ - /* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); /* */ - *pRPS++ = - (uint32_t) devpriv->ANABuf.PhysicalBase + (devpriv->AdcItems << 2); + /* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ + *rps++ = S626_RPS_STREG | (S626_BUGFIX_STREG(S626_P_FB_BUFFER1) >> 2); + *rps++ = (uint32_t)devpriv->ana_buf.physical_base + + (devpriv->adc_items << 2); - /* Indicate ADC scan loop is finished. */ - /* *pRPS++= RPS_CLRSIGNAL | RPS_SIGADC ; // Signal ReadADC() that scan is done. */ + /* Indicate ADC scan loop is finished. */ + /* Signal ReadADC() that scan is done. */ + /* *rps++= S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; */ /* invoke interrupt */ - if (devpriv->ai_cmd_running == 1) { - *pRPS++ = RPS_IRQ; - } - /* Restart RPS program at its beginning. */ - *pRPS++ = RPS_JUMP; /* Branch to start of RPS program. */ - *pRPS++ = (uint32_t) devpriv->RPSBuf.PhysicalBase; + if (devpriv->ai_cmd_running == 1) + *rps++ = S626_RPS_IRQ; + + /* Restart RPS program at its beginning. */ + *rps++ = S626_RPS_JUMP; /* Branch to start of RPS program. */ + *rps++ = (uint32_t)devpriv->rps_buf.physical_base; - /* End of RPS program build */ + /* End of RPS program build */ } #ifdef unused_code @@ -1109,14 +1909,14 @@ static int s626_ai_rinsn(struct comedi_device *dev, unsigned int *data) { struct s626_private *devpriv = dev->private; - register uint8_t i; - register int32_t *readaddr; + uint8_t i; + int32_t *readaddr; /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); /* Wait until ADC scan loop is finished (RPS Signal 0 reset) */ - while (s626_mc_test(dev, MC2_ADC_RPS, P_MC2)) + while (s626_mc_test(dev, S626_MC2_ADC_RPS, S626_P_MC2)) ; /* @@ -1124,13 +1924,13 @@ static int s626_ai_rinsn(struct comedi_device *dev, * first uint16_t in the buffer because it contains junk data from * the final ADC of the previous poll list scan. */ - readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; + readaddr = (uint32_t *)devpriv->ana_buf.logical_base + 1; /* * Convert ADC data to 16-bit integer values and * copy to application buffer. */ - for (i = 0; i < devpriv->AdcItems; i++) { + for (i = 0; i < devpriv->adc_items; i++) { *data = s626_ai_reg_to_uint(*readaddr++); data++; } @@ -1139,6 +1939,20 @@ static int s626_ai_rinsn(struct comedi_device *dev, } #endif +static int s626_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + S626_P_PSR); + if (status & S626_PSR_GPIO2) + return 0; + return -EBUSY; +} + static int s626_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1146,55 +1960,63 @@ static int s626_ai_insn_read(struct comedi_device *dev, struct s626_private *devpriv = dev->private; uint16_t chan = CR_CHAN(insn->chanspec); uint16_t range = CR_RANGE(insn->chanspec); - uint16_t AdcSpec = 0; - uint32_t GpioImage; - int tmp; + uint16_t adc_spec = 0; + uint32_t gpio_image; + uint32_t tmp; + int ret; int n; - /* Convert application's ADC specification into form + /* + * Convert application's ADC specification into form * appropriate for register programming. */ if (range == 0) - AdcSpec = (chan << 8) | (GSEL_BIPOLAR5V); + adc_spec = (chan << 8) | (S626_GSEL_BIPOLAR5V); else - AdcSpec = (chan << 8) | (GSEL_BIPOLAR10V); + adc_spec = (chan << 8) | (S626_GSEL_BIPOLAR10V); - /* Switch ADC analog gain. */ - DEBIwrite(dev, LP_GSEL, AdcSpec); /* Set gain. */ + /* Switch ADC analog gain. */ + s626_debi_write(dev, S626_LP_GSEL, adc_spec); /* Set gain. */ - /* Select ADC analog input channel. */ - DEBIwrite(dev, LP_ISEL, AdcSpec); /* Select channel. */ + /* Select ADC analog input channel. */ + s626_debi_write(dev, S626_LP_ISEL, adc_spec); /* Select channel. */ for (n = 0; n < insn->n; n++) { - - /* Delay 10 microseconds for analog input settling. */ + /* Delay 10 microseconds for analog input settling. */ udelay(10); /* Start ADC by pulsing GPIO1 low */ - GpioImage = readl(devpriv->mmio + P_GPIO); + gpio_image = readl(devpriv->mmio + S626_P_GPIO); /* Assert ADC Start command */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); /* and stretch it out */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); /* Negate ADC Start command */ - writel(GpioImage | GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); - /* Wait for ADC to complete (GPIO2 is asserted high when */ - /* ADC not busy) and for data from previous conversion to */ - /* shift into FB BUFFER 1 register. */ + /* + * Wait for ADC to complete (GPIO2 is asserted high when + * ADC not busy) and for data from previous conversion to + * shift into FB BUFFER 1 register. + */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + P_PSR) & PSR_GPIO2)) - ; + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; /* Fetch ADC data */ if (n != 0) { - tmp = readl(devpriv->mmio + P_FB_BUFFER1); + tmp = readl(devpriv->mmio + S626_P_FB_BUFFER1); data[n - 1] = s626_ai_reg_to_uint(tmp); } - /* Allow the ADC to stabilize for 4 microseconds before + /* + * Allow the ADC to stabilize for 4 microseconds before * starting the next (final) conversion. This delay is * necessary to allow sufficient time between last * conversion finished and the start of the next @@ -1205,28 +2027,31 @@ static int s626_ai_insn_read(struct comedi_device *dev, udelay(4); } - /* Start a dummy conversion to cause the data from the - * previous conversion to be shifted in. */ - GpioImage = readl(devpriv->mmio + P_GPIO); + /* + * Start a dummy conversion to cause the data from the + * previous conversion to be shifted in. + */ + gpio_image = readl(devpriv->mmio + S626_P_GPIO); /* Assert ADC Start command */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); /* and stretch it out */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); /* Negate ADC Start command */ - writel(GpioImage | GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); - /* Wait for the data to arrive in FB BUFFER 1 register. */ + /* Wait for the data to arrive in FB BUFFER 1 register. */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + P_PSR) & PSR_GPIO2)) - ; + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; - /* Fetch ADC data from audio interface's input shift register. */ + /* Fetch ADC data from audio interface's input shift register. */ /* Fetch ADC data */ if (n != 0) { - tmp = readl(devpriv->mmio + P_FB_BUFFER1); + tmp = readl(devpriv->mmio + S626_P_FB_BUFFER1); data[n - 1] = s626_ai_reg_to_uint(tmp); } @@ -1235,41 +2060,45 @@ static int s626_ai_insn_read(struct comedi_device *dev, static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd) { - int n; for (n = 0; n < cmd->chanlist_len; n++) { - if (CR_RANGE((cmd->chanlist)[n]) == 0) - ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_5V); + if (CR_RANGE(cmd->chanlist[n]) == 0) + ppl[n] = CR_CHAN(cmd->chanlist[n]) | S626_RANGE_5V; else - ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_10V); + ppl[n] = CR_CHAN(cmd->chanlist[n]) | S626_RANGE_10V; } if (n != 0) - ppl[n - 1] |= EOPL; + ppl[n - 1] |= S626_EOPL; return n; } static int s626_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; /* Start executing the RPS program */ - s626_mc_enable(dev, MC1_ERPS1, P_MC1); + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); s->async->inttrig = NULL; return 1; } -/* This function doesn't require a particular form, this is just what +/* + * This function doesn't require a particular form, this is just what * happens to be used in some of the drivers. It should convert ns * nanoseconds to a counter value suitable for programming the device. * Also, it should adjust ns so that it cooresponds to the actual time - * that the device will use. */ -static int s626_ns_to_timer(int *nanosec, int round_mode) + * that the device will use. + */ +static int s626_ns_to_timer(unsigned int *nanosec, int round_mode) { int divider, base; @@ -1292,77 +2121,78 @@ static int s626_ns_to_timer(int *nanosec, int round_mode) return divider - 1; } -static void s626_timer_load(struct comedi_device *dev, struct enc_private *k, - int tick) +static void s626_timer_load(struct comedi_device *dev, + const struct s626_enc_info *k, int tick) { - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_TIMER << BF_CLKSRC) | /* Operating mode is Timer. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - (CNTDIR_DOWN << BF_CLKPOL) | /* Count direction is Down. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); - uint16_t valueSrclatch = LATCHSRC_A_INDXA; - /* uint16_t enab=CLKENAB_ALWAYS; */ + uint16_t setup = + /* Preload upon index. */ + S626_SET_STD_LOADSRC(S626_LOADSRC_INDX) | + /* Disable hardware index. */ + S626_SET_STD_INDXSRC(S626_INDXSRC_SOFT) | + /* Operating mode is Timer. */ + S626_SET_STD_ENCMODE(S626_ENCMODE_TIMER) | + /* Count direction is Down. */ + S626_SET_STD_CLKPOL(S626_CNTDIR_DOWN) | + /* Clock multiplier is 1x. */ + S626_SET_STD_CLKMULT(S626_CLKMULT_1X) | + /* Enabled by index */ + S626_SET_STD_CLKENAB(S626_CLKENAB_INDEX); + uint16_t value_latchsrc = S626_LATCHSRC_A_INDXA; + /* uint16_t enab = S626_CLKENAB_ALWAYS; */ - k->SetMode(dev, k, Setup, FALSE); + k->set_mode(dev, k, setup, false); - /* Set the preload register */ - Preload(dev, k, tick); + /* Set the preload register */ + s626_preload(dev, k, tick); - /* Software index pulse forces the preload register to load */ - /* into the counter */ - k->SetLoadTrig(dev, k, 0); - k->PulseIndex(dev, k); + /* + * Software index pulse forces the preload register to load + * into the counter + */ + k->set_load_trig(dev, k, 0); + k->pulse_index(dev, k); /* set reload on counter overflow */ - k->SetLoadTrig(dev, k, 1); + k->set_load_trig(dev, k, 1); /* set interrupt on overflow */ - k->SetIntSrc(dev, k, INTSRC_OVER); + k->set_int_src(dev, k, S626_INTSRC_OVER); - SetLatchSource(dev, k, valueSrclatch); - /* k->SetEnable(dev,k,(uint16_t)(enab != 0)); */ + s626_set_latch_source(dev, k, value_latchsrc); + /* k->set_enable(dev, k, (uint16_t)(enab != 0)); */ } -/* TO COMPLETE */ +/* TO COMPLETE */ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct s626_private *devpriv = dev->private; uint8_t ppl[16]; struct comedi_cmd *cmd = &s->async->cmd; - struct enc_private *k; + const struct s626_enc_info *k; int tick; if (devpriv->ai_cmd_running) { - printk(KERN_ERR "s626_ai_cmd: Another ai_cmd is running %d\n", - dev->minor); + dev_err(dev->class_dev, + "s626_ai_cmd: Another ai_cmd is running\n"); return -EBUSY; } /* disable interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* clear interrupt request */ - writel(IRQ_RPS1 | IRQ_GPIO3, devpriv->mmio + P_ISR); + writel(S626_IRQ_RPS1 | S626_IRQ_GPIO3, devpriv->mmio + S626_P_ISR); /* clear any pending interrupt */ s626_dio_clear_irq(dev); - /* s626_enc_clear_irq(dev); */ + /* s626_enc_clear_irq(dev); */ /* reset ai_cmd_running flag */ devpriv->ai_cmd_running = 0; - /* test if cmd is valid */ + /* test if cmd is valid */ if (cmd == NULL) return -EINVAL; - if (dev->irq == 0) { - comedi_error(dev, - "s626_ai_cmd: cannot run command without an irq"); - return -EIO; - } - s626_ai_load_polllist(ppl, cmd); devpriv->ai_cmd_running = 1; devpriv->ai_convert_count = 0; @@ -1371,17 +2201,20 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_FOLLOW: break; case TRIG_TIMER: - /* set a conter to generate adc trigger at scan_begin_arg interval */ - k = &encpriv[5]; - tick = s626_ns_to_timer((int *)&cmd->scan_begin_arg, + /* + * set a counter to generate adc trigger at scan_begin_arg + * interval + */ + k = &s626_enc_chan_info[5]; + tick = s626_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ s626_timer_load(dev, k, tick); - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); break; case TRIG_EXT: - /* set the digital line and interrupt for scan trigger */ + /* set the digital line and interrupt for scan trigger */ if (cmd->start_src != TRIG_EXT) s626_dio_set_irq(dev, cmd->scan_begin_arg); break; @@ -1391,52 +2224,53 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_NOW: break; case TRIG_TIMER: - /* set a conter to generate adc trigger at convert_arg interval */ - k = &encpriv[4]; - tick = s626_ns_to_timer((int *)&cmd->convert_arg, + /* + * set a counter to generate adc trigger at convert_arg + * interval + */ + k = &s626_enc_chan_info[4]; + tick = s626_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ s626_timer_load(dev, k, tick); - k->SetEnable(dev, k, CLKENAB_INDEX); + k->set_enable(dev, k, S626_CLKENAB_INDEX); break; case TRIG_EXT: - /* set the digital line and interrupt for convert trigger */ - if (cmd->scan_begin_src != TRIG_EXT - && cmd->start_src == TRIG_EXT) + /* set the digital line and interrupt for convert trigger */ + if (cmd->scan_begin_src != TRIG_EXT && + cmd->start_src == TRIG_EXT) s626_dio_set_irq(dev, cmd->convert_arg); break; } switch (cmd->stop_src) { case TRIG_COUNT: - /* data arrives as one packet */ + /* data arrives as one packet */ devpriv->ai_sample_count = cmd->stop_arg; - devpriv->ai_continous = 0; + devpriv->ai_continuous = 0; break; case TRIG_NONE: - /* continous acquisition */ - devpriv->ai_continous = 1; + /* continuous acquisition */ + devpriv->ai_continuous = 1; devpriv->ai_sample_count = 1; break; } - ResetADC(dev, ppl); + s626_reset_adc(dev, ppl); switch (cmd->start_src) { case TRIG_NOW: /* Trigger ADC scan loop start */ - /* s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); */ + /* s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); */ /* Start executing the RPS program */ - s626_mc_enable(dev, MC1_ERPS1, P_MC1); - + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); s->async->inttrig = NULL; break; case TRIG_EXT: /* configure DIO channel for acquisition trigger */ s626_dio_set_irq(dev, cmd->start_arg); - s->async->inttrig = NULL; break; case TRIG_INT: @@ -1445,7 +2279,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* enable interrupt */ - writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->mmio + P_IER); + writel(S626_IRQ_GPIO3 | S626_IRQ_RPS1, devpriv->mmio + S626_P_IER); return 0; } @@ -1454,16 +2288,16 @@ static int s626_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ err |= cfc_check_trigger_src(&cmd->start_src, - TRIG_NOW | TRIG_INT | TRIG_EXT); + TRIG_NOW | TRIG_INT | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW); + TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW); err |= cfc_check_trigger_src(&cmd->convert_src, - TRIG_TIMER | TRIG_EXT | TRIG_NOW); + TRIG_TIMER | TRIG_EXT | TRIG_NOW); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -1482,40 +2316,46 @@ static int s626_ai_cmdtest(struct comedi_device *dev, if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src != TRIG_EXT) + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_src == TRIG_EXT) + break; + case TRIG_EXT: err |= cfc_check_trigger_arg_max(&cmd->start_arg, 39); + break; + } if (cmd->scan_begin_src == TRIG_EXT) err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 39); - if (cmd->convert_src == TRIG_EXT) err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 39); -#define MAX_SPEED 200000 /* in nanoseconds */ -#define MIN_SPEED 2000000000 /* in nanoseconds */ +#define S626_MAX_SPEED 200000 /* in nanoseconds */ +#define S626_MIN_SPEED 2000000000 /* in nanoseconds */ if (cmd->scan_begin_src == TRIG_TIMER) { err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); + S626_MAX_SPEED); err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SPEED); + S626_MIN_SPEED); } else { /* external trigger */ /* should be level/edge, hi/lo specification here */ /* should specify multiple external triggers */ -/* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ + /* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ } if (cmd->convert_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, MIN_SPEED); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + S626_MAX_SPEED); + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, + S626_MIN_SPEED); } else { /* external trigger */ /* see above */ -/* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ + /* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ } err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); @@ -1531,24 +2371,20 @@ static int s626_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - s626_ns_to_timer((int *)&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + s626_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } + if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - s626_ns_to_timer((int *)&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + s626_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -1563,10 +2399,10 @@ static int s626_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) struct s626_private *devpriv = dev->private; /* Stop RPS program in case it is currently running */ - s626_mc_disable(dev, MC1_ERPS1, P_MC1); + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); /* disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); devpriv->ai_cmd_running = 0; @@ -1578,6 +2414,7 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, { struct s626_private *devpriv = dev->private; int i; + int ret; uint16_t chan = CR_CHAN(insn->chanspec); int16_t dacdata; @@ -1586,7 +2423,9 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i]; dacdata -= (0x1fff); - SetDAC(dev, chan, dacdata); + ret = s626_set_dac(dev, chan, dacdata); + if (ret) + return ret; } return i; @@ -1604,7 +2443,9 @@ static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* *************** DIGITAL I/O FUNCTIONS *************** +/* *************** DIGITAL I/O FUNCTIONS *************** */ + +/* * All DIO functions address a group of DIO channels by means of * "group" argument. group may be 0, 1 or 2, which correspond to DIO * ports A, B and C, respectively. @@ -1614,19 +2455,19 @@ static void s626_dio_init(struct comedi_device *dev) { uint16_t group; - /* Prepare to treat writes to WRCapSel as capture disables. */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + /* Prepare to treat writes to WRCapSel as capture disables. */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); - /* For each group of sixteen channels ... */ + /* For each group of sixteen channels ... */ for (group = 0; group < S626_DIO_BANKS; group++) { /* Disable all interrupts */ - DEBIwrite(dev, LP_WRINTSEL(group), 0); + s626_debi_write(dev, S626_LP_WRINTSEL(group), 0); /* Disable all event captures */ - DEBIwrite(dev, LP_WRCAPSEL(group), 0xffff); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), 0xffff); /* Init all DIOs to default edge polarity */ - DEBIwrite(dev, LP_WREDGSEL(group), 0); + s626_debi_write(dev, S626_LP_WREDGSEL(group), 0); /* Program all outputs to inactive state */ - DEBIwrite(dev, LP_WRDOUT(group), 0); + s626_debi_write(dev, S626_LP_WRDOUT(group), 0); } } @@ -1636,20 +2477,11 @@ static int s626_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { unsigned long group = (unsigned long)s->private; - unsigned long mask = data[0]; - unsigned long bits = data[1]; - - if (mask) { - /* Check if requested channels are configured for output */ - if ((s->io_bits & mask) != mask) - return -EIO; - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) + s626_debi_write(dev, S626_LP_WRDOUT(group), s->state); - DEBIwrite(dev, LP_WRDOUT(group), s->state); - } - data[1] = DEBIread(dev, LP_RDDIN(group)); + data[1] = s626_debi_read(dev, S626_LP_RDDIN(group)); return insn->n; } @@ -1660,60 +2492,57 @@ static int s626_dio_insn_config(struct comedi_device *dev, unsigned int *data) { unsigned long group = (unsigned long)s->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask = 1 << chan; + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - case COMEDI_INPUT: - s->io_bits &= ~mask; - break; - case COMEDI_OUTPUT: - s->io_bits |= mask; - break; - default: - return -EINVAL; - break; - } - DEBIwrite(dev, LP_WRDOUT(group), s->io_bits); + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + + s626_debi_write(dev, S626_LP_WRDOUT(group), s->io_bits); return insn->n; } -/* Now this function initializes the value of the counter (data[0]) - and set the subdevice. To complete with trigger and interrupt - configuration */ -/* FIXME: data[0] is supposed to be an INSN_CONFIG_xxx constant indicating +/* + * Now this function initializes the value of the counter (data[0]) + * and set the subdevice. To complete with trigger and interrupt + * configuration. + * + * FIXME: data[0] is supposed to be an INSN_CONFIG_xxx constant indicating * what is being configured, but this function appears to be using data[0] - * as a variable. */ + * as a variable. + */ static int s626_enc_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_COUNTER << BF_CLKSRC) | /* Operating mode is Counter. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - /* ( CNTDIR_UP << BF_CLKPOL ) | // Count direction is Down. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); - /* uint16_t DisableIntSrc=TRUE; */ - /* uint32_t Preloadvalue; //Counter initial value */ - uint16_t valueSrclatch = LATCHSRC_AB_READ; - uint16_t enab = CLKENAB_ALWAYS; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; - - /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ - - k->SetMode(dev, k, Setup, TRUE); - Preload(dev, k, data[0]); - k->PulseIndex(dev, k); - SetLatchSource(dev, k, valueSrclatch); - k->SetEnable(dev, k, (uint16_t) (enab != 0)); + uint16_t setup = + /* Preload upon index. */ + S626_SET_STD_LOADSRC(S626_LOADSRC_INDX) | + /* Disable hardware index. */ + S626_SET_STD_INDXSRC(S626_INDXSRC_SOFT) | + /* Operating mode is Counter. */ + S626_SET_STD_ENCMODE(S626_ENCMODE_COUNTER) | + /* Active high clock. */ + S626_SET_STD_CLKPOL(S626_CLKPOL_POS) | + /* Clock multiplier is 1x. */ + S626_SET_STD_CLKMULT(S626_CLKMULT_1X) | + /* Enabled by index */ + S626_SET_STD_CLKENAB(S626_CLKENAB_INDEX); + /* uint16_t disable_int_src = true; */ + /* uint32_t Preloadvalue; //Counter initial value */ + uint16_t value_latchsrc = S626_LATCHSRC_AB_READ; + uint16_t enab = S626_CLKENAB_ALWAYS; + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; + + /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ + + k->set_mode(dev, k, setup, true); + s626_preload(dev, k, data[0]); + k->pulse_index(dev, k); + s626_set_latch_source(dev, k, value_latchsrc); + k->set_enable(dev, k, (enab != 0)); return insn->n; } @@ -1722,12 +2551,12 @@ static int s626_enc_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; for (n = 0; n < insn->n; n++) - data[n] = ReadLatch(dev, k); + data[n] = s626_read_latch(dev, k); return n; } @@ -1736,31 +2565,32 @@ static int s626_enc_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; - - /* Set the preload register */ - Preload(dev, k, data[0]); + /* Set the preload register */ + s626_preload(dev, k, data[0]); - /* Software index pulse forces the preload register to load */ - /* into the counter */ - k->SetLoadTrig(dev, k, 0); - k->PulseIndex(dev, k); - k->SetLoadTrig(dev, k, 2); + /* + * Software index pulse forces the preload register to load + * into the counter + */ + k->set_load_trig(dev, k, 0); + k->pulse_index(dev, k); + k->set_load_trig(dev, k, 2); return 1; } -static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage) +static void s626_write_misc2(struct comedi_device *dev, uint16_t new_image) { - DEBIwrite(dev, LP_MISC1, MISC1_WENABLE); /* enab writes to */ - /* MISC2 register. */ - DEBIwrite(dev, LP_WRMISC2, NewImage); /* Write new image to MISC2. */ - DEBIwrite(dev, LP_MISC1, MISC1_WDISABLE); /* Disable writes to MISC2. */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WENABLE); + s626_debi_write(dev, S626_LP_WRMISC2, new_image); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WDISABLE); } -static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, - size_t bsize) +static void s626_close_dma_b(struct comedi_device *dev, + struct s626_buffer_dma *pdma, size_t bsize) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); void *vbptr; @@ -1768,554 +2598,44 @@ static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, if (pdma == NULL) return; - /* find the matching allocation from the board struct */ - vbptr = pdma->LogicalBase; - vpptr = pdma->PhysicalBase; + /* find the matching allocation from the board struct */ + vbptr = pdma->logical_base; + vpptr = pdma->physical_base; if (vbptr) { pci_free_consistent(pcidev, bsize, vbptr, vpptr); - pdma->LogicalBase = NULL; - pdma->PhysicalBase = 0; + pdma->logical_base = NULL; + pdma->physical_base = 0; } } -/* ****** PRIVATE COUNTER FUNCTIONS ****** */ - -/* Reset a counter's index and overflow event capture flags. */ - -static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k) -{ - DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL, - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); -} - -static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k) -{ - DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL, - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B); -} - -/* Return counter setup in a format (COUNTER_SETUP) that is consistent */ -/* for both A and B counters. */ - -static uint16_t GetMode_A(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - register uint16_t crb; - register uint16_t setup; - - /* Fetch CRA and CRB register images. */ - cra = DEBIread(dev, k->MyCRA); - crb = DEBIread(dev, k->MyCRB); - - /* Populate the standardized counter setup bit fields. Note: */ - /* IndexSrc is restricted to ENC_X or IndxPol. */ - setup = ((cra & STDMSK_LOADSRC) /* LoadSrc = LoadSrcA. */ - |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) /* LatchSrc = LatchSrcA. */ - |((cra << (STDBIT_INTSRC - CRABIT_INTSRC_A)) & STDMSK_INTSRC) /* IntSrc = IntSrcA. */ - |((cra << (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))) & STDMSK_INDXSRC) /* IndxSrc = IndxSrcA<1>. */ - |((cra >> (CRABIT_INDXPOL_A - STDBIT_INDXPOL)) & STDMSK_INDXPOL) /* IndxPol = IndxPolA. */ - |((crb >> (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)) & STDMSK_CLKENAB)); /* ClkEnab = ClkEnabA. */ - - /* Adjust mode-dependent parameters. */ - if (cra & (2 << CRABIT_CLKSRC_A)) /* If Timer mode (ClkSrcA<1> == 1): */ - setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |((cra << (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) & STDMSK_CLKPOL) /* Set ClkPol to indicate count direction (ClkSrcA<0>). */ - |(MULT_X1 << STDBIT_CLKMULT)); /* ClkMult must be 1x in Timer mode. */ - - else /* If Counter mode (ClkSrcA<1> == 0): */ - setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) /* Indicate Counter mode. */ - |((cra >> (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) & STDMSK_CLKPOL) /* Pass through ClkPol. */ - |(((cra & CRAMSK_CLKMULT_A) == (MULT_X0 << CRABIT_CLKMULT_A)) ? /* Force ClkMult to 1x if not legal, else pass through. */ - (MULT_X1 << STDBIT_CLKMULT) : - ((cra >> (CRABIT_CLKMULT_A - - STDBIT_CLKMULT)) & STDMSK_CLKMULT))); - - /* Return adjusted counter setup. */ - return setup; -} - -static uint16_t GetMode_B(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - register uint16_t crb; - register uint16_t setup; - - /* Fetch CRA and CRB register images. */ - cra = DEBIread(dev, k->MyCRA); - crb = DEBIread(dev, k->MyCRB); - - /* Populate the standardized counter setup bit fields. Note: */ - /* IndexSrc is restricted to ENC_X or IndxPol. */ - setup = (((crb << (STDBIT_INTSRC - CRBBIT_INTSRC_B)) & STDMSK_INTSRC) /* IntSrc = IntSrcB. */ - |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) /* LatchSrc = LatchSrcB. */ - |((crb << (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)) & STDMSK_LOADSRC) /* LoadSrc = LoadSrcB. */ - |((crb << (STDBIT_INDXPOL - CRBBIT_INDXPOL_B)) & STDMSK_INDXPOL) /* IndxPol = IndxPolB. */ - |((crb >> (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) & STDMSK_CLKENAB) /* ClkEnab = ClkEnabB. */ - |((cra >> ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)) & STDMSK_INDXSRC)); /* IndxSrc = IndxSrcB<1>. */ - - /* Adjust mode-dependent parameters. */ - if ((crb & CRBMSK_CLKMULT_B) == (MULT_X0 << CRBBIT_CLKMULT_B)) /* If Extender mode (ClkMultB == MULT_X0): */ - setup |= ((CLKSRC_EXTENDER << STDBIT_CLKSRC) /* Indicate Extender mode. */ - |(MULT_X1 << STDBIT_CLKMULT) /* Indicate multiplier is 1x. */ - |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ - - else if (cra & (2 << CRABIT_CLKSRC_B)) /* If Timer mode (ClkSrcB<1> == 1): */ - setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |(MULT_X1 << STDBIT_CLKMULT) /* Indicate multiplier is 1x. */ - |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ - - else /* If Counter mode (ClkSrcB<1> == 0): */ - setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |((crb >> (CRBBIT_CLKMULT_B - STDBIT_CLKMULT)) & STDMSK_CLKMULT) /* Clock multiplier is passed through. */ - |((crb << (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) & STDMSK_CLKPOL)); /* Clock polarity is passed through. */ - - /* Return adjusted counter setup. */ - return setup; -} - -/* - * Set the operating mode for the specified counter. The setup - * parameter is treated as a COUNTER_SETUP data type. The following - * parameters are programmable (all other parms are ignored): ClkMult, - * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc. - */ - -static void SetMode_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc) -{ - struct s626_private *devpriv = dev->private; - register uint16_t cra; - register uint16_t crb; - register uint16_t setup = Setup; /* Cache the Standard Setup. */ - - /* Initialize CRA and CRB images. */ - cra = ((setup & CRAMSK_LOADSRC_A) /* Preload trigger is passed through. */ - |((setup & STDMSK_INDXSRC) >> (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1)))); /* IndexSrc is restricted to ENC_X or IndxPol. */ - - crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A /* Reset any pending CounterA event captures. */ - | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_A - STDBIT_CLKENAB))); /* Clock enable is passed through. */ - - /* Force IntSrc to Disabled if DisableIntSrc is asserted. */ - if (!DisableIntSrc) - cra |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - - CRABIT_INTSRC_A)); - - /* Populate all mode-dependent attributes of CRA & CRB images. */ - switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { - case CLKSRC_EXTENDER: /* Extender Mode: Force to Timer mode */ - /* (Extender valid only for B counters). */ - - case CLKSRC_TIMER: /* Timer Mode: */ - cra |= ((2 << CRABIT_CLKSRC_A) /* ClkSrcA<1> selects system clock */ - |((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) /* with count direction (ClkSrcA<0>) obtained from ClkPol. */ - |(1 << CRABIT_CLKPOL_A) /* ClkPolA behaves as always-on clock enable. */ - |(MULT_X1 << CRABIT_CLKMULT_A)); /* ClkMult must be 1x. */ - break; - - default: /* Counter Mode: */ - cra |= (CLKSRC_COUNTER /* Select ENC_C and ENC_D as clock/direction inputs. */ - | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) /* Clock polarity is passed through. */ - |(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? /* Force multiplier to x1 if not legal, otherwise pass through. */ - (MULT_X1 << CRABIT_CLKMULT_A) : - ((setup & STDMSK_CLKMULT) << (CRABIT_CLKMULT_A - - STDBIT_CLKMULT)))); - } - - /* Force positive index polarity if IndxSrc is software-driven only, */ - /* otherwise pass it through. */ - if (~setup & STDMSK_INDXSRC) - cra |= ((setup & STDMSK_INDXPOL) << (CRABIT_INDXPOL_A - - STDBIT_INDXPOL)); - - /* If IntSrc has been forced to Disabled, update the MISC2 interrupt */ - /* enable mask to indicate the counter interrupt is disabled. */ - if (DisableIntSrc) - devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; - - /* While retaining CounterB and LatchSrc configurations, program the */ - /* new counter operating mode. */ - DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra); - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A), crb); -} - -static void SetMode_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc) -{ - struct s626_private *devpriv = dev->private; - register uint16_t cra; - register uint16_t crb; - register uint16_t setup = Setup; /* Cache the Standard Setup. */ - - /* Initialize CRA and CRB images. */ - cra = ((setup & STDMSK_INDXSRC) << ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)); /* IndexSrc field is restricted to ENC_X or IndxPol. */ - - crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B /* Reset event captures and disable interrupts. */ - | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) /* Clock enable is passed through. */ - |((setup & STDMSK_LOADSRC) >> (STDBIT_LOADSRC - CRBBIT_LOADSRC_B))); /* Preload trigger source is passed through. */ - - /* Force IntSrc to Disabled if DisableIntSrc is asserted. */ - if (!DisableIntSrc) - crb |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - - CRBBIT_INTSRC_B)); - - /* Populate all mode-dependent attributes of CRA & CRB images. */ - switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { - case CLKSRC_TIMER: /* Timer Mode: */ - cra |= ((2 << CRABIT_CLKSRC_B) /* ClkSrcB<1> selects system clock */ - |((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); /* with direction (ClkSrcB<0>) obtained from ClkPol. */ - crb |= ((1 << CRBBIT_CLKPOL_B) /* ClkPolB behaves as always-on clock enable. */ - |(MULT_X1 << CRBBIT_CLKMULT_B)); /* ClkMultB must be 1x. */ - break; - - case CLKSRC_EXTENDER: /* Extender Mode: */ - cra |= ((2 << CRABIT_CLKSRC_B) /* ClkSrcB source is OverflowA (same as "timer") */ - |((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); /* with direction obtained from ClkPol. */ - crb |= ((1 << CRBBIT_CLKPOL_B) /* ClkPolB controls IndexB -- always set to active. */ - |(MULT_X0 << CRBBIT_CLKMULT_B)); /* ClkMultB selects OverflowA as the clock source. */ - break; - - default: /* Counter Mode: */ - cra |= (CLKSRC_COUNTER << CRABIT_CLKSRC_B); /* Select ENC_C and ENC_D as clock/direction inputs. */ - crb |= (((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) /* ClkPol is passed through. */ - |(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? /* Force ClkMult to x1 if not legal, otherwise pass through. */ - (MULT_X1 << CRBBIT_CLKMULT_B) : - ((setup & STDMSK_CLKMULT) << (CRBBIT_CLKMULT_B - - STDBIT_CLKMULT)))); - } - - /* Force positive index polarity if IndxSrc is software-driven only, */ - /* otherwise pass it through. */ - if (~setup & STDMSK_INDXSRC) - crb |= ((setup & STDMSK_INDXPOL) >> (STDBIT_INDXPOL - - CRBBIT_INDXPOL_B)); - - /* If IntSrc has been forced to Disabled, update the MISC2 interrupt */ - /* enable mask to indicate the counter interrupt is disabled. */ - if (DisableIntSrc) - devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; - - /* While retaining CounterA and LatchSrc configurations, program the */ - /* new counter operating mode. */ - DEBIreplace(dev, k->MyCRA, ~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B), cra); - DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb); -} - -/* Return/set a counter's enable. enab: 0=always enabled, 1=enabled by index. */ - -static void SetEnable_A(struct comedi_device *dev, struct enc_private *k, - uint16_t enab) -{ - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A), - enab << CRBBIT_CLKENAB_A); -} - -static void SetEnable_B(struct comedi_device *dev, struct enc_private *k, - uint16_t enab) -{ - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B), - enab << CRBBIT_CLKENAB_B); -} - -static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_A) & 1; -} - -static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_B) & 1; -} - -/* - * static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k ) - * { - * return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3; - * } - */ - -/* - * Return/set the event that will trigger transfer of the preload - * register into the counter. 0=ThisCntr_Index, 1=ThisCntr_Overflow, - * 2=OverflowA (B counters only), 3=disabled. - */ - -static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig) -{ - DEBIreplace(dev, k->MyCRA, ~CRAMSK_LOADSRC_A, - Trig << CRABIT_LOADSRC_A); -} - -static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig) -{ - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL), - Trig << CRBBIT_LOADSRC_B); -} - -static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRA) >> CRABIT_LOADSRC_A) & 3; -} - -static uint16_t GetLoadTrig_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_LOADSRC_B) & 3; -} - -/* Return/set counter interrupt source and clear any captured - * index/overflow events. IntSource: 0=Disabled, 1=OverflowOnly, - * 2=IndexOnly, 3=IndexAndOverflow. - */ - -static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource) -{ - struct s626_private *devpriv = dev->private; - - /* Reset any pending counter overflow or index captures. */ - DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL, - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); - - /* Program counter interrupt source. */ - DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A, - IntSource << CRABIT_INTSRC_A); - - /* Update MISC2 interrupt enable mask. */ - devpriv->CounterIntEnabs = - (devpriv->CounterIntEnabs & ~k-> - MyEventBits[3]) | k->MyEventBits[IntSource]; -} - -static void SetIntSrc_B(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource) -{ - struct s626_private *devpriv = dev->private; - uint16_t crb; - - /* Cache writeable CRB register image. */ - crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; - - /* Reset any pending counter overflow or index captures. */ - DEBIwrite(dev, k->MyCRB, - (uint16_t) (crb | CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B)); - - /* Program counter interrupt source. */ - DEBIwrite(dev, k->MyCRB, - (uint16_t) ((crb & ~CRBMSK_INTSRC_B) | (IntSource << - CRBBIT_INTSRC_B))); - - /* Update MISC2 interrupt enable mask. */ - devpriv->CounterIntEnabs = - (devpriv->CounterIntEnabs & ~k-> - MyEventBits[3]) | k->MyEventBits[IntSource]; -} - -static uint16_t GetIntSrc_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRA) >> CRABIT_INTSRC_A) & 3; -} - -static uint16_t GetIntSrc_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_INTSRC_B) & 3; -} - -/* Return/set the clock multiplier. */ - -/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKMULT ) | ( value << STDBIT_CLKMULT ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKMULT ) & 3; */ -/* } */ - -/* Return/set the clock polarity. */ - -/* static void SetClkPol( struct comedi_device *dev,struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKPOL ) | ( value << STDBIT_CLKPOL ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKPOL ) & 1; */ -/* } */ - -/* Return/set the clock source. */ - -/* static void SetClkSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKSRC ) | ( value << STDBIT_CLKSRC ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKSRC ) & 3; */ -/* } */ - -/* Return/set the index polarity. */ - -/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXPOL ) | ( (value != 0) << STDBIT_INDXPOL ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetIndexPol(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_INDXPOL ) & 1; */ -/* } */ - -/* Return/set the index source. */ - -/* static void SetIndexSrc(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXSRC ) | ( (value != 0) << STDBIT_INDXSRC ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetIndexSrc(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_INDXSRC ) & 1; */ -/* } */ - -/* Generate an index pulse. */ - -static void PulseIndex_A(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - - cra = DEBIread(dev, k->MyCRA); /* Pulse index. */ - DEBIwrite(dev, k->MyCRA, (uint16_t) (cra ^ CRAMSK_INDXPOL_A)); - DEBIwrite(dev, k->MyCRA, cra); -} - -static void PulseIndex_B(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t crb; - - crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; /* Pulse index. */ - DEBIwrite(dev, k->MyCRB, (uint16_t) (crb ^ CRBMSK_INDXPOL_B)); - DEBIwrite(dev, k->MyCRB, crb); -} - -static struct enc_private enc_private_data[] = { - { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR0A, - .MyCRB = LP_CR0B, - .MyLatchLsw = LP_CNTR0ALSW, - .MyEventBits = EVBITS(0), - }, { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR1A, - .MyCRB = LP_CR1B, - .MyLatchLsw = LP_CNTR1ALSW, - .MyEventBits = EVBITS(1), - }, { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR2A, - .MyCRB = LP_CR2B, - .MyLatchLsw = LP_CNTR2ALSW, - .MyEventBits = EVBITS(2), - }, { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR0A, - .MyCRB = LP_CR0B, - .MyLatchLsw = LP_CNTR0BLSW, - .MyEventBits = EVBITS(3), - }, { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR1A, - .MyCRB = LP_CR1B, - .MyLatchLsw = LP_CNTR1BLSW, - .MyEventBits = EVBITS(4), - }, { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR2A, - .MyCRB = LP_CR2B, - .MyLatchLsw = LP_CNTR2BLSW, - .MyEventBits = EVBITS(5), - }, -}; - -static void CountersInit(struct comedi_device *dev) +static void s626_counters_init(struct comedi_device *dev) { int chan; - struct enc_private *k; - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_COUNTER << BF_CLKSRC) | /* Operating mode is counter. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - (CNTDIR_UP << BF_CLKPOL) | /* Count direction is up. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); /* Enabled by index */ - - /* Disable all counter interrupts and clear any captured counter events. */ + const struct s626_enc_info *k; + uint16_t setup = + /* Preload upon index. */ + S626_SET_STD_LOADSRC(S626_LOADSRC_INDX) | + /* Disable hardware index. */ + S626_SET_STD_INDXSRC(S626_INDXSRC_SOFT) | + /* Operating mode is counter. */ + S626_SET_STD_ENCMODE(S626_ENCMODE_COUNTER) | + /* Active high clock. */ + S626_SET_STD_CLKPOL(S626_CLKPOL_POS) | + /* Clock multiplier is 1x. */ + S626_SET_STD_CLKMULT(S626_CLKMULT_1X) | + /* Enabled by index */ + S626_SET_STD_CLKENAB(S626_CLKENAB_INDEX); + + /* + * Disable all counter interrupts and clear any captured counter events. + */ for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) { - k = &encpriv[chan]; - k->SetMode(dev, k, Setup, TRUE); - k->SetIntSrc(dev, k, 0); - k->ResetCapFlags(dev, k); - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k = &s626_enc_chan_info[chan]; + k->set_mode(dev, k, setup, true); + k->set_int_src(dev, k, 0); + k->reset_cap_flags(dev, k); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); } } @@ -2326,71 +2646,75 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev) void *addr; dma_addr_t appdma; - addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma); + addr = pci_alloc_consistent(pcidev, S626_DMABUF_SIZE, &appdma); if (!addr) return -ENOMEM; - devpriv->ANABuf.LogicalBase = addr; - devpriv->ANABuf.PhysicalBase = appdma; + devpriv->ana_buf.logical_base = addr; + devpriv->ana_buf.physical_base = appdma; - addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma); + addr = pci_alloc_consistent(pcidev, S626_DMABUF_SIZE, &appdma); if (!addr) return -ENOMEM; - devpriv->RPSBuf.LogicalBase = addr; - devpriv->RPSBuf.PhysicalBase = appdma; + devpriv->rps_buf.logical_base = addr; + devpriv->rps_buf.physical_base = appdma; return 0; } -static void s626_initialize(struct comedi_device *dev) +static int s626_initialize(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; - dma_addr_t pPhysBuf; + dma_addr_t phys_buf; uint16_t chan; int i; + int ret; /* Enable DEBI and audio pins, enable I2C interface */ - s626_mc_enable(dev, MC1_DEBI | MC1_AUDIO | MC1_I2C, P_MC1); + s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C, + S626_P_MC1); /* - * Configure DEBI operating mode + * Configure DEBI operating mode * - * Local bus is 16 bits wide - * Declare DEBI transfer timeout interval - * Set up byte lane steering - * Intel-compatible local bus (DEBI never times out) + * Local bus is 16 bits wide + * Declare DEBI transfer timeout interval + * Set up byte lane steering + * Intel-compatible local bus (DEBI never times out) */ - writel(DEBI_CFG_SLAVE16 | - (DEBI_TOUT << DEBI_CFG_TOUT_BIT) | - DEBI_SWAP | DEBI_CFG_INTEL, - devpriv->mmio + P_DEBICFG); + writel(S626_DEBI_CFG_SLAVE16 | + (S626_DEBI_TOUT << S626_DEBI_CFG_TOUT_BIT) | S626_DEBI_SWAP | + S626_DEBI_CFG_INTEL, devpriv->mmio + S626_P_DEBICFG); /* Disable MMU paging */ - writel(DEBI_PAGE_DISABLE, devpriv->mmio + P_DEBIPAGE); + writel(S626_DEBI_PAGE_DISABLE, devpriv->mmio + S626_P_DEBIPAGE); /* Init GPIO so that ADC Start* is negated */ - writel(GPIO_BASE | GPIO1_HI, devpriv->mmio + P_GPIO); + writel(S626_GPIO_BASE | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); /* I2C device address for onboard eeprom (revb) */ - devpriv->I2CAdrs = 0xA0; + devpriv->i2c_adrs = 0xA0; /* * Issue an I2C ABORT command to halt any I2C * operation in progress and reset BUSY flag. */ - writel(I2C_CLKSEL | I2C_ABORT, devpriv->mmio + P_I2CSTAT); - s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2); - while (!(readl(devpriv->mmio + P_MC2) & MC2_UPLD_IIC)) - ; + writel(S626_I2C_CLKSEL | S626_I2C_ABORT, + devpriv->mmio + S626_P_I2CSTAT); + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; /* * Per SAA7146 data sheet, write to STATUS * reg twice to reset all I2C error flags. */ for (i = 0; i < 2; i++) { - writel(I2C_CLKSEL, devpriv->mmio + P_I2CSTAT); - s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2); - while (!s626_mc_test(dev, MC2_UPLD_IIC, P_MC2)) - ; + writel(S626_I2C_CLKSEL, devpriv->mmio + S626_P_I2CSTAT); + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; } /* @@ -2399,31 +2723,32 @@ static void s626_initialize(struct comedi_device *dev) * DAC data setup times are satisfied, enable DAC serial * clock out. */ - writel(ACON2_INIT, devpriv->mmio + P_ACON2); + writel(S626_ACON2_INIT, devpriv->mmio + S626_P_ACON2); /* * Set up TSL1 slot list, which is used to control the - * accumulation of ADC data: RSD1 = shift data in on SD1. - * SIB_A1 = store data uint8_t at next available location + * accumulation of ADC data: S626_RSD1 = shift data in on SD1. + * S626_SIB_A1 = store data uint8_t at next available location * in FB BUFFER1 register. */ - writel(RSD1 | SIB_A1, devpriv->mmio + P_TSL1); - writel(RSD1 | SIB_A1 | EOS, devpriv->mmio + P_TSL1 + 4); + writel(S626_RSD1 | S626_SIB_A1, devpriv->mmio + S626_P_TSL1); + writel(S626_RSD1 | S626_SIB_A1 | S626_EOS, + devpriv->mmio + S626_P_TSL1 + 4); /* Enable TSL1 slot list so that it executes all the time */ - writel(ACON1_ADCSTART, devpriv->mmio + P_ACON1); + writel(S626_ACON1_ADCSTART, devpriv->mmio + S626_P_ACON1); /* * Initialize RPS registers used for ADC */ /* Physical start of RPS program */ - writel((uint32_t)devpriv->RPSBuf.PhysicalBase, - devpriv->mmio + P_RPSADDR1); + writel((uint32_t)devpriv->rps_buf.physical_base, + devpriv->mmio + S626_P_RPSADDR1); /* RPS program performs no explicit mem writes */ - writel(0, devpriv->mmio + P_RPSPAGE1); + writel(0, devpriv->mmio + S626_P_RPSPAGE1); /* Disable RPS timeouts */ - writel(0, devpriv->mmio + P_RPS1_TOUT); + writel(0, devpriv->mmio + S626_P_RPS1_TOUT); #if 0 /* @@ -2435,38 +2760,38 @@ static void s626_initialize(struct comedi_device *dev) * because the SAA7146 ADC interface does not start up in * a defined state after a PCI reset. */ - { - uint8_t PollList; - uint16_t AdcData; - uint16_t StartVal; - uint16_t index; - unsigned int data[16]; + struct comedi_subdevice *s = dev->read_subdev; + uint8_t poll_list; + uint16_t adc_data; + uint16_t start_val; + uint16_t index; + unsigned int data[16]; - /* Create a simple polling list for analog input channel 0 */ - PollList = EOPL; - ResetADC(dev, &PollList); + /* Create a simple polling list for analog input channel 0 */ + poll_list = S626_EOPL; + s626_reset_adc(dev, &poll_list); - /* Get initial ADC value */ - s626_ai_rinsn(dev, dev->subdevices, NULL, data); - StartVal = data[0]; - - /* - * VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. - * - * Invoke ADCs until the new ADC value differs from the initial - * value or a timeout occurs. The timeout protects against the - * possibility that the driver is restarting and the ADC data is a - * fixed value resulting from the applied ADC analog input being - * unusually quiet or at the rail. - */ - for (index = 0; index < 500; index++) { - s626_ai_rinsn(dev, dev->subdevices, NULL, data); - AdcData = data[0]; - if (AdcData != StartVal) - break; - } + /* Get initial ADC value */ + s626_ai_rinsn(dev, s, NULL, data); + start_val = data[0]; + /* + * VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED + * EXECUTION. + * + * Invoke ADCs until the new ADC value differs from the initial + * value or a timeout occurs. The timeout protects against the + * possibility that the driver is restarting and the ADC data is + * a fixed value resulting from the applied ADC analog input + * being unusually quiet or at the rail. + */ + for (index = 0; index < 500; index++) { + s626_ai_rinsn(dev, s, NULL, data); + adc_data = data[0]; + if (adc_data != start_val) + break; + } } #endif /* SAA7146 BUG WORKAROUND */ @@ -2479,7 +2804,7 @@ static void s626_initialize(struct comedi_device *dev) * burst length = 1 DWORD * threshold = 1 DWORD. */ - writel(0, devpriv->mmio + P_PCI_BT_A); + writel(0, devpriv->mmio + S626_P_PCI_BT_A); /* * Init Audio2's output DMA physical addresses. The protection @@ -2487,18 +2812,18 @@ static void s626_initialize(struct comedi_device *dev) * single DWORD will be transferred each time a DMA transfer is * enabled. */ - pPhysBuf = devpriv->ANABuf.PhysicalBase + - (DAC_WDMABUF_OS * sizeof(uint32_t)); - writel((uint32_t)pPhysBuf, devpriv->mmio + P_BASEA2_OUT); - writel((uint32_t)(pPhysBuf + sizeof(uint32_t)), - devpriv->mmio + P_PROTA2_OUT); + phys_buf = devpriv->ana_buf.physical_base + + (S626_DAC_WDMABUF_OS * sizeof(uint32_t)); + writel((uint32_t)phys_buf, devpriv->mmio + S626_P_BASEA2_OUT); + writel((uint32_t)(phys_buf + sizeof(uint32_t)), + devpriv->mmio + S626_P_PROTA2_OUT); /* * Cache Audio2's output DMA buffer logical address. This is * where DAC data is buffered for A2 output DMA transfers. */ - devpriv->pDacWBuf = (uint32_t *)devpriv->ANABuf.LogicalBase + - DAC_WDMABUF_OS; + devpriv->dac_wbuf = (uint32_t *)devpriv->ana_buf.logical_base + + S626_DAC_WDMABUF_OS; /* * Audio2's output channels does not use paging. The @@ -2506,7 +2831,7 @@ static void s626_initialize(struct comedi_device *dev) * DMAC will automatically halt and its PCI address pointer * will be reset when the protection address is reached. */ - writel(8, devpriv->mmio + P_PAGEA2_OUT); + writel(8, devpriv->mmio + S626_P_PAGEA2_OUT); /* * Initialize time slot list 2 (TSL2), which is used to control @@ -2521,7 +2846,8 @@ static void s626_initialize(struct comedi_device *dev) */ /* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2 */ - writel(XSD2 | RSD3 | SIB_A2 | EOS, devpriv->mmio + VECTPORT(0)); + writel(S626_XSD2 | S626_RSD3 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); /* * Initialize slot 1, which is constant. Slot 1 causes a @@ -2533,18 +2859,20 @@ static void s626_initialize(struct comedi_device *dev) */ /* Slot 1: Fetch DWORD from Audio2's output FIFO */ - writel(LF_A2, devpriv->mmio + VECTPORT(1)); + writel(S626_LF_A2, devpriv->mmio + S626_VECTPORT(1)); /* Start DAC's audio interface (TSL2) running */ - writel(ACON1_DACSTART, devpriv->mmio + P_ACON1); + writel(S626_ACON1_DACSTART, devpriv->mmio + S626_P_ACON1); /* * Init Trim DACs to calibrated values. Do it twice because the * SAA7146 audio channel does not always reset properly and * sometimes causes the first few TrimDAC writes to malfunction. */ - LoadTrimDACs(dev); - LoadTrimDACs(dev); + s626_load_trim_dacs(dev); + ret = s626_load_trim_dacs(dev); + if (ret) + return ret; /* * Manually init all gate array hardware in case this is a soft @@ -2558,11 +2886,14 @@ static void s626_initialize(struct comedi_device *dev) * Init all DAC outputs to 0V and init all DAC setpoint and * polarity images. */ - for (chan = 0; chan < S626_DAC_CHANNELS; chan++) - SetDAC(dev, chan, 0); + for (chan = 0; chan < S626_DAC_CHANNELS; chan++) { + ret = s626_set_dac(dev, chan, 0); + if (ret) + return ret; + } /* Init counters */ - CountersInit(dev); + s626_counters_init(dev); /* * Without modifying the state of the Battery Backup enab, disable @@ -2570,11 +2901,13 @@ static void s626_initialize(struct comedi_device *dev) * standard DIO (vs. counter overflow) mode, disable the battery * charger, and reset the watchdog interval selector to zero. */ - WriteMISC2(dev, (uint16_t)(DEBIread(dev, LP_RDMISC2) & - MISC2_BATT_ENABLE)); + s626_write_misc2(dev, (s626_debi_read(dev, S626_LP_RDMISC2) & + S626_MISC2_BATT_ENABLE)); /* Initialize the digital I/O subsystem */ s626_dio_init(dev); + + return 0; } static int s626_auto_attach(struct comedi_device *dev, @@ -2585,10 +2918,9 @@ static int s626_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; ret = comedi_pci_enable(dev); if (ret) @@ -2599,10 +2931,10 @@ static int s626_auto_attach(struct comedi_device *dev, return -ENOMEM; /* disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* soft reset */ - writel(MC1_SOFT_RESET, devpriv->mmio + P_MC1); + writel(S626_MC1_SOFT_RESET, devpriv->mmio + S626_P_MC1); /* DMA FIXME DMA// */ @@ -2625,7 +2957,7 @@ static int s626_auto_attach(struct comedi_device *dev, s = &dev->subdevices[0]; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_DIFF; s->n_chan = S626_ADC_CHANNELS; s->maxdata = 0x3fff; s->range_table = &s626_range_table; @@ -2633,6 +2965,7 @@ static int s626_auto_attach(struct comedi_device *dev, s->insn_read = s626_ai_insn_read; if (dev->irq) { dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; s->do_cmd = s626_ai_cmd; s->do_cmdtest = s626_ai_cmdtest; s->cancel = s626_ai_cancel; @@ -2681,7 +3014,7 @@ static int s626_auto_attach(struct comedi_device *dev, s->io_bits = 0xffff; s->private = (void *)2; /* DIO group 2 */ s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; + s->insn_config = s626_dio_insn_config; s->insn_bits = s626_dio_insn_bits; s = &dev->subdevices[5]; @@ -2690,15 +3023,14 @@ static int s626_auto_attach(struct comedi_device *dev, s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; s->n_chan = S626_ENCODER_CHANNELS; s->maxdata = 0xffffff; - s->private = enc_private_data; s->range_table = &range_unknown; s->insn_config = s626_enc_insn_config; s->insn_read = s626_enc_insn_read; s->insn_write = s626_enc_insn_write; - s626_initialize(dev); - - dev_info(dev->class_dev, "%s attached\n", dev->board_name); + ret = s626_initialize(dev); + if (ret) + return ret; return 0; } @@ -2714,20 +3046,22 @@ static void s626_detach(struct comedi_device *dev) if (devpriv->mmio) { /* interrupt mask */ /* Disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* Clear board's IRQ status flag */ - writel(IRQ_GPIO3 | IRQ_RPS1, - devpriv->mmio + P_ISR); + writel(S626_IRQ_GPIO3 | S626_IRQ_RPS1, + devpriv->mmio + S626_P_ISR); - /* Disable the watchdog timer and battery charger. */ - WriteMISC2(dev, 0); + /* Disable the watchdog timer and battery charger. */ + s626_write_misc2(dev, 0); /* Close all interfaces on 7146 device */ - writel(MC1_SHUTDOWN, devpriv->mmio + P_MC1); - writel(ACON1_BASE, devpriv->mmio + P_ACON1); + writel(S626_MC1_SHUTDOWN, devpriv->mmio + S626_P_MC1); + writel(S626_ACON1_BASE, devpriv->mmio + S626_P_ACON1); - CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE); - CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE); + s626_close_dma_b(dev, &devpriv->rps_buf, + S626_DMABUF_SIZE); + s626_close_dma_b(dev, &devpriv->ana_buf, + S626_DMABUF_SIZE); } if (dev->irq) @@ -2756,9 +3090,9 @@ static int s626_pci_probe(struct pci_dev *dev, * also subvendor:subdevice ids, because otherwise it will conflict with * Philips SAA7146 media/dvb based cards. */ -static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = { - { PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, - PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0 }, +static const struct pci_device_id s626_pci_table[] = { + { PCI_DEVICE_SUB(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, + 0x6000, 0x0272) }, { 0 } }; MODULE_DEVICE_TABLE(pci, s626_pci_table); diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h index d2756b83b62..33b72739c1c 100644 --- a/drivers/staging/comedi/drivers/s626.h +++ b/drivers/staging/comedi/drivers/s626.h @@ -1,692 +1,774 @@ /* - comedi/drivers/s626.h - Sensoray s626 Comedi driver, header file - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - Based on Sensoray Model 626 Linux driver Version 0.2 - Copyright (C) 2002-2004 Sensoray Co., Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ - -/* - Driver: s626.o (s626.ko) - Description: Sensoray 626 driver - Devices: Sensoray s626 - Authors: Gianluca Palli <gpalli@deis.unibo.it>, - Updated: Thu, 12 Jul 2005 - Status: experimental - - Configuration Options: - analog input: - none - - analog output: - none - - digital channel: - s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels - supported configuration options: - INSN_CONFIG_DIO_QUERY - COMEDI_INPUT - COMEDI_OUTPUT - - encoder: - Every channel must be configured before reading. - - Example code - - insn.insn=INSN_CONFIG; // configuration instruction - insn.n=1; // number of operation (must be 1) - insn.data=&initialvalue; // initial value loaded into encoder - // during configuration - insn.subdev=5; // encoder subdevice - insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); // encoder_channel - // to configure - - comedi_do_insn(cf,&insn); // executing configuration -*/ - -#if !defined(TRUE) -#define TRUE (1) -#endif - -#if !defined(FALSE) -#define FALSE (0) -#endif - -#include <linux/slab.h> - -#define S626_SIZE 0x0200 -#define DMABUF_SIZE 4096 /* 4k pages */ + * comedi/drivers/s626.h + * Sensoray s626 Comedi driver, header file + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * Based on Sensoray Model 626 Linux driver Version 0.2 + * Copyright (C) 2002-2004 Sensoray Co., Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef S626_H_INCLUDED +#define S626_H_INCLUDED + +#define S626_DMABUF_SIZE 4096 /* 4k pages */ #define S626_ADC_CHANNELS 16 #define S626_DAC_CHANNELS 4 #define S626_ENCODER_CHANNELS 6 #define S626_DIO_CHANNELS 48 -#define S626_DIO_BANKS 3 /* Number of DIO groups. */ -#define S626_DIO_EXTCHANS 40 /* Number of */ - /* extended-capability */ - /* DIO channels. */ - -#define NUM_TRIMDACS 12 /* Number of valid TrimDAC channels. */ - -/* PCI bus interface types. */ -#define INTEL 1 /* Intel bus type. */ -#define MOTOROLA 2 /* Motorola bus type. */ +#define S626_DIO_BANKS 3 /* Number of DIO groups. */ +#define S626_DIO_EXTCHANS 40 /* Number of extended-capability + * DIO channels. */ -#define PLATFORM INTEL /* *** SELECT PLATFORM TYPE *** */ +#define S626_NUM_TRIMDACS 12 /* Number of valid TrimDAC channels. */ -#define RANGE_5V 0x10 /* +/-5V range */ -#define RANGE_10V 0x00 /* +/-10V range */ +/* PCI bus interface types. */ +#define S626_INTEL 1 /* Intel bus type. */ +#define S626_MOTOROLA 2 /* Motorola bus type. */ -#define EOPL 0x80 /* End of ADC poll list marker. */ -#define GSEL_BIPOLAR5V 0x00F0 /* LP_GSEL setting for 5V bipolar range. */ -#define GSEL_BIPOLAR10V 0x00A0 /* LP_GSEL setting for 10V bipolar range. */ +#define S626_PLATFORM S626_INTEL /* *** SELECT PLATFORM TYPE *** */ -/* Error codes that must be visible to this base class. */ -#define ERR_ILLEGAL_PARM 0x00010000 /* Illegal function parameter value was specified. */ -#define ERR_I2C 0x00020000 /* I2C error. */ -#define ERR_COUNTERSETUP 0x00200000 /* Illegal setup specified for counter channel. */ -#define ERR_DEBI_TIMEOUT 0x00400000 /* DEBI transfer timed out. */ +#define S626_RANGE_5V 0x10 /* +/-5V range */ +#define S626_RANGE_10V 0x00 /* +/-10V range */ -/* Organization (physical order) and size (in DWORDs) of logical DMA buffers contained by ANA_DMABUF. */ -#define ADC_DMABUF_DWORDS 40 /* ADC DMA buffer must hold 16 samples, plus pre/post garbage samples. */ -#define DAC_WDMABUF_DWORDS 1 /* DAC output DMA buffer holds a single sample. */ +#define S626_EOPL 0x80 /* End of ADC poll list marker. */ +#define S626_GSEL_BIPOLAR5V 0x00F0 /* S626_LP_GSEL setting 5V bipolar. */ +#define S626_GSEL_BIPOLAR10V 0x00A0 /* S626_LP_GSEL setting 10V bipolar. */ -/* All remaining space in 4KB DMA buffer is available for the RPS1 program. */ +/* Error codes that must be visible to this base class. */ +#define S626_ERR_ILLEGAL_PARM 0x00010000 /* Illegal function parameter + * value was specified. */ +#define S626_ERR_I2C 0x00020000 /* I2C error. */ +#define S626_ERR_COUNTERSETUP 0x00200000 /* Illegal setup specified for + * counter channel. */ +#define S626_ERR_DEBI_TIMEOUT 0x00400000 /* DEBI transfer timed out. */ -/* Address offsets, in DWORDS, from base of DMA buffer. */ -#define DAC_WDMABUF_OS ADC_DMABUF_DWORDS - -/* Interrupt enab bit in ISR and IER. */ -#define IRQ_GPIO3 0x00000040 /* IRQ enable for GPIO3. */ -#define IRQ_RPS1 0x10000000 -#define ISR_AFOU 0x00000800 +/* + * Organization (physical order) and size (in DWORDs) of logical DMA buffers + * contained by ANA_DMABUF. + */ +#define S626_ADC_DMABUF_DWORDS 40 /* ADC DMA buffer must hold 16 samples, + * plus pre/post garbage samples. */ +#define S626_DAC_WDMABUF_DWORDS 1 /* DAC output DMA buffer holds a single + * sample. */ + +/* All remaining space in 4KB DMA buffer is available for the RPS1 program. */ + +/* Address offsets, in DWORDS, from base of DMA buffer. */ +#define S626_DAC_WDMABUF_OS S626_ADC_DMABUF_DWORDS + +/* Interrupt enable bit in ISR and IER. */ +#define S626_IRQ_GPIO3 0x00000040 /* IRQ enable for GPIO3. */ +#define S626_IRQ_RPS1 0x10000000 +#define S626_ISR_AFOU 0x00000800 /* Audio fifo under/overflow detected. */ -#define IRQ_COINT1A 0x0400 /* conter 1A overflow interrupt mask */ -#define IRQ_COINT1B 0x0800 /* conter 1B overflow interrupt mask */ -#define IRQ_COINT2A 0x1000 /* conter 2A overflow interrupt mask */ -#define IRQ_COINT2B 0x2000 /* conter 2B overflow interrupt mask */ -#define IRQ_COINT3A 0x4000 /* conter 3A overflow interrupt mask */ -#define IRQ_COINT3B 0x8000 /* conter 3B overflow interrupt mask */ - -/* RPS command codes. */ -#define RPS_CLRSIGNAL 0x00000000 /* CLEAR SIGNAL */ -#define RPS_SETSIGNAL 0x10000000 /* SET SIGNAL */ -#define RPS_NOP 0x00000000 /* NOP */ -#define RPS_PAUSE 0x20000000 /* PAUSE */ -#define RPS_UPLOAD 0x40000000 /* UPLOAD */ -#define RPS_JUMP 0x80000000 /* JUMP */ -#define RPS_LDREG 0x90000100 /* LDREG (1 uint32_t only) */ -#define RPS_STREG 0xA0000100 /* STREG (1 uint32_t only) */ -#define RPS_STOP 0x50000000 /* STOP */ -#define RPS_IRQ 0x60000000 /* IRQ */ - -#define RPS_LOGICAL_OR 0x08000000 /* Logical OR conditionals. */ -#define RPS_INVERT 0x04000000 /* Test for negated semaphores. */ -#define RPS_DEBI 0x00000002 /* DEBI done */ - -#define RPS_SIG0 0x00200000 /* RPS semaphore 0 (used by ADC). */ -#define RPS_SIG1 0x00400000 /* RPS semaphore 1 (used by DAC). */ -#define RPS_SIG2 0x00800000 /* RPS semaphore 2 (not used). */ -#define RPS_GPIO2 0x00080000 /* RPS GPIO2 */ -#define RPS_GPIO3 0x00100000 /* RPS GPIO3 */ - -#define RPS_SIGADC RPS_SIG0 /* Trigger/status for ADC's RPS program. */ -#define RPS_SIGDAC RPS_SIG1 /* Trigger/status for DAC's RPS program. */ - -/* RPS clock parameters. */ -#define RPSCLK_SCALAR 8 /* This is apparent ratio of PCI/RPS clks (undocumented!!). */ -#define RPSCLK_PER_US (33 / RPSCLK_SCALAR) /* Number of RPS clocks in one microsecond. */ - -/* Event counter source addresses. */ -#define SBA_RPS_A0 0x27 /* Time of RPS0 busy, in PCI clocks. */ - -/* GPIO constants. */ -#define GPIO_BASE 0x10004000 /* GPIO 0,2,3 = inputs, GPIO3 = IRQ; GPIO1 = out. */ -#define GPIO1_LO 0x00000000 /* GPIO1 set to LOW. */ -#define GPIO1_HI 0x00001000 /* GPIO1 set to HIGH. */ - -/* Primary Status Register (PSR) constants. */ -#define PSR_DEBI_E 0x00040000 /* DEBI event flag. */ -#define PSR_DEBI_S 0x00080000 /* DEBI status flag. */ -#define PSR_A2_IN 0x00008000 /* Audio output DMA2 protection address reached. */ -#define PSR_AFOU 0x00000800 /* Audio FIFO under/overflow detected. */ -#define PSR_GPIO2 0x00000020 /* GPIO2 input pin: 0=AdcBusy, 1=AdcIdle. */ -#define PSR_EC0S 0x00000001 /* Event counter 0 threshold reached. */ - -/* Secondary Status Register (SSR) constants. */ -#define SSR_AF2_OUT 0x00000200 /* Audio 2 output FIFO under/overflow detected. */ - -/* Master Control Register 1 (MC1) constants. */ -#define MC1_SOFT_RESET 0x80000000 /* Invoke 7146 soft reset. */ -#define MC1_SHUTDOWN 0x3FFF0000 /* Shut down all MC1-controlled enables. */ - -#define MC1_ERPS1 0x2000 /* enab/disable RPS task 1. */ -#define MC1_ERPS0 0x1000 /* enab/disable RPS task 0. */ -#define MC1_DEBI 0x0800 /* enab/disable DEBI pins. */ -#define MC1_AUDIO 0x0200 /* enab/disable audio port pins. */ -#define MC1_I2C 0x0100 /* enab/disable I2C interface. */ -#define MC1_A2OUT 0x0008 /* enab/disable transfer on A2 out. */ -#define MC1_A2IN 0x0004 /* enab/disable transfer on A2 in. */ -#define MC1_A1IN 0x0001 /* enab/disable transfer on A1 in. */ - -/* Master Control Register 2 (MC2) constants. */ -#define MC2_UPLD_DEBIq 0x00020002 /* Upload DEBI registers. */ -#define MC2_UPLD_IICq 0x00010001 /* Upload I2C registers. */ -#define MC2_RPSSIG2_ONq 0x20002000 /* Assert RPS_SIG2. */ -#define MC2_RPSSIG1_ONq 0x10001000 /* Assert RPS_SIG1. */ -#define MC2_RPSSIG0_ONq 0x08000800 /* Assert RPS_SIG0. */ -#define MC2_UPLD_DEBI_MASKq 0x00000002 /* Upload DEBI mask. */ -#define MC2_UPLD_IIC_MASKq 0x00000001 /* Upload I2C mask. */ -#define MC2_RPSSIG2_MASKq 0x00002000 /* RPS_SIG2 bit mask. */ -#define MC2_RPSSIG1_MASKq 0x00001000 /* RPS_SIG1 bit mask. */ -#define MC2_RPSSIG0_MASKq 0x00000800 /* RPS_SIG0 bit mask. */ - -#define MC2_DELAYTRIG_4USq MC2_RPSSIG1_ON -#define MC2_DELAYBUSY_4USq MC2_RPSSIG1_MASK - -#define MC2_DELAYTRIG_6USq MC2_RPSSIG2_ON -#define MC2_DELAYBUSY_6USq MC2_RPSSIG2_MASK - -#define MC2_UPLD_DEBI 0x0002 /* Upload DEBI. */ -#define MC2_UPLD_IIC 0x0001 /* Upload I2C. */ -#define MC2_RPSSIG2 0x2000 /* RPS signal 2 (not used). */ -#define MC2_RPSSIG1 0x1000 /* RPS signal 1 (DAC RPS busy). */ -#define MC2_RPSSIG0 0x0800 /* RPS signal 0 (ADC RPS busy). */ - -#define MC2_ADC_RPS MC2_RPSSIG0 /* ADC RPS busy. */ -#define MC2_DAC_RPS MC2_RPSSIG1 /* DAC RPS busy. */ - -/* ***** oldies ***** */ -#define MC2_UPLD_DEBIQ 0x00020002 /* Upload DEBI registers. */ -#define MC2_UPLD_IICQ 0x00010001 /* Upload I2C registers. */ - -/* PCI BUS (SAA7146) REGISTER ADDRESS OFFSETS */ -#define P_PCI_BT_A 0x004C /* Audio DMA burst/threshold control. */ -#define P_DEBICFG 0x007C /* DEBI configuration. */ -#define P_DEBICMD 0x0080 /* DEBI command. */ -#define P_DEBIPAGE 0x0084 /* DEBI page. */ -#define P_DEBIAD 0x0088 /* DEBI target address. */ -#define P_I2CCTRL 0x008C /* I2C control. */ -#define P_I2CSTAT 0x0090 /* I2C status. */ -#define P_BASEA2_IN 0x00AC /* Audio input 2 base physical DMAbuf +#define S626_IRQ_COINT1A 0x0400 /* counter 1A overflow interrupt mask */ +#define S626_IRQ_COINT1B 0x0800 /* counter 1B overflow interrupt mask */ +#define S626_IRQ_COINT2A 0x1000 /* counter 2A overflow interrupt mask */ +#define S626_IRQ_COINT2B 0x2000 /* counter 2B overflow interrupt mask */ +#define S626_IRQ_COINT3A 0x4000 /* counter 3A overflow interrupt mask */ +#define S626_IRQ_COINT3B 0x8000 /* counter 3B overflow interrupt mask */ + +/* RPS command codes. */ +#define S626_RPS_CLRSIGNAL 0x00000000 /* CLEAR SIGNAL */ +#define S626_RPS_SETSIGNAL 0x10000000 /* SET SIGNAL */ +#define S626_RPS_NOP 0x00000000 /* NOP */ +#define S626_RPS_PAUSE 0x20000000 /* PAUSE */ +#define S626_RPS_UPLOAD 0x40000000 /* UPLOAD */ +#define S626_RPS_JUMP 0x80000000 /* JUMP */ +#define S626_RPS_LDREG 0x90000100 /* LDREG (1 uint32_t only) */ +#define S626_RPS_STREG 0xA0000100 /* STREG (1 uint32_t only) */ +#define S626_RPS_STOP 0x50000000 /* STOP */ +#define S626_RPS_IRQ 0x60000000 /* IRQ */ + +#define S626_RPS_LOGICAL_OR 0x08000000 /* Logical OR conditionals. */ +#define S626_RPS_INVERT 0x04000000 /* Test for negated + * semaphores. */ +#define S626_RPS_DEBI 0x00000002 /* DEBI done */ + +#define S626_RPS_SIG0 0x00200000 /* RPS semaphore 0 + * (used by ADC). */ +#define S626_RPS_SIG1 0x00400000 /* RPS semaphore 1 + * (used by DAC). */ +#define S626_RPS_SIG2 0x00800000 /* RPS semaphore 2 + * (not used). */ +#define S626_RPS_GPIO2 0x00080000 /* RPS GPIO2 */ +#define S626_RPS_GPIO3 0x00100000 /* RPS GPIO3 */ + +#define S626_RPS_SIGADC S626_RPS_SIG0 /* Trigger/status for + * ADC's RPS program. */ +#define S626_RPS_SIGDAC S626_RPS_SIG1 /* Trigger/status for + * DAC's RPS program. */ + +/* RPS clock parameters. */ +#define S626_RPSCLK_SCALAR 8 /* This is apparent ratio of + * PCI/RPS clks (undocumented!!). */ +#define S626_RPSCLK_PER_US (33 / S626_RPSCLK_SCALAR) + /* Number of RPS clocks in one + * microsecond. */ + +/* Event counter source addresses. */ +#define S626_SBA_RPS_A0 0x27 /* Time of RPS0 busy, in PCI clocks. */ + +/* GPIO constants. */ +#define S626_GPIO_BASE 0x10004000 /* GPIO 0,2,3 = inputs, + * GPIO3 = IRQ; GPIO1 = out. */ +#define S626_GPIO1_LO 0x00000000 /* GPIO1 set to LOW. */ +#define S626_GPIO1_HI 0x00001000 /* GPIO1 set to HIGH. */ + +/* Primary Status Register (PSR) constants. */ +#define S626_PSR_DEBI_E 0x00040000 /* DEBI event flag. */ +#define S626_PSR_DEBI_S 0x00080000 /* DEBI status flag. */ +#define S626_PSR_A2_IN 0x00008000 /* Audio output DMA2 protection + * address reached. */ +#define S626_PSR_AFOU 0x00000800 /* Audio FIFO under/overflow + * detected. */ +#define S626_PSR_GPIO2 0x00000020 /* GPIO2 input pin: 0=AdcBusy, + * 1=AdcIdle. */ +#define S626_PSR_EC0S 0x00000001 /* Event counter 0 threshold + * reached. */ + +/* Secondary Status Register (SSR) constants. */ +#define S626_SSR_AF2_OUT 0x00000200 /* Audio 2 output FIFO + * under/overflow detected. */ + +/* Master Control Register 1 (MC1) constants. */ +#define S626_MC1_SOFT_RESET 0x80000000 /* Invoke 7146 soft reset. */ +#define S626_MC1_SHUTDOWN 0x3FFF0000 /* Shut down all MC1-controlled + * enables. */ + +#define S626_MC1_ERPS1 0x2000 /* Enab/disable RPS task 1. */ +#define S626_MC1_ERPS0 0x1000 /* Enab/disable RPS task 0. */ +#define S626_MC1_DEBI 0x0800 /* Enab/disable DEBI pins. */ +#define S626_MC1_AUDIO 0x0200 /* Enab/disable audio port pins. */ +#define S626_MC1_I2C 0x0100 /* Enab/disable I2C interface. */ +#define S626_MC1_A2OUT 0x0008 /* Enab/disable transfer on A2 out. */ +#define S626_MC1_A2IN 0x0004 /* Enab/disable transfer on A2 in. */ +#define S626_MC1_A1IN 0x0001 /* Enab/disable transfer on A1 in. */ + +/* Master Control Register 2 (MC2) constants. */ +#define S626_MC2_UPLD_DEBI 0x0002 /* Upload DEBI. */ +#define S626_MC2_UPLD_IIC 0x0001 /* Upload I2C. */ +#define S626_MC2_RPSSIG2 0x2000 /* RPS signal 2 (not used). */ +#define S626_MC2_RPSSIG1 0x1000 /* RPS signal 1 (DAC RPS busy). */ +#define S626_MC2_RPSSIG0 0x0800 /* RPS signal 0 (ADC RPS busy). */ + +#define S626_MC2_ADC_RPS S626_MC2_RPSSIG0 /* ADC RPS busy. */ +#define S626_MC2_DAC_RPS S626_MC2_RPSSIG1 /* DAC RPS busy. */ + +/* PCI BUS (SAA7146) REGISTER ADDRESS OFFSETS */ +#define S626_P_PCI_BT_A 0x004C /* Audio DMA burst/threshold control. */ +#define S626_P_DEBICFG 0x007C /* DEBI configuration. */ +#define S626_P_DEBICMD 0x0080 /* DEBI command. */ +#define S626_P_DEBIPAGE 0x0084 /* DEBI page. */ +#define S626_P_DEBIAD 0x0088 /* DEBI target address. */ +#define S626_P_I2CCTRL 0x008C /* I2C control. */ +#define S626_P_I2CSTAT 0x0090 /* I2C status. */ +#define S626_P_BASEA2_IN 0x00AC /* Audio input 2 base physical DMAbuf * address. */ -#define P_PROTA2_IN 0x00B0 /* Audio input 2 physical DMAbuf +#define S626_P_PROTA2_IN 0x00B0 /* Audio input 2 physical DMAbuf * protection address. */ -#define P_PAGEA2_IN 0x00B4 /* Audio input 2 paging attributes. */ -#define P_BASEA2_OUT 0x00B8 /* Audio output 2 base physical DMAbuf +#define S626_P_PAGEA2_IN 0x00B4 /* Audio input 2 paging attributes. */ +#define S626_P_BASEA2_OUT 0x00B8 /* Audio output 2 base physical DMAbuf * address. */ -#define P_PROTA2_OUT 0x00BC /* Audio output 2 physical DMAbuf +#define S626_P_PROTA2_OUT 0x00BC /* Audio output 2 physical DMAbuf * protection address. */ -#define P_PAGEA2_OUT 0x00C0 /* Audio output 2 paging attributes. */ -#define P_RPSPAGE0 0x00C4 /* RPS0 page. */ -#define P_RPSPAGE1 0x00C8 /* RPS1 page. */ -#define P_RPS0_TOUT 0x00D4 /* RPS0 time-out. */ -#define P_RPS1_TOUT 0x00D8 /* RPS1 time-out. */ -#define P_IER 0x00DC /* Interrupt enable. */ -#define P_GPIO 0x00E0 /* General-purpose I/O. */ -#define P_EC1SSR 0x00E4 /* Event counter set 1 source select. */ -#define P_ECT1R 0x00EC /* Event counter threshold set 1. */ -#define P_ACON1 0x00F4 /* Audio control 1. */ -#define P_ACON2 0x00F8 /* Audio control 2. */ -#define P_MC1 0x00FC /* Master control 1. */ -#define P_MC2 0x0100 /* Master control 2. */ -#define P_RPSADDR0 0x0104 /* RPS0 instruction pointer. */ -#define P_RPSADDR1 0x0108 /* RPS1 instruction pointer. */ -#define P_ISR 0x010C /* Interrupt status. */ -#define P_PSR 0x0110 /* Primary status. */ -#define P_SSR 0x0114 /* Secondary status. */ -#define P_EC1R 0x0118 /* Event counter set 1. */ -#define P_ADP4 0x0138 /* Logical audio DMA pointer of audio +#define S626_P_PAGEA2_OUT 0x00C0 /* Audio output 2 paging attributes. */ +#define S626_P_RPSPAGE0 0x00C4 /* RPS0 page. */ +#define S626_P_RPSPAGE1 0x00C8 /* RPS1 page. */ +#define S626_P_RPS0_TOUT 0x00D4 /* RPS0 time-out. */ +#define S626_P_RPS1_TOUT 0x00D8 /* RPS1 time-out. */ +#define S626_P_IER 0x00DC /* Interrupt enable. */ +#define S626_P_GPIO 0x00E0 /* General-purpose I/O. */ +#define S626_P_EC1SSR 0x00E4 /* Event counter set 1 source select. */ +#define S626_P_ECT1R 0x00EC /* Event counter threshold set 1. */ +#define S626_P_ACON1 0x00F4 /* Audio control 1. */ +#define S626_P_ACON2 0x00F8 /* Audio control 2. */ +#define S626_P_MC1 0x00FC /* Master control 1. */ +#define S626_P_MC2 0x0100 /* Master control 2. */ +#define S626_P_RPSADDR0 0x0104 /* RPS0 instruction pointer. */ +#define S626_P_RPSADDR1 0x0108 /* RPS1 instruction pointer. */ +#define S626_P_ISR 0x010C /* Interrupt status. */ +#define S626_P_PSR 0x0110 /* Primary status. */ +#define S626_P_SSR 0x0114 /* Secondary status. */ +#define S626_P_EC1R 0x0118 /* Event counter set 1. */ +#define S626_P_ADP4 0x0138 /* Logical audio DMA pointer of audio * input FIFO A2_IN. */ -#define P_FB_BUFFER1 0x0144 /* Audio feedback buffer 1. */ -#define P_FB_BUFFER2 0x0148 /* Audio feedback buffer 2. */ -#define P_TSL1 0x0180 /* Audio time slot list 1. */ -#define P_TSL2 0x01C0 /* Audio time slot list 2. */ +#define S626_P_FB_BUFFER1 0x0144 /* Audio feedback buffer 1. */ +#define S626_P_FB_BUFFER2 0x0148 /* Audio feedback buffer 2. */ +#define S626_P_TSL1 0x0180 /* Audio time slot list 1. */ +#define S626_P_TSL2 0x01C0 /* Audio time slot list 2. */ -/* LOCAL BUS (GATE ARRAY) REGISTER ADDRESS OFFSETS */ -/* Analog I/O registers: */ -#define LP_DACPOL 0x0082 /* Write DAC polarity. */ -#define LP_GSEL 0x0084 /* Write ADC gain. */ -#define LP_ISEL 0x0086 /* Write ADC channel select. */ +/* LOCAL BUS (GATE ARRAY) REGISTER ADDRESS OFFSETS */ +/* Analog I/O registers: */ +#define S626_LP_DACPOL 0x0082 /* Write DAC polarity. */ +#define S626_LP_GSEL 0x0084 /* Write ADC gain. */ +#define S626_LP_ISEL 0x0086 /* Write ADC channel select. */ /* Digital I/O registers */ -#define LP_RDDIN(x) (0x0040 + (x) * 0x10) /* R: digital input */ -#define LP_WRINTSEL(x) (0x0042 + (x) * 0x10) /* W: int enable */ -#define LP_WREDGSEL(x) (0x0044 + (x) * 0x10) /* W: edge selection */ -#define LP_WRCAPSEL(x) (0x0046 + (x) * 0x10) /* W: capture enable */ -#define LP_RDCAPFLG(x) (0x0048 + (x) * 0x10) /* R: edges captured */ -#define LP_WRDOUT(x) (0x0048 + (x) * 0x10) /* W: digital output */ -#define LP_RDINTSEL(x) (0x004a + (x) * 0x10) /* R: int enable */ -#define LP_RDEDGSEL(x) (0x004c + (x) * 0x10) /* R: edge selection */ -#define LP_RDCAPSEL(x) (0x004e + (x) * 0x10) /* R: capture enable */ - -/* Counter Registers (read/write): */ -#define LP_CR0A 0x0000 /* 0A setup register. */ -#define LP_CR0B 0x0002 /* 0B setup register. */ -#define LP_CR1A 0x0004 /* 1A setup register. */ -#define LP_CR1B 0x0006 /* 1B setup register. */ -#define LP_CR2A 0x0008 /* 2A setup register. */ -#define LP_CR2B 0x000A /* 2B setup register. */ - -/* Counter PreLoad (write) and Latch (read) Registers: */ -#define LP_CNTR0ALSW 0x000C /* 0A lsw. */ -#define LP_CNTR0AMSW 0x000E /* 0A msw. */ -#define LP_CNTR0BLSW 0x0010 /* 0B lsw. */ -#define LP_CNTR0BMSW 0x0012 /* 0B msw. */ -#define LP_CNTR1ALSW 0x0014 /* 1A lsw. */ -#define LP_CNTR1AMSW 0x0016 /* 1A msw. */ -#define LP_CNTR1BLSW 0x0018 /* 1B lsw. */ -#define LP_CNTR1BMSW 0x001A /* 1B msw. */ -#define LP_CNTR2ALSW 0x001C /* 2A lsw. */ -#define LP_CNTR2AMSW 0x001E /* 2A msw. */ -#define LP_CNTR2BLSW 0x0020 /* 2B lsw. */ -#define LP_CNTR2BMSW 0x0022 /* 2B msw. */ - -/* Miscellaneous Registers (read/write): */ -#define LP_MISC1 0x0088 /* Read/write Misc1. */ -#define LP_WRMISC2 0x0090 /* Write Misc2. */ -#define LP_RDMISC2 0x0082 /* Read Misc2. */ - -/* Bit masks for MISC1 register that are the same for reads and writes. */ -#define MISC1_WENABLE 0x8000 /* enab writes to MISC2 (except Clear +#define S626_LP_RDDIN(x) (0x0040 + (x) * 0x10) /* R: digital input */ +#define S626_LP_WRINTSEL(x) (0x0042 + (x) * 0x10) /* W: int enable */ +#define S626_LP_WREDGSEL(x) (0x0044 + (x) * 0x10) /* W: edge selection */ +#define S626_LP_WRCAPSEL(x) (0x0046 + (x) * 0x10) /* W: capture enable */ +#define S626_LP_RDCAPFLG(x) (0x0048 + (x) * 0x10) /* R: edges captured */ +#define S626_LP_WRDOUT(x) (0x0048 + (x) * 0x10) /* W: digital output */ +#define S626_LP_RDINTSEL(x) (0x004a + (x) * 0x10) /* R: int enable */ +#define S626_LP_RDEDGSEL(x) (0x004c + (x) * 0x10) /* R: edge selection */ +#define S626_LP_RDCAPSEL(x) (0x004e + (x) * 0x10) /* R: capture enable */ + +/* Counter Registers (read/write): */ +#define S626_LP_CR0A 0x0000 /* 0A setup register. */ +#define S626_LP_CR0B 0x0002 /* 0B setup register. */ +#define S626_LP_CR1A 0x0004 /* 1A setup register. */ +#define S626_LP_CR1B 0x0006 /* 1B setup register. */ +#define S626_LP_CR2A 0x0008 /* 2A setup register. */ +#define S626_LP_CR2B 0x000A /* 2B setup register. */ + +/* Counter PreLoad (write) and Latch (read) Registers: */ +#define S626_LP_CNTR0ALSW 0x000C /* 0A lsw. */ +#define S626_LP_CNTR0AMSW 0x000E /* 0A msw. */ +#define S626_LP_CNTR0BLSW 0x0010 /* 0B lsw. */ +#define S626_LP_CNTR0BMSW 0x0012 /* 0B msw. */ +#define S626_LP_CNTR1ALSW 0x0014 /* 1A lsw. */ +#define S626_LP_CNTR1AMSW 0x0016 /* 1A msw. */ +#define S626_LP_CNTR1BLSW 0x0018 /* 1B lsw. */ +#define S626_LP_CNTR1BMSW 0x001A /* 1B msw. */ +#define S626_LP_CNTR2ALSW 0x001C /* 2A lsw. */ +#define S626_LP_CNTR2AMSW 0x001E /* 2A msw. */ +#define S626_LP_CNTR2BLSW 0x0020 /* 2B lsw. */ +#define S626_LP_CNTR2BMSW 0x0022 /* 2B msw. */ + +/* Miscellaneous Registers (read/write): */ +#define S626_LP_MISC1 0x0088 /* Read/write Misc1. */ +#define S626_LP_WRMISC2 0x0090 /* Write Misc2. */ +#define S626_LP_RDMISC2 0x0082 /* Read Misc2. */ + +/* Bit masks for MISC1 register that are the same for reads and writes. */ +#define S626_MISC1_WENABLE 0x8000 /* enab writes to MISC2 (except Clear * Watchdog bit). */ -#define MISC1_WDISABLE 0x0000 /* Disable writes to MISC2. */ -#define MISC1_EDCAP 0x1000 /* enab edge capture on DIO chans - * specified by LP_WRCAPSELx. */ -#define MISC1_NOEDCAP 0x0000 /* Disable edge capture on specified +#define S626_MISC1_WDISABLE 0x0000 /* Disable writes to MISC2. */ +#define S626_MISC1_EDCAP 0x1000 /* Enable edge capture on DIO chans + * specified by S626_LP_WRCAPSELx. */ +#define S626_MISC1_NOEDCAP 0x0000 /* Disable edge capture on specified * DIO chans. */ -/* Bit masks for MISC1 register reads. */ -#define RDMISC1_WDTIMEOUT 0x4000 /* Watchdog timer timed out. */ - -/* Bit masks for MISC2 register writes. */ -#define WRMISC2_WDCLEAR 0x8000 /* Reset watchdog timer to zero. */ -#define WRMISC2_CHARGE_ENABLE 0x4000 /* enab battery trickle charging. */ - -/* Bit masks for MISC2 register that are the same for reads and writes. */ -#define MISC2_BATT_ENABLE 0x0008 /* Backup battery enable. */ -#define MISC2_WDENABLE 0x0004 /* Watchdog timer enable. */ -#define MISC2_WDPERIOD_MASK 0x0003 /* Watchdog interval */ - /* select mask. */ - -/* Bit masks for ACON1 register. */ -#define A2_RUN 0x40000000 /* Run A2 based on TSL2. */ -#define A1_RUN 0x20000000 /* Run A1 based on TSL1. */ -#define A1_SWAP 0x00200000 /* Use big-endian for A1. */ -#define A2_SWAP 0x00100000 /* Use big-endian for A2. */ -#define WS_MODES 0x00019999 /* WS0 = TSL1 trigger */ - /* input, WS1-WS4 = */ - /* CS* outputs. */ - -#if PLATFORM == INTEL /* Base ACON1 config: always run A1 based - * on TSL1. */ -#define ACON1_BASE (WS_MODES | A1_RUN) -#elif PLATFORM == MOTOROLA -#define ACON1_BASE (WS_MODES | A1_RUN | A1_SWAP | A2_SWAP) +/* Bit masks for MISC1 register reads. */ +#define S626_RDMISC1_WDTIMEOUT 0x4000 /* Watchdog timer timed out. */ + +/* Bit masks for MISC2 register writes. */ +#define S626_WRMISC2_WDCLEAR 0x8000 /* Reset watchdog timer to zero. */ +#define S626_WRMISC2_CHARGE_ENABLE 0x4000 /* Enable battery trickle charging. */ + +/* Bit masks for MISC2 register that are the same for reads and writes. */ +#define S626_MISC2_BATT_ENABLE 0x0008 /* Backup battery enable. */ +#define S626_MISC2_WDENABLE 0x0004 /* Watchdog timer enable. */ +#define S626_MISC2_WDPERIOD_MASK 0x0003 /* Watchdog interval select mask. */ + +/* Bit masks for ACON1 register. */ +#define S626_A2_RUN 0x40000000 /* Run A2 based on TSL2. */ +#define S626_A1_RUN 0x20000000 /* Run A1 based on TSL1. */ +#define S626_A1_SWAP 0x00200000 /* Use big-endian for A1. */ +#define S626_A2_SWAP 0x00100000 /* Use big-endian for A2. */ +#define S626_WS_MODES 0x00019999 /* WS0 = TSL1 trigger input, + * WS1-WS4 = CS* outputs. */ + +#if S626_PLATFORM == S626_INTEL /* Base ACON1 config: always run + * A1 based on TSL1. */ +#define S626_ACON1_BASE (S626_WS_MODES | S626_A1_RUN) +#elif S626_PLATFORM == S626_MOTOROLA +#define S626_ACON1_BASE \ + (S626_WS_MODES | S626_A1_RUN | S626_A1_SWAP | S626_A2_SWAP) #endif -#define ACON1_ADCSTART ACON1_BASE /* Start ADC: run A1 - * based on TSL1. */ -#define ACON1_DACSTART (ACON1_BASE | A2_RUN) +#define S626_ACON1_ADCSTART S626_ACON1_BASE /* Start ADC: run A1 + * based on TSL1. */ +#define S626_ACON1_DACSTART (S626_ACON1_BASE | S626_A2_RUN) /* Start transmit to DAC: run A2 based on TSL2. */ -#define ACON1_DACSTOP ACON1_BASE /* Halt A2. */ - -/* Bit masks for ACON2 register. */ -#define A1_CLKSRC_BCLK1 0x00000000 /* A1 bit rate = BCLK1 (ADC). */ -#define A2_CLKSRC_X1 0x00800000 /* A2 bit rate = ACLK/1 (DACs). */ -#define A2_CLKSRC_X2 0x00C00000 /* A2 bit rate = ACLK/2 (DACs). */ -#define A2_CLKSRC_X4 0x01400000 /* A2 bit rate = ACLK/4 (DACs). */ -#define INVERT_BCLK2 0x00100000 /* Invert BCLK2 (DACs). */ -#define BCLK2_OE 0x00040000 /* enab BCLK2 (DACs). */ -#define ACON2_XORMASK 0x000C0000 /* XOR mask for ACON2 */ - /* active-low bits. */ - -#define ACON2_INIT (ACON2_XORMASK ^ (A1_CLKSRC_BCLK1 | A2_CLKSRC_X2 | INVERT_BCLK2 | BCLK2_OE)) - -/* Bit masks for timeslot records. */ -#define WS1 0x40000000 /* WS output to assert. */ -#define WS2 0x20000000 -#define WS3 0x10000000 -#define WS4 0x08000000 -#define RSD1 0x01000000 /* Shift A1 data in on SD1. */ -#define SDW_A1 0x00800000 /* Store rcv'd char at next - * char slot of DWORD1 buffer. */ -#define SIB_A1 0x00400000 /* Store rcv'd char at next +#define S626_ACON1_DACSTOP S626_ACON1_BASE /* Halt A2. */ + +/* Bit masks for ACON2 register. */ +#define S626_A1_CLKSRC_BCLK1 0x00000000 /* A1 bit rate = BCLK1 (ADC). */ +#define S626_A2_CLKSRC_X1 0x00800000 /* A2 bit rate = ACLK/1 + * (DACs). */ +#define S626_A2_CLKSRC_X2 0x00C00000 /* A2 bit rate = ACLK/2 + * (DACs). */ +#define S626_A2_CLKSRC_X4 0x01400000 /* A2 bit rate = ACLK/4 + * (DACs). */ +#define S626_INVERT_BCLK2 0x00100000 /* Invert BCLK2 (DACs). */ +#define S626_BCLK2_OE 0x00040000 /* Enable BCLK2 (DACs). */ +#define S626_ACON2_XORMASK 0x000C0000 /* XOR mask for ACON2 + * active-low bits. */ + +#define S626_ACON2_INIT (S626_ACON2_XORMASK ^ \ + (S626_A1_CLKSRC_BCLK1 | S626_A2_CLKSRC_X2 | \ + S626_INVERT_BCLK2 | S626_BCLK2_OE)) + +/* Bit masks for timeslot records. */ +#define S626_WS1 0x40000000 /* WS output to assert. */ +#define S626_WS2 0x20000000 +#define S626_WS3 0x10000000 +#define S626_WS4 0x08000000 +#define S626_RSD1 0x01000000 /* Shift A1 data in on SD1. */ +#define S626_SDW_A1 0x00800000 /* Store rcv'd char at next char + * slot of DWORD1 buffer. */ +#define S626_SIB_A1 0x00400000 /* Store rcv'd char at next * char slot of FB1 buffer. */ -#define SF_A1 0x00200000 /* Write unsigned long +#define S626_SF_A1 0x00200000 /* Write unsigned long * buffer to input FIFO. */ /* Select parallel-to-serial converter's data source: */ -#define XFIFO_0 0x00000000 /* Data fifo byte 0. */ -#define XFIFO_1 0x00000010 /* Data fifo byte 1. */ -#define XFIFO_2 0x00000020 /* Data fifo byte 2. */ -#define XFIFO_3 0x00000030 /* Data fifo byte 3. */ -#define XFB0 0x00000040 /* FB_BUFFER byte 0. */ -#define XFB1 0x00000050 /* FB_BUFFER byte 1. */ -#define XFB2 0x00000060 /* FB_BUFFER byte 2. */ -#define XFB3 0x00000070 /* FB_BUFFER byte 3. */ -#define SIB_A2 0x00000200 /* Store next dword from A2's - * input shifter to FB2 buffer. */ -#define SF_A2 0x00000100 /* Store next dword from A2's +#define S626_XFIFO_0 0x00000000 /* Data fifo byte 0. */ +#define S626_XFIFO_1 0x00000010 /* Data fifo byte 1. */ +#define S626_XFIFO_2 0x00000020 /* Data fifo byte 2. */ +#define S626_XFIFO_3 0x00000030 /* Data fifo byte 3. */ +#define S626_XFB0 0x00000040 /* FB_BUFFER byte 0. */ +#define S626_XFB1 0x00000050 /* FB_BUFFER byte 1. */ +#define S626_XFB2 0x00000060 /* FB_BUFFER byte 2. */ +#define S626_XFB3 0x00000070 /* FB_BUFFER byte 3. */ +#define S626_SIB_A2 0x00000200 /* Store next dword from A2's + * input shifter to FB2 + * buffer. */ +#define S626_SF_A2 0x00000100 /* Store next dword from A2's * input shifter to its input * fifo. */ -#define LF_A2 0x00000080 /* Load next dword from A2's +#define S626_LF_A2 0x00000080 /* Load next dword from A2's * output fifo into its * output dword buffer. */ -#define XSD2 0x00000008 /* Shift data out on SD2. */ -#define RSD3 0x00001800 /* Shift data in on SD3. */ -#define RSD2 0x00001000 /* Shift data in on SD2. */ -#define LOW_A2 0x00000002 /* Drive last SD low */ - /* for 7 clks, then */ - /* tri-state. */ -#define EOS 0x00000001 /* End of superframe. */ - -/* I2C configuration constants. */ -#define I2C_CLKSEL 0x0400 -/* I2C bit rate = PCIclk/480 = 68.75 KHz. */ - -#define I2C_BITRATE 68.75 -/* I2C bus data bit rate (determined by I2C_CLKSEL) in KHz. */ - -#define I2C_WRTIME 15.0 -/* Worst case time, in msec, for EEPROM internal write op. */ - -/* I2C manifest constants. */ - -/* Max retries to wait for EEPROM write. */ -#define I2C_RETRIES (I2C_WRTIME * I2C_BITRATE / 9.0) -#define I2C_ERR 0x0002 /* I2C control/status */ - /* flag ERROR. */ -#define I2C_BUSY 0x0001 /* I2C control/status */ - /* flag BUSY. */ -#define I2C_ABORT 0x0080 /* I2C status flag ABORT. */ -#define I2C_ATTRSTART 0x3 /* I2C attribute START. */ -#define I2C_ATTRCONT 0x2 /* I2C attribute CONT. */ -#define I2C_ATTRSTOP 0x1 /* I2C attribute STOP. */ -#define I2C_ATTRNOP 0x0 /* I2C attribute NOP. */ - -/* I2C read command | EEPROM address. */ -#define I2CR (devpriv->I2CAdrs | 1) - -/* I2C write command | EEPROM address. */ -#define I2CW (devpriv->I2CAdrs) - -/* Code macros used for constructing I2C command bytes. */ -#define I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) -#define I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) -#define I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) - -/* oldest */ -#define P_DEBICFGq 0x007C /* DEBI configuration. */ -#define P_DEBICMDq 0x0080 /* DEBI command. */ -#define P_DEBIPAGEq 0x0084 /* DEBI page. */ -#define P_DEBIADq 0x0088 /* DEBI target address. */ - -#define DEBI_CFG_TOQ 0x03C00000 /* timeout (15 PCI cycles) */ -#define DEBI_CFG_FASTQ 0x10000000 /* fast mode enable */ -#define DEBI_CFG_16Q 0x00080000 /* 16-bit access enable */ -#define DEBI_CFG_INCQ 0x00040000 /* enable address increment */ -#define DEBI_CFG_TIMEROFFQ 0x00010000 /* disable timer */ -#define DEBI_CMD_RDQ 0x00050000 /* read immediate 2 bytes */ -#define DEBI_CMD_WRQ 0x00040000 /* write immediate 2 bytes */ -#define DEBI_PAGE_DISABLEQ 0x00000000 /* paging disable */ - -/* DEBI command constants. */ -#define DEBI_CMD_SIZE16 (2 << 17) /* Transfer size is */ - /* always 2 bytes. */ -#define DEBI_CMD_READ 0x00010000 /* Read operation. */ -#define DEBI_CMD_WRITE 0x00000000 /* Write operation. */ - -/* Read immediate 2 bytes. */ -#define DEBI_CMD_RDWORD (DEBI_CMD_READ | DEBI_CMD_SIZE16) - -/* Write immediate 2 bytes. */ -#define DEBI_CMD_WRWORD (DEBI_CMD_WRITE | DEBI_CMD_SIZE16) - -/* DEBI configuration constants. */ -#define DEBI_CFG_XIRQ_EN 0x80000000 /* enab external */ - /* interrupt on GPIO3. */ -#define DEBI_CFG_XRESUME 0x40000000 /* Resume block */ - /* transfer when XIRQ */ - /* deasserted. */ -#define DEBI_CFG_FAST 0x10000000 /* Fast mode enable. */ - -/* 4-bit field that specifies DEBI timeout value in PCI clock cycles: */ -#define DEBI_CFG_TOUT_BIT 22 /* Finish DEBI cycle after */ - /* this many clocks. */ - -/* 2-bit field that specifies Endian byte lane steering: */ -#define DEBI_CFG_SWAP_NONE 0x00000000 /* Straight - don't */ - /* swap any bytes */ - /* (Intel). */ -#define DEBI_CFG_SWAP_2 0x00100000 /* 2-byte swap (Motorola). */ -#define DEBI_CFG_SWAP_4 0x00200000 /* 4-byte swap. */ -#define DEBI_CFG_16 0x00080000 /* Slave is able to */ - /* serve 16-bit */ - /* cycles. */ - -#define DEBI_CFG_SLAVE16 0x00080000 /* Slave is able to */ - /* serve 16-bit */ - /* cycles. */ -#define DEBI_CFG_INC 0x00040000 /* enab address */ - /* increment for block */ - /* transfers. */ -#define DEBI_CFG_INTEL 0x00020000 /* Intel style local bus. */ -#define DEBI_CFG_TIMEROFF 0x00010000 /* Disable timer. */ - -#if PLATFORM == INTEL - -#define DEBI_TOUT 7 /* Wait 7 PCI clocks */ - /* (212 ns) before */ - /* polling RDY. */ - -/* Intel byte lane steering (pass through all byte lanes). */ -#define DEBI_SWAP DEBI_CFG_SWAP_NONE - -#elif PLATFORM == MOTOROLA - -#define DEBI_TOUT 15 /* Wait 15 PCI clocks (454 ns) */ - /* maximum before timing out. */ -#define DEBI_SWAP DEBI_CFG_SWAP_2 /* Motorola byte lane steering. */ +#define S626_XSD2 0x00000008 /* Shift data out on SD2. */ +#define S626_RSD3 0x00001800 /* Shift data in on SD3. */ +#define S626_RSD2 0x00001000 /* Shift data in on SD2. */ +#define S626_LOW_A2 0x00000002 /* Drive last SD low for 7 clks, + * then tri-state. */ +#define S626_EOS 0x00000001 /* End of superframe. */ + +/* I2C configuration constants. */ +#define S626_I2C_CLKSEL 0x0400 /* I2C bit rate = + * PCIclk/480 = 68.75 KHz. */ +#define S626_I2C_BITRATE 68.75 /* I2C bus data bit rate + * (determined by + * S626_I2C_CLKSEL) in KHz. */ +#define S626_I2C_WRTIME 15.0 /* Worst case time, in msec, + * for EEPROM internal write + * op. */ + +/* I2C manifest constants. */ + +/* Max retries to wait for EEPROM write. */ +#define S626_I2C_RETRIES (S626_I2C_WRTIME * S626_I2C_BITRATE / 9.0) +#define S626_I2C_ERR 0x0002 /* I2C control/status flag ERROR. */ +#define S626_I2C_BUSY 0x0001 /* I2C control/status flag BUSY. */ +#define S626_I2C_ABORT 0x0080 /* I2C status flag ABORT. */ +#define S626_I2C_ATTRSTART 0x3 /* I2C attribute START. */ +#define S626_I2C_ATTRCONT 0x2 /* I2C attribute CONT. */ +#define S626_I2C_ATTRSTOP 0x1 /* I2C attribute STOP. */ +#define S626_I2C_ATTRNOP 0x0 /* I2C attribute NOP. */ + +/* Code macros used for constructing I2C command bytes. */ +#define S626_I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) +#define S626_I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) +#define S626_I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) + +/* DEBI command constants. */ +#define S626_DEBI_CMD_SIZE16 (2 << 17) /* Transfer size is always + * 2 bytes. */ +#define S626_DEBI_CMD_READ 0x00010000 /* Read operation. */ +#define S626_DEBI_CMD_WRITE 0x00000000 /* Write operation. */ + +/* Read immediate 2 bytes. */ +#define S626_DEBI_CMD_RDWORD (S626_DEBI_CMD_READ | S626_DEBI_CMD_SIZE16) + +/* Write immediate 2 bytes. */ +#define S626_DEBI_CMD_WRWORD (S626_DEBI_CMD_WRITE | S626_DEBI_CMD_SIZE16) + +/* DEBI configuration constants. */ +#define S626_DEBI_CFG_XIRQ_EN 0x80000000 /* Enable external interrupt + * on GPIO3. */ +#define S626_DEBI_CFG_XRESUME 0x40000000 /* Resume block */ + /* Transfer when XIRQ + * deasserted. */ +#define S626_DEBI_CFG_TOQ 0x03C00000 /* Timeout (15 PCI cycles). */ +#define S626_DEBI_CFG_FAST 0x10000000 /* Fast mode enable. */ + +/* 4-bit field that specifies DEBI timeout value in PCI clock cycles: */ +#define S626_DEBI_CFG_TOUT_BIT 22 /* Finish DEBI cycle after this many + * clocks. */ + +/* 2-bit field that specifies Endian byte lane steering: */ +#define S626_DEBI_CFG_SWAP_NONE 0x00000000 /* Straight - don't swap any + * bytes (Intel). */ +#define S626_DEBI_CFG_SWAP_2 0x00100000 /* 2-byte swap (Motorola). */ +#define S626_DEBI_CFG_SWAP_4 0x00200000 /* 4-byte swap. */ +#define S626_DEBI_CFG_SLAVE16 0x00080000 /* Slave is able to serve + * 16-bit cycles. */ +#define S626_DEBI_CFG_INC 0x00040000 /* Enable address increment + * for block transfers. */ +#define S626_DEBI_CFG_INTEL 0x00020000 /* Intel style local bus. */ +#define S626_DEBI_CFG_TIMEROFF 0x00010000 /* Disable timer. */ + +#if S626_PLATFORM == S626_INTEL + +#define S626_DEBI_TOUT 7 /* Wait 7 PCI clocks (212 ns) before + * polling RDY. */ + +/* Intel byte lane steering (pass through all byte lanes). */ +#define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_NONE + +#elif S626_PLATFORM == S626_MOTOROLA + +#define S626_DEBI_TOUT 15 /* Wait 15 PCI clocks (454 ns) maximum + * before timing out. */ + +/* Motorola byte lane steering. */ +#define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_2 #endif -/* DEBI page table constants. */ -#define DEBI_PAGE_DISABLE 0x00000000 /* Paging disable. */ - -/* ******* EXTRA FROM OTHER SANSORAY * .h ******* */ - -/* LoadSrc values: */ -#define LOADSRC_INDX 0 /* Preload core in response to */ - /* Index. */ -#define LOADSRC_OVER 1 /* Preload core in response to */ - /* Overflow. */ -#define LOADSRCB_OVERA 2 /* Preload B core in response */ - /* to A Overflow. */ -#define LOADSRC_NONE 3 /* Never preload core. */ - -/* IntSrc values: */ -#define INTSRC_NONE 0 /* Interrupts disabled. */ -#define INTSRC_OVER 1 /* Interrupt on Overflow. */ -#define INTSRC_INDX 2 /* Interrupt on Index. */ -#define INTSRC_BOTH 3 /* Interrupt on Index or Overflow. */ - -/* LatchSrc values: */ -#define LATCHSRC_AB_READ 0 /* Latch on read. */ -#define LATCHSRC_A_INDXA 1 /* Latch A on A Index. */ -#define LATCHSRC_B_INDXB 2 /* Latch B on B Index. */ -#define LATCHSRC_B_OVERA 3 /* Latch B on A Overflow. */ - -/* IndxSrc values: */ -#define INDXSRC_HARD 0 /* Hardware or software index. */ -#define INDXSRC_SOFT 1 /* Software index only. */ - -/* IndxPol values: */ -#define INDXPOL_POS 0 /* Index input is active high. */ -#define INDXPOL_NEG 1 /* Index input is active low. */ - -/* ClkSrc values: */ -#define CLKSRC_COUNTER 0 /* Counter mode. */ -#define CLKSRC_TIMER 2 /* Timer mode. */ -#define CLKSRC_EXTENDER 3 /* Extender mode. */ - -/* ClkPol values: */ -#define CLKPOL_POS 0 /* Counter/Extender clock is */ - /* active high. */ -#define CLKPOL_NEG 1 /* Counter/Extender clock is */ - /* active low. */ -#define CNTDIR_UP 0 /* Timer counts up. */ -#define CNTDIR_DOWN 1 /* Timer counts down. */ - -/* ClkEnab values: */ -#define CLKENAB_ALWAYS 0 /* Clock always enabled. */ -#define CLKENAB_INDEX 1 /* Clock is enabled by index. */ - -/* ClkMult values: */ -#define CLKMULT_4X 0 /* 4x clock multiplier. */ -#define CLKMULT_2X 1 /* 2x clock multiplier. */ -#define CLKMULT_1X 2 /* 1x clock multiplier. */ - -/* Bit Field positions in COUNTER_SETUP structure: */ -#define BF_LOADSRC 9 /* Preload trigger. */ -#define BF_INDXSRC 7 /* Index source. */ -#define BF_INDXPOL 6 /* Index polarity. */ -#define BF_CLKSRC 4 /* Clock source. */ -#define BF_CLKPOL 3 /* Clock polarity/count direction. */ -#define BF_CLKMULT 1 /* Clock multiplier. */ -#define BF_CLKENAB 0 /* Clock enable. */ - -/* Enumerated counter operating modes specified by ClkSrc bit field in */ -/* a COUNTER_SETUP. */ - -#define CLKSRC_COUNTER 0 /* Counter: ENC_C clock, ENC_D */ - /* direction. */ -#define CLKSRC_TIMER 2 /* Timer: SYS_C clock, */ - /* direction specified by */ - /* ClkPol. */ -#define CLKSRC_EXTENDER 3 /* Extender: OVR_A clock, */ - /* ENC_D direction. */ - -/* Enumerated counter clock multipliers. */ - -#define MULT_X0 0x0003 /* Supports no multipliers; */ - /* fixed physical multiplier = */ - /* 3. */ -#define MULT_X1 0x0002 /* Supports multiplier x1; */ - /* fixed physical multiplier = */ - /* 2. */ -#define MULT_X2 0x0001 /* Supports multipliers x1, */ - /* x2; physical multipliers = */ - /* 1 or 2. */ -#define MULT_X4 0x0000 /* Supports multipliers x1, */ - /* x2, x4; physical */ - /* multipliers = 0, 1 or 2. */ - -/* Sanity-check limits for parameters. */ - -#define NUM_COUNTERS 6 /* Maximum valid counter */ - /* logical channel number. */ -#define NUM_INTSOURCES 4 -#define NUM_LATCHSOURCES 4 -#define NUM_CLKMULTS 4 -#define NUM_CLKSOURCES 4 -#define NUM_CLKPOLS 2 -#define NUM_INDEXPOLS 2 -#define NUM_INDEXSOURCES 2 -#define NUM_LOADTRIGS 4 - -/* Bit field positions in CRA and CRB counter control registers. */ - -/* Bit field positions in CRA: */ -#define CRABIT_INDXSRC_B 14 /* B index source. */ -#define CRABIT_CLKSRC_B 12 /* B clock source. */ -#define CRABIT_INDXPOL_A 11 /* A index polarity. */ -#define CRABIT_LOADSRC_A 9 /* A preload trigger. */ -#define CRABIT_CLKMULT_A 7 /* A clock multiplier. */ -#define CRABIT_INTSRC_A 5 /* A interrupt source. */ -#define CRABIT_CLKPOL_A 4 /* A clock polarity. */ -#define CRABIT_INDXSRC_A 2 /* A index source. */ -#define CRABIT_CLKSRC_A 0 /* A clock source. */ - -/* Bit field positions in CRB: */ -#define CRBBIT_INTRESETCMD 15 /* Interrupt reset command. */ -#define CRBBIT_INTRESET_B 14 /* B interrupt reset enable. */ -#define CRBBIT_INTRESET_A 13 /* A interrupt reset enable. */ -#define CRBBIT_CLKENAB_A 12 /* A clock enable. */ -#define CRBBIT_INTSRC_B 10 /* B interrupt source. */ -#define CRBBIT_LATCHSRC 8 /* A/B latch source. */ -#define CRBBIT_LOADSRC_B 6 /* B preload trigger. */ -#define CRBBIT_CLKMULT_B 3 /* B clock multiplier. */ -#define CRBBIT_CLKENAB_B 2 /* B clock enable. */ -#define CRBBIT_INDXPOL_B 1 /* B index polarity. */ -#define CRBBIT_CLKPOL_B 0 /* B clock polarity. */ - -/* Bit field masks for CRA and CRB. */ - -#define CRAMSK_INDXSRC_B (3 << CRABIT_INDXSRC_B) -#define CRAMSK_CLKSRC_B (3 << CRABIT_CLKSRC_B) -#define CRAMSK_INDXPOL_A (1 << CRABIT_INDXPOL_A) -#define CRAMSK_LOADSRC_A (3 << CRABIT_LOADSRC_A) -#define CRAMSK_CLKMULT_A (3 << CRABIT_CLKMULT_A) -#define CRAMSK_INTSRC_A (3 << CRABIT_INTSRC_A) -#define CRAMSK_CLKPOL_A (3 << CRABIT_CLKPOL_A) -#define CRAMSK_INDXSRC_A (3 << CRABIT_INDXSRC_A) -#define CRAMSK_CLKSRC_A (3 << CRABIT_CLKSRC_A) - -#define CRBMSK_INTRESETCMD (1 << CRBBIT_INTRESETCMD) -#define CRBMSK_INTRESET_B (1 << CRBBIT_INTRESET_B) -#define CRBMSK_INTRESET_A (1 << CRBBIT_INTRESET_A) -#define CRBMSK_CLKENAB_A (1 << CRBBIT_CLKENAB_A) -#define CRBMSK_INTSRC_B (3 << CRBBIT_INTSRC_B) -#define CRBMSK_LATCHSRC (3 << CRBBIT_LATCHSRC) -#define CRBMSK_LOADSRC_B (3 << CRBBIT_LOADSRC_B) -#define CRBMSK_CLKMULT_B (3 << CRBBIT_CLKMULT_B) -#define CRBMSK_CLKENAB_B (1 << CRBBIT_CLKENAB_B) -#define CRBMSK_INDXPOL_B (1 << CRBBIT_INDXPOL_B) -#define CRBMSK_CLKPOL_B (1 << CRBBIT_CLKPOL_B) - -#define CRBMSK_INTCTRL (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A | CRBMSK_INTRESET_B) /* Interrupt reset control bits. */ - -/* Bit field positions for standardized SETUP structure. */ - -#define STDBIT_INTSRC 13 -#define STDBIT_LATCHSRC 11 -#define STDBIT_LOADSRC 9 -#define STDBIT_INDXSRC 7 -#define STDBIT_INDXPOL 6 -#define STDBIT_CLKSRC 4 -#define STDBIT_CLKPOL 3 -#define STDBIT_CLKMULT 1 -#define STDBIT_CLKENAB 0 - -/* Bit field masks for standardized SETUP structure. */ - -#define STDMSK_INTSRC (3 << STDBIT_INTSRC) -#define STDMSK_LATCHSRC (3 << STDBIT_LATCHSRC) -#define STDMSK_LOADSRC (3 << STDBIT_LOADSRC) -#define STDMSK_INDXSRC (1 << STDBIT_INDXSRC) -#define STDMSK_INDXPOL (1 << STDBIT_INDXPOL) -#define STDMSK_CLKSRC (3 << STDBIT_CLKSRC) -#define STDMSK_CLKPOL (1 << STDBIT_CLKPOL) -#define STDMSK_CLKMULT (3 << STDBIT_CLKMULT) -#define STDMSK_CLKENAB (1 << STDBIT_CLKENAB) - -struct bufferDMA { - dma_addr_t PhysicalBase; - void *LogicalBase; - uint32_t DMAHandle; -}; +/* DEBI page table constants. */ +#define S626_DEBI_PAGE_DISABLE 0x00000000 /* Paging disable. */ + +/* ******* EXTRA FROM OTHER SENSORAY * .h ******* */ + +/* LoadSrc values: */ +#define S626_LOADSRC_INDX 0 /* Preload core in response to Index. */ +#define S626_LOADSRC_OVER 1 /* Preload core in response to + * Overflow. */ +#define S626_LOADSRCB_OVERA 2 /* Preload B core in response to + * A Overflow. */ +#define S626_LOADSRC_NONE 3 /* Never preload core. */ + +/* IntSrc values: */ +#define S626_INTSRC_NONE 0 /* Interrupts disabled. */ +#define S626_INTSRC_OVER 1 /* Interrupt on Overflow. */ +#define S626_INTSRC_INDX 2 /* Interrupt on Index. */ +#define S626_INTSRC_BOTH 3 /* Interrupt on Index or Overflow. */ + +/* LatchSrc values: */ +#define S626_LATCHSRC_AB_READ 0 /* Latch on read. */ +#define S626_LATCHSRC_A_INDXA 1 /* Latch A on A Index. */ +#define S626_LATCHSRC_B_INDXB 2 /* Latch B on B Index. */ +#define S626_LATCHSRC_B_OVERA 3 /* Latch B on A Overflow. */ + +/* IndxSrc values: */ +#define S626_INDXSRC_ENCODER 0 /* Encoder. */ +#define S626_INDXSRC_DIGIN 1 /* Digital inputs. */ +#define S626_INDXSRC_SOFT 2 /* S/w controlled by IndxPol bit. */ +#define S626_INDXSRC_DISABLED 3 /* Index disabled. */ + +/* IndxPol values: */ +#define S626_INDXPOL_POS 0 /* Index input is active high. */ +#define S626_INDXPOL_NEG 1 /* Index input is active low. */ + +/* Logical encoder mode values: */ +#define S626_ENCMODE_COUNTER 0 /* Counter mode. */ +#define S626_ENCMODE_TIMER 2 /* Timer mode. */ +#define S626_ENCMODE_EXTENDER 3 /* Extender mode. */ + +/* Physical CntSrc values (for Counter A source and Counter B source): */ +#define S626_CNTSRC_ENCODER 0 /* Encoder */ +#define S626_CNTSRC_DIGIN 1 /* Digital inputs */ +#define S626_CNTSRC_SYSCLK 2 /* System clock up */ +#define S626_CNTSRC_SYSCLK_DOWN 3 /* System clock down */ + +/* ClkPol values: */ +#define S626_CLKPOL_POS 0 /* Counter/Extender clock is + * active high. */ +#define S626_CLKPOL_NEG 1 /* Counter/Extender clock is + * active low. */ +#define S626_CNTDIR_UP 0 /* Timer counts up. */ +#define S626_CNTDIR_DOWN 1 /* Timer counts down. */ + +/* ClkEnab values: */ +#define S626_CLKENAB_ALWAYS 0 /* Clock always enabled. */ +#define S626_CLKENAB_INDEX 1 /* Clock is enabled by index. */ + +/* ClkMult values: */ +#define S626_CLKMULT_4X 0 /* 4x clock multiplier. */ +#define S626_CLKMULT_2X 1 /* 2x clock multiplier. */ +#define S626_CLKMULT_1X 2 /* 1x clock multiplier. */ +#define S626_CLKMULT_SPECIAL 3 /* Special clock multiplier value. */ + +/* Sanity-check limits for parameters. */ + +#define S626_NUM_COUNTERS 6 /* Maximum valid counter + * logical channel number. */ +#define S626_NUM_INTSOURCES 4 +#define S626_NUM_LATCHSOURCES 4 +#define S626_NUM_CLKMULTS 4 +#define S626_NUM_CLKSOURCES 4 +#define S626_NUM_CLKPOLS 2 +#define S626_NUM_INDEXPOLS 2 +#define S626_NUM_INDEXSOURCES 2 +#define S626_NUM_LOADTRIGS 4 + +/* General macros for manipulating bitfields: */ +#define S626_MAKE(x, w, p) (((x) & ((1 << (w)) - 1)) << (p)) +#define S626_UNMAKE(v, w, p) (((v) >> (p)) & ((1 << (w)) - 1)) + +/* Bit field positions in CRA: */ +#define S626_CRABIT_INDXSRC_B 14 /* B index source. */ +#define S626_CRABIT_CNTSRC_B 12 /* B counter source. */ +#define S626_CRABIT_INDXPOL_A 11 /* A index polarity. */ +#define S626_CRABIT_LOADSRC_A 9 /* A preload trigger. */ +#define S626_CRABIT_CLKMULT_A 7 /* A clock multiplier. */ +#define S626_CRABIT_INTSRC_A 5 /* A interrupt source. */ +#define S626_CRABIT_CLKPOL_A 4 /* A clock polarity. */ +#define S626_CRABIT_INDXSRC_A 2 /* A index source. */ +#define S626_CRABIT_CNTSRC_A 0 /* A counter source. */ + +/* Bit field widths in CRA: */ +#define S626_CRAWID_INDXSRC_B 2 +#define S626_CRAWID_CNTSRC_B 2 +#define S626_CRAWID_INDXPOL_A 1 +#define S626_CRAWID_LOADSRC_A 2 +#define S626_CRAWID_CLKMULT_A 2 +#define S626_CRAWID_INTSRC_A 2 +#define S626_CRAWID_CLKPOL_A 1 +#define S626_CRAWID_INDXSRC_A 2 +#define S626_CRAWID_CNTSRC_A 2 + +/* Bit field masks for CRA: */ +#define S626_CRAMSK_INDXSRC_B S626_SET_CRA_INDXSRC_B(~0) +#define S626_CRAMSK_CNTSRC_B S626_SET_CRA_CNTSRC_B(~0) +#define S626_CRAMSK_INDXPOL_A S626_SET_CRA_INDXPOL_A(~0) +#define S626_CRAMSK_LOADSRC_A S626_SET_CRA_LOADSRC_A(~0) +#define S626_CRAMSK_CLKMULT_A S626_SET_CRA_CLKMULT_A(~0) +#define S626_CRAMSK_INTSRC_A S626_SET_CRA_INTSRC_A(~0) +#define S626_CRAMSK_CLKPOL_A S626_SET_CRA_CLKPOL_A(~0) +#define S626_CRAMSK_INDXSRC_A S626_SET_CRA_INDXSRC_A(~0) +#define S626_CRAMSK_CNTSRC_A S626_SET_CRA_CNTSRC_A(~0) + +/* Construct parts of the CRA value: */ +#define S626_SET_CRA_INDXSRC_B(x) \ + S626_MAKE((x), S626_CRAWID_INDXSRC_B, S626_CRABIT_INDXSRC_B) +#define S626_SET_CRA_CNTSRC_B(x) \ + S626_MAKE((x), S626_CRAWID_CNTSRC_B, S626_CRABIT_CNTSRC_B) +#define S626_SET_CRA_INDXPOL_A(x) \ + S626_MAKE((x), S626_CRAWID_INDXPOL_A, S626_CRABIT_INDXPOL_A) +#define S626_SET_CRA_LOADSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_LOADSRC_A, S626_CRABIT_LOADSRC_A) +#define S626_SET_CRA_CLKMULT_A(x) \ + S626_MAKE((x), S626_CRAWID_CLKMULT_A, S626_CRABIT_CLKMULT_A) +#define S626_SET_CRA_INTSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_INTSRC_A, S626_CRABIT_INTSRC_A) +#define S626_SET_CRA_CLKPOL_A(x) \ + S626_MAKE((x), S626_CRAWID_CLKPOL_A, S626_CRABIT_CLKPOL_A) +#define S626_SET_CRA_INDXSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_INDXSRC_A, S626_CRABIT_INDXSRC_A) +#define S626_SET_CRA_CNTSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_CNTSRC_A, S626_CRABIT_CNTSRC_A) + +/* Extract parts of the CRA value: */ +#define S626_GET_CRA_INDXSRC_B(v) \ + S626_UNMAKE((v), S626_CRAWID_INDXSRC_B, S626_CRABIT_INDXSRC_B) +#define S626_GET_CRA_CNTSRC_B(v) \ + S626_UNMAKE((v), S626_CRAWID_CNTSRC_B, S626_CRABIT_CNTSRC_B) +#define S626_GET_CRA_INDXPOL_A(v) \ + S626_UNMAKE((v), S626_CRAWID_INDXPOL_A, S626_CRABIT_INDXPOL_A) +#define S626_GET_CRA_LOADSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_LOADSRC_A, S626_CRABIT_LOADSRC_A) +#define S626_GET_CRA_CLKMULT_A(v) \ + S626_UNMAKE((v), S626_CRAWID_CLKMULT_A, S626_CRABIT_CLKMULT_A) +#define S626_GET_CRA_INTSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_INTSRC_A, S626_CRABIT_INTSRC_A) +#define S626_GET_CRA_CLKPOL_A(v) \ + S626_UNMAKE((v), S626_CRAWID_CLKPOL_A, S626_CRABIT_CLKPOL_A) +#define S626_GET_CRA_INDXSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_INDXSRC_A, S626_CRABIT_INDXSRC_A) +#define S626_GET_CRA_CNTSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_CNTSRC_A, S626_CRABIT_CNTSRC_A) + +/* Bit field positions in CRB: */ +#define S626_CRBBIT_INTRESETCMD 15 /* (w) Interrupt reset command. */ +#define S626_CRBBIT_CNTDIR_B 15 /* (r) B counter direction. */ +#define S626_CRBBIT_INTRESET_B 14 /* (w) B interrupt reset enable. */ +#define S626_CRBBIT_OVERDO_A 14 /* (r) A overflow routed to dig. out. */ +#define S626_CRBBIT_INTRESET_A 13 /* (w) A interrupt reset enable. */ +#define S626_CRBBIT_OVERDO_B 13 /* (r) B overflow routed to dig. out. */ +#define S626_CRBBIT_CLKENAB_A 12 /* A clock enable. */ +#define S626_CRBBIT_INTSRC_B 10 /* B interrupt source. */ +#define S626_CRBBIT_LATCHSRC 8 /* A/B latch source. */ +#define S626_CRBBIT_LOADSRC_B 6 /* B preload trigger. */ +#define S626_CRBBIT_CLEAR_B 7 /* B cleared when A overflows. */ +#define S626_CRBBIT_CLKMULT_B 3 /* B clock multiplier. */ +#define S626_CRBBIT_CLKENAB_B 2 /* B clock enable. */ +#define S626_CRBBIT_INDXPOL_B 1 /* B index polarity. */ +#define S626_CRBBIT_CLKPOL_B 0 /* B clock polarity. */ + +/* Bit field widths in CRB: */ +#define S626_CRBWID_INTRESETCMD 1 +#define S626_CRBWID_CNTDIR_B 1 +#define S626_CRBWID_INTRESET_B 1 +#define S626_CRBWID_OVERDO_A 1 +#define S626_CRBWID_INTRESET_A 1 +#define S626_CRBWID_OVERDO_B 1 +#define S626_CRBWID_CLKENAB_A 1 +#define S626_CRBWID_INTSRC_B 2 +#define S626_CRBWID_LATCHSRC 2 +#define S626_CRBWID_LOADSRC_B 2 +#define S626_CRBWID_CLEAR_B 1 +#define S626_CRBWID_CLKMULT_B 2 +#define S626_CRBWID_CLKENAB_B 1 +#define S626_CRBWID_INDXPOL_B 1 +#define S626_CRBWID_CLKPOL_B 1 + +/* Bit field masks for CRB: */ +#define S626_CRBMSK_INTRESETCMD S626_SET_CRB_INTRESETCMD(~0) /* (w) */ +#define S626_CRBMSK_CNTDIR_B S626_CRBMSK_INTRESETCMD /* (r) */ +#define S626_CRBMSK_INTRESET_B S626_SET_CRB_INTRESET_B(~0) /* (w) */ +#define S626_CRBMSK_OVERDO_A S626_CRBMSK_INTRESET_B /* (r) */ +#define S626_CRBMSK_INTRESET_A S626_SET_CRB_INTRESET_A(~0) /* (w) */ +#define S626_CRBMSK_OVERDO_B S626_CRBMSK_INTRESET_A /* (r) */ +#define S626_CRBMSK_CLKENAB_A S626_SET_CRB_CLKENAB_A(~0) +#define S626_CRBMSK_INTSRC_B S626_SET_CRB_INTSRC_B(~0) +#define S626_CRBMSK_LATCHSRC S626_SET_CRB_LATCHSRC(~0) +#define S626_CRBMSK_LOADSRC_B S626_SET_CRB_LOADSRC_B(~0) +#define S626_CRBMSK_CLEAR_B S626_SET_CRB_CLEAR_B(~0) +#define S626_CRBMSK_CLKMULT_B S626_SET_CRB_CLKMULT_B(~0) +#define S626_CRBMSK_CLKENAB_B S626_SET_CRB_CLKENAB_B(~0) +#define S626_CRBMSK_INDXPOL_B S626_SET_CRB_INDXPOL_B(~0) +#define S626_CRBMSK_CLKPOL_B S626_SET_CRB_CLKPOL_B(~0) + +/* Interrupt reset control bits. */ +#define S626_CRBMSK_INTCTRL (S626_CRBMSK_INTRESETCMD | \ + S626_CRBMSK_INTRESET_A | \ + S626_CRBMSK_INTRESET_B) + +/* Construct parts of the CRB value: */ +#define S626_SET_CRB_INTRESETCMD(x) \ + S626_MAKE((x), S626_CRBWID_INTRESETCMD, S626_CRBBIT_INTRESETCMD) +#define S626_SET_CRB_INTRESET_B(x) \ + S626_MAKE((x), S626_CRBWID_INTRESET_B, S626_CRBBIT_INTRESET_B) +#define S626_SET_CRB_INTRESET_A(x) \ + S626_MAKE((x), S626_CRBWID_INTRESET_A, S626_CRBBIT_INTRESET_A) +#define S626_SET_CRB_CLKENAB_A(x) \ + S626_MAKE((x), S626_CRBWID_CLKENAB_A, S626_CRBBIT_CLKENAB_A) +#define S626_SET_CRB_INTSRC_B(x) \ + S626_MAKE((x), S626_CRBWID_INTSRC_B, S626_CRBBIT_INTSRC_B) +#define S626_SET_CRB_LATCHSRC(x) \ + S626_MAKE((x), S626_CRBWID_LATCHSRC, S626_CRBBIT_LATCHSRC) +#define S626_SET_CRB_LOADSRC_B(x) \ + S626_MAKE((x), S626_CRBWID_LOADSRC_B, S626_CRBBIT_LOADSRC_B) +#define S626_SET_CRB_CLEAR_B(x) \ + S626_MAKE((x), S626_CRBWID_CLEAR_B, S626_CRBBIT_CLEAR_B) +#define S626_SET_CRB_CLKMULT_B(x) \ + S626_MAKE((x), S626_CRBWID_CLKMULT_B, S626_CRBBIT_CLKMULT_B) +#define S626_SET_CRB_CLKENAB_B(x) \ + S626_MAKE((x), S626_CRBWID_CLKENAB_B, S626_CRBBIT_CLKENAB_B) +#define S626_SET_CRB_INDXPOL_B(x) \ + S626_MAKE((x), S626_CRBWID_INDXPOL_B, S626_CRBBIT_INDXPOL_B) +#define S626_SET_CRB_CLKPOL_B(x) \ + S626_MAKE((x), S626_CRBWID_CLKPOL_B, S626_CRBBIT_CLKPOL_B) + +/* Extract parts of the CRB value: */ +#define S626_GET_CRB_CNTDIR_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CNTDIR_B, S626_CRBBIT_CNTDIR_B) +#define S626_GET_CRB_OVERDO_A(v) \ + S626_UNMAKE((v), S626_CRBWID_OVERDO_A, S626_CRBBIT_OVERDO_A) +#define S626_GET_CRB_OVERDO_B(v) \ + S626_UNMAKE((v), S626_CRBWID_OVERDO_B, S626_CRBBIT_OVERDO_B) +#define S626_GET_CRB_CLKENAB_A(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKENAB_A, S626_CRBBIT_CLKENAB_A) +#define S626_GET_CRB_INTSRC_B(v) \ + S626_UNMAKE((v), S626_CRBWID_INTSRC_B, S626_CRBBIT_INTSRC_B) +#define S626_GET_CRB_LATCHSRC(v) \ + S626_UNMAKE((v), S626_CRBWID_LATCHSRC, S626_CRBBIT_LATCHSRC) +#define S626_GET_CRB_LOADSRC_B(v) \ + S626_UNMAKE((v), S626_CRBWID_LOADSRC_B, S626_CRBBIT_LOADSRC_B) +#define S626_GET_CRB_CLEAR_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLEAR_B, S626_CRBBIT_CLEAR_B) +#define S626_GET_CRB_CLKMULT_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKMULT_B, S626_CRBBIT_CLKMULT_B) +#define S626_GET_CRB_CLKENAB_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKENAB_B, S626_CRBBIT_CLKENAB_B) +#define S626_GET_CRB_INDXPOL_B(v) \ + S626_UNMAKE((v), S626_CRBWID_INDXPOL_B, S626_CRBBIT_INDXPOL_B) +#define S626_GET_CRB_CLKPOL_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKPOL_B, S626_CRBBIT_CLKPOL_B) + +/* Bit field positions for standardized SETUP structure: */ +#define S626_STDBIT_INTSRC 13 +#define S626_STDBIT_LATCHSRC 11 +#define S626_STDBIT_LOADSRC 9 +#define S626_STDBIT_INDXSRC 7 +#define S626_STDBIT_INDXPOL 6 +#define S626_STDBIT_ENCMODE 4 +#define S626_STDBIT_CLKPOL 3 +#define S626_STDBIT_CLKMULT 1 +#define S626_STDBIT_CLKENAB 0 + +/* Bit field widths for standardized SETUP structure: */ +#define S626_STDWID_INTSRC 2 +#define S626_STDWID_LATCHSRC 2 +#define S626_STDWID_LOADSRC 2 +#define S626_STDWID_INDXSRC 2 +#define S626_STDWID_INDXPOL 1 +#define S626_STDWID_ENCMODE 2 +#define S626_STDWID_CLKPOL 1 +#define S626_STDWID_CLKMULT 2 +#define S626_STDWID_CLKENAB 1 + +/* Bit field masks for standardized SETUP structure: */ +#define S626_STDMSK_INTSRC S626_SET_STD_INTSRC(~0) +#define S626_STDMSK_LATCHSRC S626_SET_STD_LATCHSRC(~0) +#define S626_STDMSK_LOADSRC S626_SET_STD_LOADSRC(~0) +#define S626_STDMSK_INDXSRC S626_SET_STD_INDXSRC(~0) +#define S626_STDMSK_INDXPOL S626_SET_STD_INDXPOL(~0) +#define S626_STDMSK_ENCMODE S626_SET_STD_ENCMODE(~0) +#define S626_STDMSK_CLKPOL S626_SET_STD_CLKPOL(~0) +#define S626_STDMSK_CLKMULT S626_SET_STD_CLKMULT(~0) +#define S626_STDMSK_CLKENAB S626_SET_STD_CLKENAB(~0) + +/* Construct parts of standardized SETUP structure: */ +#define S626_SET_STD_INTSRC(x) \ + S626_MAKE((x), S626_STDWID_INTSRC, S626_STDBIT_INTSRC) +#define S626_SET_STD_LATCHSRC(x) \ + S626_MAKE((x), S626_STDWID_LATCHSRC, S626_STDBIT_LATCHSRC) +#define S626_SET_STD_LOADSRC(x) \ + S626_MAKE((x), S626_STDWID_LOADSRC, S626_STDBIT_LOADSRC) +#define S626_SET_STD_INDXSRC(x) \ + S626_MAKE((x), S626_STDWID_INDXSRC, S626_STDBIT_INDXSRC) +#define S626_SET_STD_INDXPOL(x) \ + S626_MAKE((x), S626_STDWID_INDXPOL, S626_STDBIT_INDXPOL) +#define S626_SET_STD_ENCMODE(x) \ + S626_MAKE((x), S626_STDWID_ENCMODE, S626_STDBIT_ENCMODE) +#define S626_SET_STD_CLKPOL(x) \ + S626_MAKE((x), S626_STDWID_CLKPOL, S626_STDBIT_CLKPOL) +#define S626_SET_STD_CLKMULT(x) \ + S626_MAKE((x), S626_STDWID_CLKMULT, S626_STDBIT_CLKMULT) +#define S626_SET_STD_CLKENAB(x) \ + S626_MAKE((x), S626_STDWID_CLKENAB, S626_STDBIT_CLKENAB) + +/* Extract parts of standardized SETUP structure: */ +#define S626_GET_STD_INTSRC(v) \ + S626_UNMAKE((v), S626_STDWID_INTSRC, S626_STDBIT_INTSRC) +#define S626_GET_STD_LATCHSRC(v) \ + S626_UNMAKE((v), S626_STDWID_LATCHSRC, S626_STDBIT_LATCHSRC) +#define S626_GET_STD_LOADSRC(v) \ + S626_UNMAKE((v), S626_STDWID_LOADSRC, S626_STDBIT_LOADSRC) +#define S626_GET_STD_INDXSRC(v) \ + S626_UNMAKE((v), S626_STDWID_INDXSRC, S626_STDBIT_INDXSRC) +#define S626_GET_STD_INDXPOL(v) \ + S626_UNMAKE((v), S626_STDWID_INDXPOL, S626_STDBIT_INDXPOL) +#define S626_GET_STD_ENCMODE(v) \ + S626_UNMAKE((v), S626_STDWID_ENCMODE, S626_STDBIT_ENCMODE) +#define S626_GET_STD_CLKPOL(v) \ + S626_UNMAKE((v), S626_STDWID_CLKPOL, S626_STDBIT_CLKPOL) +#define S626_GET_STD_CLKMULT(v) \ + S626_UNMAKE((v), S626_STDWID_CLKMULT, S626_STDBIT_CLKMULT) +#define S626_GET_STD_CLKENAB(v) \ + S626_UNMAKE((v), S626_STDWID_CLKENAB, S626_STDBIT_CLKENAB) + +#endif diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index b4f5fe35b0f..441813ffb17 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -26,10 +26,10 @@ Status: in development */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> #include <linux/sched.h> #include <linux/slab.h> @@ -719,10 +719,9 @@ static int serial2002_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->port = it->options[0]; devpriv->speed = it->options[1]; diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index 06aee302bbc..3bfa221faf4 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -67,6 +67,7 @@ Configuration Options: * options that are used with comedi_config. */ +#include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" @@ -141,6 +142,29 @@ static int skel_ns_to_timer(unsigned int *ns, int round) } /* + * This function doesn't require a particular form, this is just + * what happens to be used in some of the drivers. The comedi_timeout() + * helper uses this callback to check for the end-of-conversion while + * waiting for up to 1 second. This function should return 0 when the + * conversion is finished and -EBUSY to keep waiting. Any other errno + * will terminate comedi_timeout() and return that errno to the caller. + * If the timeout occurs, comedi_timeout() will return -ETIMEDOUT. + */ +static int skel_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + /* status = inb(dev->iobase + SKEL_STATUS); */ + status = 1; + if (status) + return 0; + return -EBUSY; +} + +/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ @@ -148,9 +172,9 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct skel_board *thisboard = comedi_board(dev); - int n, i; + int n; unsigned int d; - unsigned int status; + int ret; /* a typical programming sequence */ @@ -164,18 +188,10 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ /* outw(0,dev->iobase + SKEL_CONVERT); */ -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = 1; - /* status = inb(dev->iobase + SKEL_STATUS); */ - if (status) - break; - } - if (i == TIMEOUT) { - dev_warn(dev->class_dev, "ai timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0); + if (ret) + return ret; /* read data */ /* d = inw(dev->iobase + SKEL_AI_DATA); */ @@ -204,7 +220,7 @@ static int skel_ai_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -270,24 +286,19 @@ static int skel_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - skel_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + skel_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - skel_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + skel_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -331,61 +342,71 @@ static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* DIO devices are slightly special. Although it is possible to +/* + * DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ + * This allows packed reading/writing of the DIO channels. The + * comedi core can convert between insn_bits and insn_read/write. + */ static int skel_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + /* + * The insn data is a mask in data[0] and the new data + * in data[1], each channel cooresponding to a bit. + * + * The core provided comedi_dio_update_state() function can + * be used to handle the internal state update to DIO subdevices + * with <= 32 channels. This function will return '0' if the + * state does not change or the mask of the channels that need + * to be updated. + */ + if (comedi_dio_update_state(s, data)) { /* Write out the new digital output lines */ - /* outw(s->state,dev->iobase + SKEL_DIO); */ + /* outw(s->state, dev->iobase + SKEL_DIO); */ } - /* on return, data[1] contains the value of the digital - * input and output lines. */ - /* data[1]=inw(dev->iobase + SKEL_DIO); */ - /* or we could just return the software copy of the output values if - * it was a purely digital output subdevice */ - /* data[1]=s->state; */ + /* + * On return, data[1] contains the value of the digital + * input and output lines. + */ + /* data[1] = inw(dev->iobase + SKEL_DIO); */ + + /* + * Or we could just return the software copy of the output + * values if it was a purely digital output subdevice. + */ + /* data[1] = s->state; */ return insn->n; } static int skel_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + int ret; - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } - /* outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); */ + /* + * The input or output configuration of each digital line is + * configured by special insn_config instructions. + * + * chanspec contains the channel to be changed + * data[0] contains the instruction to perform on the channel + * + * Normally the core provided comedi_dio_insn_config() function + * can be used to handle the boilerplpate. + */ + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + + /* Update the hardware to the new configuration */ + /* outw(s->io_bits, dev->iobase + SKEL_DIO_CONFIG); */ return insn->n; } @@ -445,8 +466,6 @@ static int skel_common_attach(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; } - dev_info(dev->class_dev, "skel: attached\n"); - return 0; } @@ -484,10 +503,9 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* dev->board_name = thisboard->name; */ /* Allocate the private data */ - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* * Supported boards are usually either auto-attached via the @@ -558,10 +576,9 @@ static int skel_auto_attach(struct comedi_device *dev, dev->board_name = thisboard->name; /* Allocate the private data */ - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; /* Enable the PCI device. */ ret = comedi_pci_enable(dev); @@ -689,7 +706,7 @@ static int skel_pci_probe(struct pci_dev *dev, * This is used by modprobe to translate PCI IDs to drivers. * Should only be used for PCI and ISA-PnP devices */ -static DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = { +static const struct pci_device_id skel_pci_table[] = { { PCI_VDEVICE(SKEL, 0x0100), BOARD_SKEL100 }, { PCI_VDEVICE(SKEL, 0x0200), BOARD_SKEL200 }, { 0 } diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index 45c661cbdbb..848c3080158 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -26,6 +26,7 @@ Status: unknown /* include files ----------------------------------------------------------- */ +#include <linux/module.h> #include "../comedidev.h" /* Some global definitions: the registers of the DNP ----------------------- */ @@ -45,115 +46,87 @@ Status: unknown #define PCMR 0xa3 /* Port C Mode Register */ #define PCDR 0xa7 /* Port C Data Register */ -/* ------------------------------------------------------------------------- */ -/* The insn_bits interface allows packed reading/writing of DIO channels. */ -/* The comedi core can convert between insn_bits and insn_read/write, so you */ -/* are able to use these instructions as well. */ -/* ------------------------------------------------------------------------- */ - static int dnp_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data in data[1], */ - /* each channel cooresponding to a bit. */ - - /* Ports A and B are straight forward: each bit corresponds to an */ - /* output pin with the same order. Port C is different: bits 0...3 */ - /* correspond to bits 4...7 of the output register (PCDR). */ + unsigned int mask; + unsigned int val; - if (data[0]) { + /* + * Ports A and B are straight forward: each bit corresponds to an + * output pin with the same order. Port C is different: bits 0...3 + * correspond to bits 4...7 of the output register (PCDR). + */ + mask = comedi_dio_update_state(s, data); + if (mask) { outb(PADR, CSCIR); - outb((inb(CSCDR) - & ~(u8) (data[0] & 0x0000FF)) - | (u8) (data[1] & 0x0000FF), CSCDR); + outb(s->state & 0xff, CSCDR); outb(PBDR, CSCIR); - outb((inb(CSCDR) - & ~(u8) ((data[0] & 0x00FF00) >> 8)) - | (u8) ((data[1] & 0x00FF00) >> 8), CSCDR); + outb((s->state >> 8) & 0xff, CSCDR); outb(PCDR, CSCIR); - outb((inb(CSCDR) - & ~(u8) ((data[0] & 0x0F0000) >> 12)) - | (u8) ((data[1] & 0x0F0000) >> 12), CSCDR); + val = inb(CSCDR) & 0x0f; + outb(((s->state >> 12) & 0xf0) | val, CSCDR); } - /* on return, data[1] contains the value of the digital input lines. */ outb(PADR, CSCIR); - data[0] = inb(CSCDR); + val = inb(CSCDR); outb(PBDR, CSCIR); - data[0] += inb(CSCDR) << 8; + val |= (inb(CSCDR) << 8); outb(PCDR, CSCIR); - data[0] += ((inb(CSCDR) & 0xF0) << 12); + val |= ((inb(CSCDR) & 0xf0) << 12); - return insn->n; + data[1] = val; + return insn->n; } -/* ------------------------------------------------------------------------- */ -/* Configure the direction of the bidirectional digital i/o pins. chanspec */ -/* contains the channel to be changed and data[0] contains either */ -/* COMEDI_INPUT or COMEDI_OUTPUT. */ -/* ------------------------------------------------------------------------- */ - static int dnp_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + unsigned int val; + int ret; - u8 register_buffer; - - /* reduces chanspec to lower 16 bits */ - int chan = CR_CHAN(insn->chanspec); - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - case INSN_CONFIG_DIO_INPUT: - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (inb(CSCDR) & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } - /* Test: which port does the channel belong to? */ - - /* We have to pay attention with port C: this is the meaning of PCMR: */ - /* Bit in PCMR: 7 6 5 4 3 2 1 0 */ - /* Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch */ + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - if ((chan >= 0) && (chan <= 7)) { - /* this is port A */ + if (chan < 8) { /* Port A */ + mask = 1 << chan; outb(PAMR, CSCIR); - } else if ((chan >= 8) && (chan <= 15)) { - /* this is port B */ - chan -= 8; + } else if (chan < 16) { /* Port B */ + mask = 1 << (chan - 8); outb(PBMR, CSCIR); - } else if ((chan >= 16) && (chan <= 19)) { - /* this is port C; multiplication with 2 brings bits into */ - /* correct position for PCMR! */ - chan -= 16; - chan *= 2; + } else { /* Port C */ + /* + * We have to pay attention with port C. + * This is the meaning of PCMR: + * Bit in PCMR: 7 6 5 4 3 2 1 0 + * Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch + * + * Multiplication by 2 brings bits into correct position + * for PCMR! + */ + mask = 1 << ((chan - 16) * 2); outb(PCMR, CSCIR); - } else { - return -EINVAL; } - /* read 'old' direction of the port and set bits (out=1, in=0) */ - register_buffer = inb(CSCDR); + val = inb(CSCDR); if (data[0] == COMEDI_OUTPUT) - register_buffer |= (1 << chan); + val |= mask; else - register_buffer &= ~(1 << chan); - - outb(register_buffer, CSCDR); + val &= ~mask; + outb(val, CSCDR); - return 1; + return insn->n; } @@ -188,8 +161,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(PCMR, CSCIR); outb((inb(CSCDR) & 0xAA), CSCDR); - dev_info(dev->class_dev, "%s: attached\n", dev->board_name); - return 1; + return 0; } static void dnp_detach(struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c index c9201d821fb..adf7cb7086c 100644 --- a/drivers/staging/comedi/drivers/unioxx5.c +++ b/drivers/staging/comedi/drivers/unioxx5.c @@ -38,11 +38,10 @@ Devices: [Fastwel] UNIOxx-5 (unioxx5), */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/module.h> +#include <linux/delay.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/slab.h> #define DRIVER_NAME "unioxx5" #define UNIOXX5_SIZE 0x10 @@ -91,12 +90,14 @@ static int __unioxx5_define_chan_offset(int chan_num) } #if 0 /* not used? */ -static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode) +static void __unioxx5_digital_config(struct comedi_subdevice *s, int mode) { + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; int i, mask; mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00; - printk("COMEDI: mode = %d\n", mask); + dev_dbg(csdev, "mode = %d\n", mask); outb(1, usp->usp_iobase + 0); @@ -135,15 +136,18 @@ static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel) usp->usp_prev_cn_val[channel_offset - 1] = conf; } -static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, +static int __unioxx5_digital_read(struct comedi_subdevice *s, unsigned int *data, int channel, int minor) { + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; int channel_offset, mask = 1 << (channel & 0x07); channel_offset = __unioxx5_define_chan_offset(channel); if (channel_offset < 0) { - pr_err("comedi%d: undefined channel %d. channel range is 0 .. 23\n", - minor, channel); + dev_err(csdev, + "undefined channel %d. channel range is 0 .. 23\n", + channel); return 0; } @@ -157,9 +161,11 @@ static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, return 1; } -static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, +static int __unioxx5_analog_read(struct comedi_subdevice *s, unsigned int *data, int channel, int minor) { + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; int module_no, read_ch; char control; @@ -168,8 +174,9 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, /* defining if given module can work on input */ if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) { - pr_err("comedi%d: module in position %d with id 0x%02x is for output only", - minor, module_no, usp->usp_module_type[module_no]); + dev_err(csdev, + "module in position %d with id 0x%02x is for output only", + module_no, usp->usp_module_type[module_no]); return 0; } @@ -185,7 +192,7 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, /* if four bytes readding error occurs - return 0(false) */ if ((control & Rx4CA_ERR_MASK)) { - printk("COMEDI: 4 bytes error\n"); + dev_err(csdev, "4 bytes error\n"); return 0; } @@ -197,16 +204,19 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, return 1; } -static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, +static int __unioxx5_digital_write(struct comedi_subdevice *s, unsigned int *data, int channel, int minor) { + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; int channel_offset, val; int mask = 1 << (channel & 0x07); channel_offset = __unioxx5_define_chan_offset(channel); if (channel_offset < 0) { - pr_err("comedi%d: undefined channel %d. channel range is 0 .. 23\n", - minor, channel); + dev_err(csdev, + "undefined channel %d. channel range is 0 .. 23\n", + channel); return 0; } @@ -225,9 +235,11 @@ static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, return 1; } -static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, +static int __unioxx5_analog_write(struct comedi_subdevice *s, unsigned int *data, int channel, int minor) { + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; int module, i; module = channel / 2; /* definig module number(0 .. 11) */ @@ -235,8 +247,9 @@ static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, /* defining if given module can work on output */ if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) { - pr_err("comedi%d: module in position %d with id 0x%0x is for input only!\n", - minor, module, usp->usp_module_type[module]); + dev_err(csdev, + "module in position %d with id 0x%0x is for input only!\n", + module, usp->usp_module_type[module]); return 0; } @@ -273,10 +286,10 @@ static int unioxx5_subdev_read(struct comedi_device *dev, type = usp->usp_module_type[channel / 2]; if (type == MODULE_DIGITAL) { - if (!__unioxx5_digital_read(usp, data, channel, dev->minor)) + if (!__unioxx5_digital_read(subdev, data, channel, dev->minor)) return -1; } else { - if (!__unioxx5_analog_read(usp, data, channel, dev->minor)) + if (!__unioxx5_analog_read(subdev, data, channel, dev->minor)) return -1; } @@ -295,10 +308,10 @@ static int unioxx5_subdev_write(struct comedi_device *dev, type = usp->usp_module_type[channel / 2]; if (type == MODULE_DIGITAL) { - if (!__unioxx5_digital_write(usp, data, channel, dev->minor)) + if (!__unioxx5_digital_write(subdev, data, channel, dev->minor)) return -1; } else { - if (!__unioxx5_analog_write(usp, data, channel, dev->minor)) + if (!__unioxx5_analog_write(subdev, data, channel, dev->minor)) return -1; } @@ -318,16 +331,15 @@ static int unioxx5_insn_config(struct comedi_device *dev, if (type != MODULE_DIGITAL) { dev_err(dev->class_dev, - "comedi%d: channel configuration accessible only for digital modules\n", - dev->minor); + "channel configuration accessible only for digital modules\n"); return -1; } channel_offset = __unioxx5_define_chan_offset(channel); if (channel_offset < 0) { dev_err(dev->class_dev, - "comedi%d: undefined channel %d. channel range is 0 .. 23\n", - dev->minor, channel); + "undefined channel %d. channel range is 0 .. 23\n", + channel); return -1; } @@ -342,8 +354,7 @@ static int unioxx5_insn_config(struct comedi_device *dev, flags |= mask; break; default: - dev_err(dev->class_dev, - "comedi%d: unknown flag\n", dev->minor); + dev_err(dev->class_dev, "unknown flag\n"); return -1; } @@ -435,9 +446,10 @@ static int unioxx5_attach(struct comedi_device *dev, dev->iobase = iobase; iobase += UNIOXX5_SUBDEV_BASE; + n_subd = 0; - /* defining number of subdevices and getting they types (it must be 'g01') */ - for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) { + /* getting number of subdevices with types 'g01' */ + for (i = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) { id = inb(ba + 0xE); num = inb(ba + 0xF); diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 279e5bd493f..5f65e4213c6 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -78,12 +78,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. * */ -/* generates loads of debug info */ -/* #define NOISY_DUX_DEBUGBUG */ - #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/usb.h> @@ -94,42 +90,29 @@ sampling rate. If you sample two channels you get 4kHz and so on. #include "comedi_fc.h" -/* timeout for the USB-transfer in ms*/ -#define BULK_TIMEOUT 1000 - -/* constants for "firmware" upload and download */ -#define FIRMWARE "usbdux_firmware.bin" -#define USBDUXSUB_FIRMWARE 0xA0 -#define VENDOR_DIR_IN 0xC0 -#define VENDOR_DIR_OUT 0x40 - -/* internal addresses of the 8051 processor */ -#define USBDUXSUB_CPUCS 0xE600 - -/* - * the minor device number, major is 180 only for debugging purposes and to - * upload special firmware (programming the eeprom etc) which is not compatible - * with the comedi framwork - */ -#define USBDUXSUB_MINOR 32 - -/* max lenghth of the transfer-buffer for software upload */ -#define TB_LEN 0x2000 - -/* Input endpoint number: ISO/IRQ */ -#define ISOINEP 6 - -/* Output endpoint number: ISO/IRQ */ -#define ISOOUTEP 2 - -/* This EP sends DUX commands to USBDUX */ -#define COMMAND_OUT_EP 1 - -/* This EP receives the DUX commands from USBDUX */ -#define COMMAND_IN_EP 8 - -/* Output endpoint for PWM */ -#define PWM_EP 4 +/* constants for firmware upload and download */ +#define USBDUX_FIRMWARE "usbdux_firmware.bin" +#define USBDUX_FIRMWARE_MAX_LEN 0x2000 +#define USBDUX_FIRMWARE_CMD 0xa0 +#define VENDOR_DIR_IN 0xc0 +#define VENDOR_DIR_OUT 0x40 +#define USBDUX_CPU_CS 0xe600 + +/* usbdux bulk transfer commands */ +#define USBDUX_CMD_MULT_AI 0 +#define USBDUX_CMD_AO 1 +#define USBDUX_CMD_DIO_CFG 2 +#define USBDUX_CMD_DIO_BITS 3 +#define USBDUX_CMD_SINGLE_AI 4 +#define USBDUX_CMD_TIMER_RD 5 +#define USBDUX_CMD_TIMER_WR 6 +#define USBDUX_CMD_PWM_ON 7 +#define USBDUX_CMD_PWM_OFF 8 + +#define USBDUX_NUM_AO_CHAN 4 + +/* timeout for the USB-transfer in ms */ +#define BULK_TIMEOUT 1000 /* 300Hz max frequ under PWM */ #define MIN_PWM_PERIOD ((long)(1E9/300)) @@ -137,11 +120,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. /* Default PWM frequency */ #define PWM_DEFAULT_PERIOD ((long)(1E9/100)) -/* Number of channels */ -#define NUMCHANNELS 8 - /* Size of one A/D value */ -#define SIZEADIN ((sizeof(int16_t))) +#define SIZEADIN ((sizeof(uint16_t))) /* * Size of the input-buffer IN BYTES @@ -152,11 +132,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. /* 16 bytes. */ #define SIZEINSNBUF 16 -/* Number of DA channels */ -#define NUMOUTCHANNELS 8 - /* size of one value for the D/A converter: channel and value */ -#define SIZEDAOUT ((sizeof(int8_t)+sizeof(int16_t))) +#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) /* * Size of the output-buffer in bytes @@ -185,101 +162,53 @@ sampling rate. If you sample two channels you get 4kHz and so on. /* must have more buffers due to buggy USB ctr */ #define NUMOFOUTBUFFERSHIGH 10 -/* Total number of usbdux devices */ -#define NUMUSBDUX 16 - -/* Analogue in subdevice */ -#define SUBDEV_AD 0 - -/* Analogue out subdevice */ -#define SUBDEV_DA 1 - -/* Digital I/O */ -#define SUBDEV_DIO 2 - -/* counter */ -#define SUBDEV_COUNTER 3 - -/* timer aka pwm output */ -#define SUBDEV_PWM 4 - /* number of retries to get the right dux command */ #define RETRIES 10 -/**************************************************/ -/* comedi constants */ -static const struct comedi_lrange range_usbdux_ai_range = { 4, { - BIP_RANGE - (4.096), - BIP_RANGE(4.096 - / 2), - UNI_RANGE - (4.096), - UNI_RANGE(4.096 - / 2) - } +static const struct comedi_lrange range_usbdux_ai_range = { + 4, { + BIP_RANGE(4.096), + BIP_RANGE(4.096 / 2), + UNI_RANGE(4.096), + UNI_RANGE(4.096 / 2) + } }; -static const struct comedi_lrange range_usbdux_ao_range = { 2, { - BIP_RANGE - (4.096), - UNI_RANGE - (4.096), - } +static const struct comedi_lrange range_usbdux_ao_range = { + 2, { + BIP_RANGE(4.096), + UNI_RANGE(4.096) + } }; -/* - * private structure of one subdevice - */ - -/* - * This is the structure which holds all the data of - * this driver one sub device just now: A/D - */ -struct usbduxsub { - /* attached? */ - int attached; - /* is it associated with a subdevice? */ - int probed; - /* pointer to the usb-device */ - struct usb_device *usbdev; +struct usbdux_private { /* actual number of in-buffers */ - int num_in_buffers; + int n_ai_urbs; /* actual number of out-buffers */ - int num_out_buffers; + int n_ao_urbs; /* ISO-transfer handling: buffers */ - struct urb **urb_in; - struct urb **urb_out; + struct urb **ai_urbs; + struct urb **ao_urbs; /* pwm-transfer handling */ - struct urb *urb_pwm; + struct urb *pwm_urb; /* PWM period */ unsigned int pwm_period; /* PWM internal delay for the GPIF in the FX2 */ - int8_t pwn_delay; + uint8_t pwm_delay; /* size of the PWM buffer which holds the bit pattern */ - int size_pwm_buf; + int pwm_buf_sz; /* input buffer for the ISO-transfer */ - int16_t *in_buffer; + uint16_t *in_buf; /* input buffer for single insn */ - int16_t *insn_buffer; - /* output buffer for single DA outputs */ - int16_t *out_buffer; - /* interface number */ - int ifnum; - /* interface structure in 2.6 */ - struct usb_interface *interface; - /* comedi device for the interrupt context */ - struct comedi_device *comedidev; - /* is it USB_SPEED_HIGH or not? */ - short int high_speed; - /* asynchronous command is running */ - short int ai_cmd_running; - short int ao_cmd_running; - /* pwm is running */ - short int pwm_cmd_running; - /* continous acquisition */ - short int ai_continous; - short int ao_continous; + uint16_t *insn_buf; + + unsigned int ao_readback[USBDUX_NUM_AO_CHAN]; + + unsigned int high_speed:1; + unsigned int ai_cmd_running:1; + unsigned int ao_cmd_running:1; + unsigned int pwm_cmd_running:1; + /* number of samples to acquire */ int ai_sample_count; int ao_sample_count; @@ -291,132 +220,63 @@ struct usbduxsub { unsigned int ao_counter; /* interval in frames/uframes */ unsigned int ai_interval; - /* D/A commands */ - int8_t *dac_commands; /* commands */ - int8_t *dux_commands; + uint8_t *dux_commands; struct semaphore sem; }; -/* - * The pointer to the private usb-data of the driver is also the private data - * for the comedi-device. This has to be global as the usb subsystem needs - * global variables. The other reason is that this structure must be there - * _before_ any comedi command is issued. The usb subsystem must be initialised - * before comedi can access it. - */ -static struct usbduxsub usbduxsub[NUMUSBDUX]; - -static DEFINE_SEMAPHORE(start_stop_sem); - -/* - * Stops the data acquision - * It should be safe to call this function from any context - */ -static int usbduxsub_unlink_inurbs(struct usbduxsub *usbduxsub_tmp) +static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs) { - int i = 0; - int err = 0; + int i; - if (usbduxsub_tmp && usbduxsub_tmp->urb_in) { - for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) { - if (usbduxsub_tmp->urb_in[i]) { - /* We wait here until all transfers have been - * cancelled. */ - usb_kill_urb(usbduxsub_tmp->urb_in[i]); - } - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: usbdux: unlinked InURB %d, err=%d\n", - i, err); - } - } - return err; + for (i = 0; i < num_urbs; i++) + usb_kill_urb(urbs[i]); } -/* - * This will stop a running acquisition operation - * Is called from within this driver from both the - * interrupt context and from comedi - */ -static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink) +static void usbdux_ai_stop(struct comedi_device *dev, int do_unlink) { - int ret = 0; - - if (!this_usbduxsub) { - pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n"); - return -EFAULT; - } - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n"); - - if (do_unlink) { - /* stop aquistion */ - ret = usbduxsub_unlink_inurbs(this_usbduxsub); - } + struct usbdux_private *devpriv = dev->private; - this_usbduxsub->ai_cmd_running = 0; + if (do_unlink && devpriv->ai_urbs) + usbdux_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs); - return ret; + devpriv->ai_cmd_running = 0; } -/* - * This will cancel a running acquisition operation. - * This is called by comedi but never from inside the driver. - */ static int usbdux_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub; - int res = 0; - - /* force unlink of all urbs */ - this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_cancel\n"); + struct usbdux_private *devpriv = dev->private; /* prevent other CPUs from submitting new commands just now */ - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); /* unlink only if the urb really has been submitted */ - res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running); - up(&this_usbduxsub->sem); - return res; + usbdux_ai_stop(dev, devpriv->ai_cmd_running); + up(&devpriv->sem); + + return 0; } /* analogue IN - interrupt service routine */ static void usbduxsub_ai_isoc_irq(struct urb *urb) { - int i, err, n; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - /* subdevice which is the AD converter */ - s = &this_comedidev->subdevices[SUBDEV_AD]; + struct comedi_device *dev = urb->context; + struct comedi_subdevice *s = dev->read_subdev; + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int i, err; /* first we test if something unusual has just happened */ switch (urb->status) { case 0: /* copy the result in the transfer buffer */ - memcpy(this_usbduxsub->in_buffer, - urb->transfer_buffer, SIZEINBUF); + memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); break; case -EILSEQ: /* error in the ISOchronous data */ /* we don't copy the data into the transfer buffer */ /* and recycle the last data byte */ - dev_dbg(&urb->dev->dev, - "comedi%d: usbdux: CRC error in ISO IN stream.\n", - this_usbduxsub->comedidev->minor); - + dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); break; case -ECONNRESET: @@ -424,29 +284,27 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ - if (this_usbduxsub->ai_cmd_running) { - /* we are still running a command */ - /* tell this comedi */ + if (devpriv->ai_cmd_running) { s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* stop the transfer w/o unlink */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); } return; default: /* a real error on the bus */ /* pass error to comedi if we are really running a command */ - if (this_usbduxsub->ai_cmd_running) { - dev_err(&urb->dev->dev, - "Non-zero urb status received in ai intr " - "context: %d\n", urb->status); + if (devpriv->ai_cmd_running) { + dev_err(dev->class_dev, + "Non-zero urb status received in ai intr context: %d\n", + urb->status); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* don't do an unlink here */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); } return; } @@ -455,7 +313,7 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) * at this point we are reasonably sure that nothing dodgy has happened * are we running a command? */ - if (unlikely((!(this_usbduxsub->ai_cmd_running)))) { + if (unlikely(!devpriv->ai_cmd_running)) { /* * not running a command, do not continue execution if no * asynchronous command is running in particular not resubmit @@ -463,144 +321,100 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) return; } - urb->dev = this_usbduxsub->usbdev; + urb->dev = comedi_to_usb_dev(dev); /* resubmit the urb */ err = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(err < 0)) { - dev_err(&urb->dev->dev, - "comedi_: urb resubmit failed in int-context! err=%d\n", - err); + dev_err(dev->class_dev, + "urb resubmit failed in int-context! err=%d\n", err); if (err == -EL2NSYNC) - dev_err(&urb->dev->dev, - "buggy USB host controller or bug in IRQ " - "handler!\n"); + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler!\n"); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* don't do an unlink here */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); return; } - this_usbduxsub->ai_counter--; - if (likely(this_usbduxsub->ai_counter > 0)) + devpriv->ai_counter--; + if (likely(devpriv->ai_counter > 0)) return; /* timer zero, transfer measurements to comedi */ - this_usbduxsub->ai_counter = this_usbduxsub->ai_timer; + devpriv->ai_counter = devpriv->ai_timer; /* test, if we transmit only a fixed number of samples */ - if (!(this_usbduxsub->ai_continous)) { + if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ - this_usbduxsub->ai_sample_count--; + devpriv->ai_sample_count--; /* all samples received? */ - if (this_usbduxsub->ai_sample_count < 0) { + if (devpriv->ai_sample_count < 0) { /* prevent a resubmit next time */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); /* say comedi that the acquistion is over */ s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); return; } } /* get the data from the USB bus and hand it over to comedi */ - n = s->async->cmd.chanlist_len; - for (i = 0; i < n; i++) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int range = CR_RANGE(cmd->chanlist[i]); + uint16_t val = le16_to_cpu(devpriv->in_buf[i]); + + /* bipolar data is two's-complement */ + if (comedi_range_is_bipolar(s, range)) + val ^= ((s->maxdata + 1) >> 1); + /* transfer data */ - if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) { - err = comedi_buf_put - (s->async, - le16_to_cpu(this_usbduxsub->in_buffer[i]) ^ 0x800); - } else { - err = comedi_buf_put - (s->async, - le16_to_cpu(this_usbduxsub->in_buffer[i])); - } + err = comedi_buf_put(s, val); if (unlikely(err == 0)) { /* buffer overflow */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); return; } } /* tell comedi that data is there */ s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); } -static int usbduxsub_unlink_outurbs(struct usbduxsub *usbduxsub_tmp) +static void usbdux_ao_stop(struct comedi_device *dev, int do_unlink) { - int i = 0; - int err = 0; + struct usbdux_private *devpriv = dev->private; - if (usbduxsub_tmp && usbduxsub_tmp->urb_out) { - for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) { - if (usbduxsub_tmp->urb_out[i]) - usb_kill_urb(usbduxsub_tmp->urb_out[i]); + if (do_unlink && devpriv->ao_urbs) + usbdux_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs); - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: usbdux: unlinked OutURB %d: res=%d\n", - i, err); - } - } - return err; + devpriv->ao_cmd_running = 0; } -/* This will cancel a running acquisition operation - * in any context. - */ -static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink) -{ - int ret = 0; - - if (!this_usbduxsub) - return -EFAULT; - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n"); - - if (do_unlink) - ret = usbduxsub_unlink_outurbs(this_usbduxsub); - - this_usbduxsub->ao_cmd_running = 0; - - return ret; -} - -/* force unlink, is called by comedi */ static int usbdux_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub = dev->private; - int res = 0; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; /* prevent other CPUs from submitting a command just now */ - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); /* unlink only if it is really running */ - res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running); - up(&this_usbduxsub->sem); - return res; + usbdux_ao_stop(dev, devpriv->ao_cmd_running); + up(&devpriv->sem); + + return 0; } static void usbduxsub_ao_isoc_irq(struct urb *urb) { - int i, ret; - int8_t *datap; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - - s = &this_comedidev->subdevices[SUBDEV_DA]; + struct comedi_device *dev = urb->context; + struct comedi_subdevice *s = dev->write_subdev; + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + uint8_t *datap; + int ret; + int i; switch (urb->status) { case 0: @@ -613,246 +427,130 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) case -ECONNABORTED: /* after an unlink command, unplug, ... etc */ /* no unlink needed here. Already shutting down. */ - if (this_usbduxsub->ao_cmd_running) { + if (devpriv->ao_cmd_running) { s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); - usbdux_ao_stop(this_usbduxsub, 0); + comedi_event(dev, s); + usbdux_ao_stop(dev, 0); } return; default: /* a real error */ - if (this_usbduxsub->ao_cmd_running) { - dev_err(&urb->dev->dev, - "comedi_: Non-zero urb status received in ao " - "intr context: %d\n", urb->status); + if (devpriv->ao_cmd_running) { + dev_err(dev->class_dev, + "Non-zero urb status received in ao intr context: %d\n", + urb->status); s->async->events |= COMEDI_CB_ERROR; s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* we do an unlink if we are in the high speed mode */ - usbdux_ao_stop(this_usbduxsub, 0); + usbdux_ao_stop(dev, 0); } return; } /* are we actually running? */ - if (!(this_usbduxsub->ao_cmd_running)) + if (!devpriv->ao_cmd_running) return; /* normal operation: executing a command in this subdevice */ - this_usbduxsub->ao_counter--; - if ((int)this_usbduxsub->ao_counter <= 0) { + devpriv->ao_counter--; + if ((int)devpriv->ao_counter <= 0) { /* timer zero */ - this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; + devpriv->ao_counter = devpriv->ao_timer; /* handle non continous acquisition */ - if (!(this_usbduxsub->ao_continous)) { + if (cmd->stop_src == TRIG_COUNT) { /* fixed number of samples */ - this_usbduxsub->ao_sample_count--; - if (this_usbduxsub->ao_sample_count < 0) { + devpriv->ao_sample_count--; + if (devpriv->ao_sample_count < 0) { /* all samples transmitted */ - usbdux_ao_stop(this_usbduxsub, 0); + usbdux_ao_stop(dev, 0); s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* no resubmit of the urb */ return; } } + /* transmit data to the USB bus */ - ((uint8_t *) (urb->transfer_buffer))[0] = - s->async->cmd.chanlist_len; - for (i = 0; i < s->async->cmd.chanlist_len; i++) { - short temp; - if (i >= NUMOUTCHANNELS) - break; + datap = urb->transfer_buffer; + *datap++ = cmd->chanlist_len; + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned short val; - /* pointer to the DA */ - datap = - (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1])); - /* get the data from comedi */ - ret = comedi_buf_get(s->async, &temp); - datap[0] = temp; - datap[1] = temp >> 8; - datap[2] = this_usbduxsub->dac_commands[i]; - /* printk("data[0]=%x, data[1]=%x, data[2]=%x\n", */ - /* datap[0],datap[1],datap[2]); */ + ret = comedi_buf_get(s, &val); if (ret < 0) { - dev_err(&urb->dev->dev, - "comedi: buffer underflow\n"); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_OVERFLOW; + dev_err(dev->class_dev, "buffer underflow\n"); + s->async->events |= (COMEDI_CB_EOA | + COMEDI_CB_OVERFLOW); } - /* transmit data to comedi */ + /* pointer to the DA */ + *datap++ = val & 0xff; + *datap++ = (val >> 8) & 0xff; + *datap++ = chan << 6; + devpriv->ao_readback[chan] = val; + s->async->events |= COMEDI_CB_BLOCK; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); } } urb->transfer_buffer_length = SIZEOUTBUF; - urb->dev = this_usbduxsub->usbdev; + urb->dev = comedi_to_usb_dev(dev); urb->status = 0; - if (this_usbduxsub->ao_cmd_running) { - if (this_usbduxsub->high_speed) { - /* uframes */ - urb->interval = 8; - } else { - /* frames */ - urb->interval = 1; - } + if (devpriv->ao_cmd_running) { + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ urb->number_of_packets = 1; urb->iso_frame_desc[0].offset = 0; urb->iso_frame_desc[0].length = SIZEOUTBUF; urb->iso_frame_desc[0].status = 0; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { - dev_err(&urb->dev->dev, - "comedi_: ao urb resubm failed in int-cont. " - "ret=%d", ret); + dev_err(dev->class_dev, + "ao urb resubm failed in int-cont. ret=%d", + ret); if (ret == EL2NSYNC) - dev_err(&urb->dev->dev, - "buggy USB host controller or bug in " - "IRQ handling!\n"); + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handling!\n"); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* don't do an unlink here */ - usbdux_ao_stop(this_usbduxsub, 0); + usbdux_ao_stop(dev, 0); } } } -#define FIRMWARE_MAX_LEN 0x2000 - -static int usbdux_firmware_upload(struct comedi_device *dev, - const u8 *data, size_t size, - unsigned long context) +static int usbdux_submit_urbs(struct comedi_device *dev, + struct urb **urbs, int num_urbs, + int input_urb) { - struct usbduxsub *usbduxsub = dev->private; - struct usb_device *usb = usbduxsub->usbdev; - uint8_t *buf; - uint8_t *tmp; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + struct urb *urb; int ret; - - if (!data) - return 0; - - if (size > FIRMWARE_MAX_LEN) { - dev_err(&usbduxsub->interface->dev, - "usbdux firmware binary it too large for FX2.\n"); - return -ENOMEM; - } - - /* we generate a local buffer for the firmware */ - buf = kmemdup(data, size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* we need a malloc'ed buffer for usb_control_msg() */ - tmp = kmalloc(1, GFP_KERNEL); - if (!tmp) { - kfree(buf); - return -ENOMEM; - } - - /* stop the current firmware on the device */ - *tmp = 1; /* 7f92 to one */ - ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), - USBDUXSUB_FIRMWARE, - VENDOR_DIR_OUT, - USBDUXSUB_CPUCS, 0x0000, - tmp, 1, - BULK_TIMEOUT); - if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: can not stop firmware\n"); - goto done; - } - - /* upload the new firmware to the device */ - ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), - USBDUXSUB_FIRMWARE, - VENDOR_DIR_OUT, - 0, 0x0000, - buf, size, - BULK_TIMEOUT); - if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: firmware upload failed\n"); - goto done; - } - - /* start the new firmware on the device */ - *tmp = 0; /* 7f92 to zero */ - ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), - USBDUXSUB_FIRMWARE, - VENDOR_DIR_OUT, - USBDUXSUB_CPUCS, 0x0000, - tmp, 1, - BULK_TIMEOUT); - if (ret < 0) - dev_err(&usbduxsub->interface->dev, - "comedi_: can not start firmware\n"); - -done: - kfree(tmp); - kfree(buf); - return ret; -} - -static int usbduxsub_submit_inurbs(struct usbduxsub *usbduxsub) -{ - int i, err_flag; - - if (!usbduxsub) - return -EFAULT; + int i; /* Submit all URBs and start the transfer on the bus */ - for (i = 0; i < usbduxsub->num_in_buffers; i++) { - /* in case of a resubmission after an unlink... */ - usbduxsub->urb_in[i]->interval = usbduxsub->ai_interval; - usbduxsub->urb_in[i]->context = usbduxsub->comedidev; - usbduxsub->urb_in[i]->dev = usbduxsub->usbdev; - usbduxsub->urb_in[i]->status = 0; - usbduxsub->urb_in[i]->transfer_flags = URB_ISO_ASAP; - dev_dbg(&usbduxsub->interface->dev, - "comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n", - usbduxsub->comedidev->minor, i, - (usbduxsub->urb_in[i]->context), - (usbduxsub->urb_in[i]->dev), - (usbduxsub->urb_in[i]->interval)); - err_flag = usb_submit_urb(usbduxsub->urb_in[i], GFP_ATOMIC); - if (err_flag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: ai: usb_submit_urb(%d) error %d\n", - i, err_flag); - return err_flag; - } - } - return 0; -} + for (i = 0; i < num_urbs; i++) { + urb = urbs[i]; -static int usbduxsub_submit_outurbs(struct usbduxsub *usbduxsub) -{ - int i, err_flag; - - if (!usbduxsub) - return -EFAULT; - - for (i = 0; i < usbduxsub->num_out_buffers; i++) { - dev_dbg(&usbduxsub->interface->dev, - "comedi_: submitting out-urb[%d]\n", i); /* in case of a resubmission after an unlink... */ - usbduxsub->urb_out[i]->context = usbduxsub->comedidev; - usbduxsub->urb_out[i]->dev = usbduxsub->usbdev; - usbduxsub->urb_out[i]->status = 0; - usbduxsub->urb_out[i]->transfer_flags = URB_ISO_ASAP; - err_flag = usb_submit_urb(usbduxsub->urb_out[i], GFP_ATOMIC); - if (err_flag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: ao: usb_submit_urb(%d) error %d\n", - i, err_flag); - return err_flag; - } + if (input_urb) + urb->interval = devpriv->ai_interval; + urb->context = dev; + urb->dev = usb; + urb->status = 0; + urb->transfer_flags = URB_ISO_ASAP; + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + return ret; } return 0; } @@ -860,13 +558,10 @@ static int usbduxsub_submit_outurbs(struct usbduxsub *usbduxsub) static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *this_usbduxsub = dev->private; int err = 0, i; unsigned int tmp_timer; - if (!(this_usbduxsub->probed)) - return -ENODEV; - /* Step 1 : check if triggers are trivially valid */ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); @@ -949,228 +644,150 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, * creates the ADC command for the MAX1271 * range is the range value from comedi */ -static int8_t create_adc_command(unsigned int chan, int range) +static uint8_t create_adc_command(unsigned int chan, unsigned int range) { - int8_t p = (range <= 1); - int8_t r = ((range % 2) == 0); + uint8_t p = (range <= 1); + uint8_t r = ((range % 2) == 0); + return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3); } -/* bulk transfers to usbdux */ +static int send_dux_commands(struct comedi_device *dev, unsigned int cmd_type) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + int nsent; -#define SENDADCOMMANDS 0 -#define SENDDACOMMANDS 1 -#define SENDDIOCONFIGCOMMAND 2 -#define SENDDIOBITSCOMMAND 3 -#define SENDSINGLEAD 4 -#define READCOUNTERCOMMAND 5 -#define WRITECOUNTERCOMMAND 6 -#define SENDPWMON 7 -#define SENDPWMOFF 8 + devpriv->dux_commands[0] = cmd_type; -static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type) -{ - int result, nsent; - - this_usbduxsub->dux_commands[0] = cmd_type; -#ifdef NOISY_DUX_DEBUGBUG - printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ", - this_usbduxsub->comedidev->minor); - for (result = 0; result < SIZEOFDUXBUFFER; result++) - printk(" %02x", this_usbduxsub->dux_commands[result]); - printk("\n"); -#endif - result = usb_bulk_msg(this_usbduxsub->usbdev, - usb_sndbulkpipe(this_usbduxsub->usbdev, - COMMAND_OUT_EP), - this_usbduxsub->dux_commands, SIZEOFDUXBUFFER, - &nsent, BULK_TIMEOUT); - if (result < 0) - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "could not transmit dux_command to the usb-device, " - "err=%d\n", this_usbduxsub->comedidev->minor, result); - - return result; + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1), + devpriv->dux_commands, SIZEOFDUXBUFFER, + &nsent, BULK_TIMEOUT); } -static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command) +static int receive_dux_commands(struct comedi_device *dev, unsigned int command) { - int result = (-EFAULT); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + int ret; int nrec; int i; for (i = 0; i < RETRIES; i++) { - result = usb_bulk_msg(this_usbduxsub->usbdev, - usb_rcvbulkpipe(this_usbduxsub->usbdev, - COMMAND_IN_EP), - this_usbduxsub->insn_buffer, SIZEINSNBUF, + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8), + devpriv->insn_buf, SIZEINSNBUF, &nrec, BULK_TIMEOUT); - if (result < 0) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "insn: USB error %d while receiving DUX command" - "\n", this_usbduxsub->comedidev->minor, result); - return result; - } - if (le16_to_cpu(this_usbduxsub->insn_buffer[0]) == command) - return result; + if (ret < 0) + return ret; + if (le16_to_cpu(devpriv->insn_buf[0]) == command) + return ret; } - /* this is only reached if the data has been requested a couple of - * times */ - dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: " - "wrong data returned from firmware: want cmd %d, got cmd %d.\n", - this_usbduxsub->comedidev->minor, command, - le16_to_cpu(this_usbduxsub->insn_buffer[0])); + /* command not received */ return -EFAULT; } static int usbdux_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - struct usbduxsub *this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig\n", dev->minor); - - if (trignum != 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig: invalid trignum\n", - dev->minor); - up(&this_usbduxsub->sem); + if (trig_num != cmd->start_arg) return -EINVAL; - } - if (!(this_usbduxsub->ai_cmd_running)) { - this_usbduxsub->ai_cmd_running = 1; - ret = usbduxsub_submit_inurbs(this_usbduxsub); + + down(&devpriv->sem); + + if (!devpriv->ai_cmd_running) { + devpriv->ai_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig: " - "urbSubmit: err=%d\n", dev->minor, ret); - this_usbduxsub->ai_cmd_running = 0; - up(&this_usbduxsub->sem); - return ret; + devpriv->ai_cmd_running = 0; + goto ai_trig_exit; } s->async->inttrig = NULL; } else { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ai_inttrig but acqu is already running\n", - dev->minor); + ret = -EBUSY; } - up(&this_usbduxsub->sem); - return 1; + +ai_trig_exit: + up(&devpriv->sem); + return ret; } static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct usbdux_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int chan, range; - int i, ret; - struct usbduxsub *this_usbduxsub = dev->private; - int result; - - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_cmd\n", dev->minor); + int len = cmd->chanlist_len; + int ret = -EBUSY; + int i; /* block other CPUs from starting an ai_cmd */ - down(&this_usbduxsub->sem); + down(&devpriv->sem); + + if (devpriv->ai_cmd_running) + goto ai_cmd_exit; - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ai_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "ai_cmd not possible. Another ai_cmd is running.\n", - dev->minor); - up(&this_usbduxsub->sem); - return -EBUSY; - } /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; - this_usbduxsub->dux_commands[1] = cmd->chanlist_len; - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - range = CR_RANGE(cmd->chanlist[i]); - if (i >= NUMCHANNELS) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: channel list too long\n", - dev->minor); - break; - } - this_usbduxsub->dux_commands[i + 2] = - create_adc_command(chan, range); - } - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi %d: sending commands to the usb device: size=%u\n", - dev->minor, NUMCHANNELS); + devpriv->dux_commands[1] = len; + for (i = 0; i < len; ++i) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); - result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS); - if (result < 0) { - up(&this_usbduxsub->sem); - return result; + devpriv->dux_commands[i + 2] = create_adc_command(chan, range); } - if (this_usbduxsub->high_speed) { + ret = send_dux_commands(dev, USBDUX_CMD_MULT_AI); + if (ret < 0) + goto ai_cmd_exit; + + if (devpriv->high_speed) { /* * every channel gets a time window of 125us. Thus, if we * sample all 8 channels we need 1ms. If we sample only one * channel we need only 125us */ - this_usbduxsub->ai_interval = 1; + devpriv->ai_interval = 1; /* find a power of 2 for the interval */ - while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) { - this_usbduxsub->ai_interval = - (this_usbduxsub->ai_interval) * 2; - } - this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 * - (this_usbduxsub-> - ai_interval)); + while (devpriv->ai_interval < len) + devpriv->ai_interval *= 2; + + devpriv->ai_timer = cmd->scan_begin_arg / + (125000 * devpriv->ai_interval); } else { /* interval always 1ms */ - this_usbduxsub->ai_interval = 1; - this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000; + devpriv->ai_interval = 1; + devpriv->ai_timer = cmd->scan_begin_arg / 1000000; } - if (this_usbduxsub->ai_timer < 1) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: " - "timer=%d, scan_begin_arg=%d. " - "Not properly tested by cmdtest?\n", dev->minor, - this_usbduxsub->ai_timer, cmd->scan_begin_arg); - up(&this_usbduxsub->sem); - return -EINVAL; + if (devpriv->ai_timer < 1) { + ret = -EINVAL; + goto ai_cmd_exit; } - this_usbduxsub->ai_counter = this_usbduxsub->ai_timer; + + devpriv->ai_counter = devpriv->ai_timer; if (cmd->stop_src == TRIG_COUNT) { /* data arrives as one packet */ - this_usbduxsub->ai_sample_count = cmd->stop_arg; - this_usbduxsub->ai_continous = 0; + devpriv->ai_sample_count = cmd->stop_arg; } else { /* continous acquisition */ - this_usbduxsub->ai_continous = 1; - this_usbduxsub->ai_sample_count = 0; + devpriv->ai_sample_count = 0; } if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ - this_usbduxsub->ai_cmd_running = 1; - ret = usbduxsub_submit_inurbs(this_usbduxsub); + devpriv->ai_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); if (ret < 0) { - this_usbduxsub->ai_cmd_running = 0; + devpriv->ai_cmd_running = 0; /* fixme: unlink here?? */ - up(&this_usbduxsub->sem); - return ret; + goto ai_cmd_exit; } s->async->inttrig = NULL; } else { @@ -1179,202 +796,157 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* wait for an internal signal */ s->async->inttrig = usbdux_ai_inttrig; } - up(&this_usbduxsub->sem); - return 0; + +ai_cmd_exit: + up(&devpriv->sem); + + return ret; } /* Mode 0 is used to get a single conversion on demand */ static int usbdux_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int ret = -EBUSY; int i; - unsigned int one = 0; - int chan, range; - int err; - struct usbduxsub *this_usbduxsub = dev->private; - - if (!this_usbduxsub) - return 0; - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n", - dev->minor, insn->n, insn->subdev); + down(&devpriv->sem); - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ai_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ai_insn_read not possible. " - "Async Command is running.\n", dev->minor); - up(&this_usbduxsub->sem); - return 0; - } + if (devpriv->ai_cmd_running) + goto ai_read_exit; - /* sample one channel */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); /* set command for the first channel */ - this_usbduxsub->dux_commands[1] = create_adc_command(chan, range); + devpriv->dux_commands[1] = create_adc_command(chan, range); /* adc commands */ - err = send_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } + ret = send_dux_commands(dev, USBDUX_CMD_SINGLE_AI); + if (ret < 0) + goto ai_read_exit; for (i = 0; i < insn->n; i++) { - err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) { - up(&this_usbduxsub->sem); - return 0; - } - one = le16_to_cpu(this_usbduxsub->insn_buffer[1]); - if (CR_RANGE(insn->chanspec) <= 1) - one = one ^ 0x800; + ret = receive_dux_commands(dev, USBDUX_CMD_SINGLE_AI); + if (ret < 0) + goto ai_read_exit; + + val = le16_to_cpu(devpriv->insn_buf[1]); + + /* bipolar data is two's-complement */ + if (comedi_range_is_bipolar(s, range)) + val ^= ((s->maxdata + 1) >> 1); - data[i] = one; + data[i] = val; } - up(&this_usbduxsub->sem); - return i; -} -/************************************/ -/* analog out */ +ai_read_exit: + up(&devpriv->sem); + + return ret ? ret : insn->n; +} static int usbdux_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); - struct usbduxsub *this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); for (i = 0; i < insn->n; i++) - data[i] = this_usbduxsub->out_buffer[chan]; + data[i] = devpriv->ao_readback[chan]; + up(&devpriv->sem); - up(&this_usbduxsub->sem); - return i; + return insn->n; } static int usbdux_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int i, err; - int chan = CR_CHAN(insn->chanspec); - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + uint16_t *p = (uint16_t *)&devpriv->dux_commands[2]; + int ret = -EBUSY; + int i; - if (!this_usbduxsub) - return -EFAULT; + down(&devpriv->sem); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write\n", dev->minor); + if (devpriv->ao_cmd_running) + goto ao_write_exit; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ao_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write: " - "ERROR: asynchronous ao_cmd is running\n", dev->minor); - up(&this_usbduxsub->sem); - return 0; - } + /* number of channels: 1 */ + devpriv->dux_commands[1] = 1; + /* channel number */ + devpriv->dux_commands[4] = chan << 6; for (i = 0; i < insn->n; i++) { - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n", - dev->minor, chan, i, data[i]); + val = data[i]; - /* number of channels: 1 */ - this_usbduxsub->dux_commands[1] = 1; /* one 16 bit value */ - *((int16_t *) (this_usbduxsub->dux_commands + 2)) = - cpu_to_le16(data[i]); - this_usbduxsub->out_buffer[chan] = data[i]; - /* channel number */ - this_usbduxsub->dux_commands[4] = (chan << 6); - err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } + *p = cpu_to_le16(val); + + ret = send_dux_commands(dev, USBDUX_CMD_AO); + if (ret < 0) + goto ao_write_exit; } - up(&this_usbduxsub->sem); + devpriv->ao_readback[chan] = val; + +ao_write_exit: + up(&devpriv->sem); - return i; + return ret ? ret : insn->n; } static int usbdux_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - struct usbduxsub *this_usbduxsub = dev->private; - - if (!this_usbduxsub) - return -EFAULT; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (trignum != 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_inttrig: invalid trignum\n", - dev->minor); - up(&this_usbduxsub->sem); + if (trig_num != cmd->start_arg) return -EINVAL; - } - if (!(this_usbduxsub->ao_cmd_running)) { - this_usbduxsub->ao_cmd_running = 1; - ret = usbduxsub_submit_outurbs(this_usbduxsub); + + down(&devpriv->sem); + + if (!devpriv->ao_cmd_running) { + devpriv->ao_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_inttrig: submitURB: " - "err=%d\n", dev->minor, ret); - this_usbduxsub->ao_cmd_running = 0; - up(&this_usbduxsub->sem); - return ret; + devpriv->ao_cmd_running = 0; + goto ao_trig_exit; } s->async->inttrig = NULL; } else { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ao_inttrig but acqu is already running.\n", - dev->minor); + ret = -EBUSY; } - up(&this_usbduxsub->sem); - return 1; + +ao_trig_exit: + up(&devpriv->sem); + return ret; } static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *this_usbduxsub = dev->private; int err = 0; unsigned int flags; if (!this_usbduxsub) return -EFAULT; - if (!(this_usbduxsub->probed)) - return -ENODEV; - /* Step 1 : check if triggers are trivially valid */ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); @@ -1451,99 +1023,63 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct usbdux_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int chan, gain; - int i, ret; - struct usbduxsub *this_usbduxsub = dev->private; + int ret = -EBUSY; - if (!this_usbduxsub) - return -EFAULT; + down(&devpriv->sem); - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s\n", dev->minor, __func__); + if (devpriv->ao_cmd_running) + goto ao_cmd_exit; /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - gain = CR_RANGE(cmd->chanlist[i]); - if (i >= NUMOUTCHANNELS) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: %s: channel list too long\n", - dev->minor, __func__); - break; - } - this_usbduxsub->dac_commands[i] = (chan << 6); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: dac command for ch %d is %x\n", - dev->minor, i, this_usbduxsub->dac_commands[i]); - } /* we count in steps of 1ms (125us) */ /* 125us mode not used yet */ - if (0) { /* (this_usbduxsub->high_speed) */ + if (0) { /* (devpriv->high_speed) */ /* 125us */ /* timing of the conversion itself: every 125 us */ - this_usbduxsub->ao_timer = cmd->convert_arg / 125000; + devpriv->ao_timer = cmd->convert_arg / 125000; } else { /* 1ms */ /* timing of the scan: we get all channels at once */ - this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000; - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: scan_begin_src=%d, scan_begin_arg=%d, " - "convert_src=%d, convert_arg=%d\n", dev->minor, - cmd->scan_begin_src, cmd->scan_begin_arg, - cmd->convert_src, cmd->convert_arg); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_timer=%d (ms)\n", - dev->minor, this_usbduxsub->ao_timer); - if (this_usbduxsub->ao_timer < 1) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux: ao_timer=%d, " - "scan_begin_arg=%d. " - "Not properly tested by cmdtest?\n", - dev->minor, this_usbduxsub->ao_timer, - cmd->scan_begin_arg); - up(&this_usbduxsub->sem); - return -EINVAL; + devpriv->ao_timer = cmd->scan_begin_arg / 1000000; + if (devpriv->ao_timer < 1) { + ret = -EINVAL; + goto ao_cmd_exit; } } - this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; + + devpriv->ao_counter = devpriv->ao_timer; if (cmd->stop_src == TRIG_COUNT) { /* not continuous */ /* counter */ /* high speed also scans everything at once */ - if (0) { /* (this_usbduxsub->high_speed) */ - this_usbduxsub->ao_sample_count = - (cmd->stop_arg) * (cmd->scan_end_arg); + if (0) { /* (devpriv->high_speed) */ + devpriv->ao_sample_count = cmd->stop_arg * + cmd->scan_end_arg; } else { /* there's no scan as the scan has been */ /* perf inside the FX2 */ /* data arrives as one packet */ - this_usbduxsub->ao_sample_count = cmd->stop_arg; + devpriv->ao_sample_count = cmd->stop_arg; } - this_usbduxsub->ao_continous = 0; } else { /* continous acquisition */ - this_usbduxsub->ao_continous = 1; - this_usbduxsub->ao_sample_count = 0; + devpriv->ao_sample_count = 0; } if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ - this_usbduxsub->ao_cmd_running = 1; - ret = usbduxsub_submit_outurbs(this_usbduxsub); + devpriv->ao_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); if (ret < 0) { - this_usbduxsub->ao_cmd_running = 0; + devpriv->ao_cmd_running = 0; /* fixme: unlink here?? */ - up(&this_usbduxsub->sem); - return ret; + goto ao_cmd_exit; } s->async->inttrig = NULL; } else { @@ -1553,149 +1089,121 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->inttrig = usbdux_ao_inttrig; } - up(&this_usbduxsub->sem); - return 0; +ao_cmd_exit: + up(&devpriv->sem); + + return ret; } static int usbdux_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + int ret; - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; /* 1 means Out */ - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - break; - default: - return -EINVAL; - break; - } - /* we don't tell the firmware here as it would take 8 frames */ - /* to submit the information. We do it in the insn_bits. */ + /* + * We don't tell the firmware here as it would take 8 frames + * to submit the information. We do it in the insn_bits. + */ return insn->n; } static int usbdux_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; - int err; + struct usbdux_private *devpriv = dev->private; + int ret; - if (!this_usbduxsub) - return -EFAULT; + down(&devpriv->sem); - down(&this_usbduxsub->sem); + comedi_dio_update_state(s, data); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + /* Always update the hardware. See the (*insn_config). */ + devpriv->dux_commands[1] = s->io_bits; + devpriv->dux_commands[2] = s->state; - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - this_usbduxsub->dux_commands[1] = s->io_bits; - this_usbduxsub->dux_commands[2] = s->state; - - /* This command also tells the firmware to return */ - /* the digital input lines */ - err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } - err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } + /* + * This command also tells the firmware to return + * the digital input lines. + */ + ret = send_dux_commands(dev, USBDUX_CMD_DIO_BITS); + if (ret < 0) + goto dio_exit; + ret = receive_dux_commands(dev, USBDUX_CMD_DIO_BITS); + if (ret < 0) + goto dio_exit; - data[1] = le16_to_cpu(this_usbduxsub->insn_buffer[1]); - up(&this_usbduxsub->sem); - return insn->n; + data[1] = le16_to_cpu(devpriv->insn_buf[1]); + +dio_exit: + up(&devpriv->sem); + + return ret ? ret : insn->n; } -/* reads the 4 counters, only two are used just now */ static int usbdux_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; - int chan = insn->chanspec; - int err; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret = 0; + int i; - down(&this_usbduxsub->sem); + down(&devpriv->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + for (i = 0; i < insn->n; i++) { + ret = send_dux_commands(dev, USBDUX_CMD_TIMER_RD); + if (ret < 0) + goto counter_read_exit; + ret = receive_dux_commands(dev, USBDUX_CMD_TIMER_RD); + if (ret < 0) + goto counter_read_exit; - err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; + data[i] = le16_to_cpu(devpriv->insn_buf[chan + 1]); } - err = receive_dux_commands(this_usbduxsub, READCOUNTERCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } +counter_read_exit: + up(&devpriv->sem); - data[0] = le16_to_cpu(this_usbduxsub->insn_buffer[chan + 1]); - up(&this_usbduxsub->sem); - return 1; + return ret ? ret : insn->n; } static int usbdux_counter_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; - int err; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + uint16_t *p = (uint16_t *)&devpriv->dux_commands[2]; + int ret = 0; + int i; - down(&this_usbduxsub->sem); + down(&devpriv->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + devpriv->dux_commands[1] = chan; - this_usbduxsub->dux_commands[1] = insn->chanspec; - *((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data); + for (i = 0; i < insn->n; i++) { + *p = cpu_to_le16(data[i]); - err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; + ret = send_dux_commands(dev, USBDUX_CMD_TIMER_WR); + if (ret < 0) + break; } - up(&this_usbduxsub->sem); + up(&devpriv->sem); - return 1; + return ret ? ret : insn->n; } static int usbdux_counter_config(struct comedi_device *dev, @@ -1706,73 +1214,43 @@ static int usbdux_counter_config(struct comedi_device *dev, return 2; } -/***********************************/ -/* PWM */ - -static int usbduxsub_unlink_pwm_urbs(struct usbduxsub *usbduxsub_tmp) +static void usbduxsub_unlink_pwm_urbs(struct comedi_device *dev) { - int err = 0; + struct usbdux_private *devpriv = dev->private; - if (usbduxsub_tmp && usbduxsub_tmp->urb_pwm) { - if (usbduxsub_tmp->urb_pwm) - usb_kill_urb(usbduxsub_tmp->urb_pwm); - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: unlinked PwmURB: res=%d\n", err); - } - return err; + usb_kill_urb(devpriv->pwm_urb); } -/* This cancels a running acquisition operation - * in any context. - */ -static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink) +static void usbdux_pwm_stop(struct comedi_device *dev, int do_unlink) { - int ret = 0; + struct usbdux_private *devpriv = dev->private; - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__); if (do_unlink) - ret = usbduxsub_unlink_pwm_urbs(this_usbduxsub); - - this_usbduxsub->pwm_cmd_running = 0; + usbduxsub_unlink_pwm_urbs(dev); - return ret; + devpriv->pwm_cmd_running = 0; } -/* force unlink - is called by comedi */ static int usbdux_pwm_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub = dev->private; - int res = 0; + struct usbdux_private *devpriv = dev->private; + int ret; + down(&devpriv->sem); /* unlink only if it is really running */ - res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running); + usbdux_pwm_stop(dev, devpriv->pwm_cmd_running); + ret = send_dux_commands(dev, USBDUX_CMD_PWM_OFF); + up(&devpriv->sem); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi %d: sending pwm off command to the usb device.\n", - dev->minor); - - return send_dux_commands(this_usbduxsub, SENDPWMOFF); + return ret; } static void usbduxsub_pwm_irq(struct urb *urb) { + struct comedi_device *dev = urb->context; + struct usbdux_private *devpriv = dev->private; int ret; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* printk(KERN_DEBUG "PWM: IRQ\n"); */ - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - - s = &this_comedidev->subdevices[SUBDEV_DA]; switch (urb->status) { case 0: @@ -1787,220 +1265,171 @@ static void usbduxsub_pwm_irq(struct urb *urb) * after an unlink command, unplug, ... etc * no unlink needed here. Already shutting down. */ - if (this_usbduxsub->pwm_cmd_running) - usbdux_pwm_stop(this_usbduxsub, 0); + if (devpriv->pwm_cmd_running) + usbdux_pwm_stop(dev, 0); return; default: /* a real error */ - if (this_usbduxsub->pwm_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi_: Non-zero urb status received in " - "pwm intr context: %d\n", urb->status); - usbdux_pwm_stop(this_usbduxsub, 0); + if (devpriv->pwm_cmd_running) { + dev_err(dev->class_dev, + "Non-zero urb status received in pwm intr context: %d\n", + urb->status); + usbdux_pwm_stop(dev, 0); } return; } /* are we actually running? */ - if (!(this_usbduxsub->pwm_cmd_running)) + if (!devpriv->pwm_cmd_running) return; - urb->transfer_buffer_length = this_usbduxsub->size_pwm_buf; - urb->dev = this_usbduxsub->usbdev; + urb->transfer_buffer_length = devpriv->pwm_buf_sz; + urb->dev = comedi_to_usb_dev(dev); urb->status = 0; - if (this_usbduxsub->pwm_cmd_running) { + if (devpriv->pwm_cmd_running) { ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi_: pwm urb resubm failed in int-cont. " - "ret=%d", ret); + dev_err(dev->class_dev, + "pwm urb resubm failed in int-cont. ret=%d", + ret); if (ret == EL2NSYNC) - dev_err(&this_usbduxsub->interface->dev, - "buggy USB host controller or bug in " - "IRQ handling!\n"); + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handling!\n"); /* don't do an unlink here */ - usbdux_pwm_stop(this_usbduxsub, 0); + usbdux_pwm_stop(dev, 0); } } } -static int usbduxsub_submit_pwm_urbs(struct usbduxsub *usbduxsub) +static int usbduxsub_submit_pwm_urbs(struct comedi_device *dev) { - int err_flag; - - if (!usbduxsub) - return -EFAULT; - - dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n"); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + struct urb *urb = devpriv->pwm_urb; /* in case of a resubmission after an unlink... */ - usb_fill_bulk_urb(usbduxsub->urb_pwm, - usbduxsub->usbdev, - usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP), - usbduxsub->urb_pwm->transfer_buffer, - usbduxsub->size_pwm_buf, usbduxsub_pwm_irq, - usbduxsub->comedidev); - - err_flag = usb_submit_urb(usbduxsub->urb_pwm, GFP_ATOMIC); - if (err_flag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: usbdux: pwm: usb_submit_urb error %d\n", - err_flag); - return err_flag; - } - return 0; + usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4), + urb->transfer_buffer, + devpriv->pwm_buf_sz, + usbduxsub_pwm_irq, + dev); + + return usb_submit_urb(urb, GFP_ATOMIC); } static int usbdux_pwm_period(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int period) + struct comedi_subdevice *s, + unsigned int period) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *devpriv = dev->private; int fx2delay = 255; if (period < MIN_PWM_PERIOD) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: illegal period setting for pwm.\n", - dev->minor); return -EAGAIN; } else { - fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6; - if (fx2delay > 255) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: period %d for pwm is too low.\n", - dev->minor, period); + fx2delay = (period / (6 * 512 * 1000 / 33)) - 6; + if (fx2delay > 255) return -EAGAIN; - } } - this_usbduxsub->pwn_delay = fx2delay; - this_usbduxsub->pwm_period = period; - dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n", - __func__, period, fx2delay); + devpriv->pwm_delay = fx2delay; + devpriv->pwm_period = period; + return 0; } -/* is called from insn so there's no need to do all the sanity checks */ static int usbdux_pwm_start(struct comedi_device *dev, struct comedi_subdevice *s) { - int ret, i; - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *devpriv = dev->private; + int ret = 0; - dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n", - dev->minor, __func__); + down(&devpriv->sem); - if (this_usbduxsub->pwm_cmd_running) { - /* already running */ - return 0; - } + if (devpriv->pwm_cmd_running) + goto pwm_start_exit; - this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwn_delay); - ret = send_dux_commands(this_usbduxsub, SENDPWMON); + devpriv->dux_commands[1] = devpriv->pwm_delay; + ret = send_dux_commands(dev, USBDUX_CMD_PWM_ON); if (ret < 0) - return ret; + goto pwm_start_exit; /* initialise the buffer */ - for (i = 0; i < this_usbduxsub->size_pwm_buf; i++) - ((char *)(this_usbduxsub->urb_pwm->transfer_buffer))[i] = 0; + memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz); - this_usbduxsub->pwm_cmd_running = 1; - ret = usbduxsub_submit_pwm_urbs(this_usbduxsub); - if (ret < 0) { - this_usbduxsub->pwm_cmd_running = 0; - return ret; - } - return 0; + devpriv->pwm_cmd_running = 1; + ret = usbduxsub_submit_pwm_urbs(dev); + if (ret < 0) + devpriv->pwm_cmd_running = 0; + +pwm_start_exit: + up(&devpriv->sem); + + return ret; } -/* generates the bit pattern for PWM with the optional sign bit */ -static int usbdux_pwm_pattern(struct comedi_device *dev, - struct comedi_subdevice *s, int channel, - unsigned int value, unsigned int sign) +static void usbdux_pwm_pattern(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int value, + unsigned int sign) { - struct usbduxsub *this_usbduxsub = dev->private; - int i, szbuf; - char *p_buf; - char pwm_mask; - char sgn_mask; - char c; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; + char pwm_mask = (1 << chan); /* DIO bit for the PWM data */ + char sgn_mask = (16 << chan); /* DIO bit for the sign */ + char *buf = (char *)(devpriv->pwm_urb->transfer_buffer); + int szbuf = devpriv->pwm_buf_sz; + int i; - /* this is the DIO bit which carries the PWM data */ - pwm_mask = (1 << channel); - /* this is the DIO bit which carries the optional direction bit */ - sgn_mask = (16 << channel); - /* this is the buffer which will be filled with the with bit */ - /* pattern for one period */ - szbuf = this_usbduxsub->size_pwm_buf; - p_buf = (char *)(this_usbduxsub->urb_pwm->transfer_buffer); for (i = 0; i < szbuf; i++) { - c = *p_buf; - /* reset bits */ - c = c & (~pwm_mask); - /* set the bit as long as the index is lower than the value */ + char c = *buf; + + c &= ~pwm_mask; if (i < value) - c = c | pwm_mask; - /* set the optional sign bit for a relay */ - if (!sign) { - /* positive value */ - c = c & (~sgn_mask); - } else { - /* negative value */ - c = c | sgn_mask; - } - *(p_buf++) = c; + c |= pwm_mask; + if (!sign) + c &= ~sgn_mask; + else + c |= sgn_mask; + *buf++ = c; } - return 1; } static int usbdux_pwm_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); - if (!this_usbduxsub) - return -EFAULT; - - if ((insn->n) != 1) { - /* - * doesn't make sense to have more than one value here because - * it would just overwrite the PWM buffer a couple of times - */ + /* + * It doesn't make sense to support more than one value here + * because it would just overwrite the PWM buffer. + */ + if (insn->n != 1) return -EINVAL; - } /* - * the sign is set via a special INSN only, this gives us 8 bits for - * normal operation - * relay sign 0 by default + * The sign is set via a special INSN only, this gives us 8 bits + * for normal operation, sign is 0 by default. */ - return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0); -} + usbdux_pwm_pattern(dev, s, chan, data[0], 0); -static int usbdux_pwm_read(struct comedi_device *x1, - struct comedi_subdevice *x2, struct comedi_insn *x3, - unsigned int *x4) -{ - /* not needed */ - return -EINVAL; -}; + return insn->n; +} -/* switches on/off PWM */ static int usbdux_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + switch (data[0]) { case INSN_CONFIG_ARM: - /* switch it on */ - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: pwm on\n", dev->minor, __func__); /* * if not zero the PWM is limited to a certain time which is * not supported here @@ -2009,33 +1438,22 @@ static int usbdux_pwm_config(struct comedi_device *dev, return -EINVAL; return usbdux_pwm_start(dev, s); case INSN_CONFIG_DISARM: - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: pwm off\n", dev->minor, __func__); return usbdux_pwm_cancel(dev, s); case INSN_CONFIG_GET_PWM_STATUS: - /* - * to check if the USB transmission has failed or in case PWM - * was limited to n cycles to check if it has terminated - */ - data[1] = this_usbduxsub->pwm_cmd_running; + data[1] = devpriv->pwm_cmd_running; return 0; case INSN_CONFIG_PWM_SET_PERIOD: - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: setting period\n", dev->minor, __func__); return usbdux_pwm_period(dev, s, data[1]); case INSN_CONFIG_PWM_GET_PERIOD: - data[1] = this_usbduxsub->pwm_period; + data[1] = devpriv->pwm_period; return 0; case INSN_CONFIG_PWM_SET_H_BRIDGE: - /* value in the first byte and the sign in the second for a - relay */ - return usbdux_pwm_pattern(dev, s, - /* the channel number */ - CR_CHAN(insn->chanspec), - /* actual PWM data */ - data[1], - /* just a sign */ - (data[2] != 0)); + /* + * data[1] = value + * data[2] = sign (for a relay) + */ + usbdux_pwm_pattern(dev, s, chan, data[1], (data[2] != 0)); + return 0; case INSN_CONFIG_PWM_GET_H_BRIDGE: /* values are not kept in this driver, nothing to return here */ return -EINVAL; @@ -2043,253 +1461,331 @@ static int usbdux_pwm_config(struct comedi_device *dev, return -EINVAL; } -/* end of PWM */ -/*****************************************************************/ - -static void tidy_up(struct usbduxsub *usbduxsub_tmp) +static int usbdux_firmware_upload(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { - int i; + struct usb_device *usb = comedi_to_usb_dev(dev); + uint8_t *buf; + uint8_t *tmp; + int ret; - if (!usbduxsub_tmp) - return; - dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n"); + if (!data) + return 0; - /* shows the usb subsystem that the driver is down */ - if (usbduxsub_tmp->interface) - usb_set_intfdata(usbduxsub_tmp->interface, NULL); + if (size > USBDUX_FIRMWARE_MAX_LEN) { + dev_err(dev->class_dev, + "usbdux firmware binary it too large for FX2.\n"); + return -ENOMEM; + } - usbduxsub_tmp->probed = 0; + /* we generate a local buffer for the firmware */ + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (usbduxsub_tmp->urb_in) { - if (usbduxsub_tmp->ai_cmd_running) { - usbduxsub_tmp->ai_cmd_running = 0; - usbduxsub_unlink_inurbs(usbduxsub_tmp); - } - for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) { - kfree(usbduxsub_tmp->urb_in[i]->transfer_buffer); - usbduxsub_tmp->urb_in[i]->transfer_buffer = NULL; - usb_kill_urb(usbduxsub_tmp->urb_in[i]); - usb_free_urb(usbduxsub_tmp->urb_in[i]); - usbduxsub_tmp->urb_in[i] = NULL; - } - kfree(usbduxsub_tmp->urb_in); - usbduxsub_tmp->urb_in = NULL; + /* we need a malloc'ed buffer for usb_control_msg() */ + tmp = kmalloc(1, GFP_KERNEL); + if (!tmp) { + kfree(buf); + return -ENOMEM; } - if (usbduxsub_tmp->urb_out) { - if (usbduxsub_tmp->ao_cmd_running) { - usbduxsub_tmp->ao_cmd_running = 0; - usbduxsub_unlink_outurbs(usbduxsub_tmp); - } - for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) { - kfree(usbduxsub_tmp->urb_out[i]->transfer_buffer); - usbduxsub_tmp->urb_out[i]->transfer_buffer = NULL; - if (usbduxsub_tmp->urb_out[i]) { - usb_kill_urb(usbduxsub_tmp->urb_out[i]); - usb_free_urb(usbduxsub_tmp->urb_out[i]); - usbduxsub_tmp->urb_out[i] = NULL; - } - } - kfree(usbduxsub_tmp->urb_out); - usbduxsub_tmp->urb_out = NULL; + + /* stop the current firmware on the device */ + *tmp = 1; /* 7f92 to one */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUX_FIRMWARE_CMD, + VENDOR_DIR_OUT, + USBDUX_CPU_CS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "can not stop firmware\n"); + goto done; } - if (usbduxsub_tmp->urb_pwm) { - if (usbduxsub_tmp->pwm_cmd_running) { - usbduxsub_tmp->pwm_cmd_running = 0; - usbduxsub_unlink_pwm_urbs(usbduxsub_tmp); - } - kfree(usbduxsub_tmp->urb_pwm->transfer_buffer); - usbduxsub_tmp->urb_pwm->transfer_buffer = NULL; - usb_kill_urb(usbduxsub_tmp->urb_pwm); - usb_free_urb(usbduxsub_tmp->urb_pwm); - usbduxsub_tmp->urb_pwm = NULL; + + /* upload the new firmware to the device */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUX_FIRMWARE_CMD, + VENDOR_DIR_OUT, + 0, 0x0000, + buf, size, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "firmware upload failed\n"); + goto done; } - kfree(usbduxsub_tmp->in_buffer); - usbduxsub_tmp->in_buffer = NULL; - kfree(usbduxsub_tmp->insn_buffer); - usbduxsub_tmp->insn_buffer = NULL; - kfree(usbduxsub_tmp->out_buffer); - usbduxsub_tmp->out_buffer = NULL; - kfree(usbduxsub_tmp->dac_commands); - usbduxsub_tmp->dac_commands = NULL; - kfree(usbduxsub_tmp->dux_commands); - usbduxsub_tmp->dux_commands = NULL; - usbduxsub_tmp->ai_cmd_running = 0; - usbduxsub_tmp->ao_cmd_running = 0; - usbduxsub_tmp->pwm_cmd_running = 0; + + /* start the new firmware on the device */ + *tmp = 0; /* 7f92 to zero */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUX_FIRMWARE_CMD, + VENDOR_DIR_OUT, + USBDUX_CPU_CS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) + dev_err(dev->class_dev, "can not start firmware\n"); + +done: + kfree(tmp); + kfree(buf); + return ret; } -static int usbdux_attach_common(struct comedi_device *dev, - struct usbduxsub *udev) +static int usbdux_alloc_usb_buffers(struct comedi_device *dev) { - int ret; - struct comedi_subdevice *s = NULL; - int n_subdevs; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + struct urb *urb; + int i; - down(&udev->sem); - /* pointer back to the corresponding comedi device */ - udev->comedidev = dev; + devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); + devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL); + devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL); + devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(void *), + GFP_KERNEL); + devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(void *), + GFP_KERNEL); + if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf || + !devpriv->ai_urbs || !devpriv->ao_urbs) + return -ENOMEM; - /* set number of subdevices */ - if (udev->high_speed) { - /* with pwm */ - n_subdevs = 5; - } else { - /* without pwm */ - n_subdevs = 4; - } + for (i = 0; i < devpriv->n_ai_urbs; i++) { + /* one frame: 1ms */ + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) + return -ENOMEM; + devpriv->ai_urbs[i] = urb; + + urb->dev = usb; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(usb, 6); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); + if (!urb->transfer_buffer) + return -ENOMEM; - ret = comedi_alloc_subdevices(dev, n_subdevs); - if (ret) { - up(&udev->sem); - return ret; + urb->complete = usbduxsub_ai_isoc_irq; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEINBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEINBUF; } - /* private structure is also simply the usb-structure */ - dev->private = udev; + for (i = 0; i < devpriv->n_ao_urbs; i++) { + /* one frame: 1ms */ + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) + return -ENOMEM; + devpriv->ao_urbs[i] = urb; + + urb->dev = usb; + urb->context = dev; + urb->pipe = usb_sndisocpipe(usb, 2); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); + if (!urb->transfer_buffer) + return -ENOMEM; - /* the first subdevice is the A/D converter */ - s = &dev->subdevices[SUBDEV_AD]; - /* the URBs get the comedi subdevice */ - /* which is responsible for reading */ - /* this is the subdevice which reads data */ - dev->read_subdev = s; - /* the subdevice receives as private structure the */ - /* usb-structure */ - s->private = NULL; - /* analog input */ - s->type = COMEDI_SUBD_AI; - /* readable and ref is to ground */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - /* 8 channels */ - s->n_chan = 8; - /* length of the channellist */ - s->len_chanlist = 8; - /* callback functions */ - s->insn_read = usbdux_ai_insn_read; - s->do_cmdtest = usbdux_ai_cmdtest; - s->do_cmd = usbdux_ai_cmd; - s->cancel = usbdux_ai_cancel; - /* max value from the A/D converter (12bit) */ - s->maxdata = 0xfff; - /* range table to convert to physical units */ - s->range_table = (&range_usbdux_ai_range); - - /* analog out */ - s = &dev->subdevices[SUBDEV_DA]; - /* analog out */ - s->type = COMEDI_SUBD_AO; - /* backward pointer */ - dev->write_subdev = s; - /* the subdevice receives as private structure the */ - /* usb-structure */ - s->private = NULL; - /* are writable */ - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; - /* 4 channels */ - s->n_chan = 4; - /* length of the channellist */ - s->len_chanlist = 4; - /* 12 bit resolution */ - s->maxdata = 0x0fff; - /* bipolar range */ - s->range_table = (&range_usbdux_ao_range); - /* callback */ - s->do_cmdtest = usbdux_ao_cmdtest; - s->do_cmd = usbdux_ao_cmd; - s->cancel = usbdux_ao_cancel; - s->insn_read = usbdux_ao_insn_read; - s->insn_write = usbdux_ao_insn_write; - - /* digital I/O */ - s = &dev->subdevices[SUBDEV_DIO]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = (&range_digital); - s->insn_bits = usbdux_dio_insn_bits; - s->insn_config = usbdux_dio_insn_config; - /* we don't use it */ - s->private = NULL; - - /* counter */ - s = &dev->subdevices[SUBDEV_COUNTER]; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 4; - s->maxdata = 0xFFFF; - s->insn_read = usbdux_counter_read; - s->insn_write = usbdux_counter_write; - s->insn_config = usbdux_counter_config; - - if (udev->high_speed) { - /* timer / pwm */ - s = &dev->subdevices[SUBDEV_PWM]; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; - s->n_chan = 8; - /* this defines the max duty cycle resolution */ - s->maxdata = udev->size_pwm_buf; - s->insn_write = usbdux_pwm_write; - s->insn_read = usbdux_pwm_read; - s->insn_config = usbdux_pwm_config; - usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD); + urb->complete = usbduxsub_ao_isoc_irq; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEOUTBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEOUTBUF; + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ } - /* finally decide that it's attached */ - udev->attached = 1; - up(&udev->sem); + /* pwm */ + if (devpriv->pwm_buf_sz) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + devpriv->pwm_urb = urb; - dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n", - dev->minor); + /* max bulk ep size in high speed */ + urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, + GFP_KERNEL); + if (!urb->transfer_buffer) + return -ENOMEM; + } return 0; } +static void usbdux_free_usb_buffers(struct comedi_device *dev) +{ + struct usbdux_private *devpriv = dev->private; + struct urb *urb; + int i; + + urb = devpriv->pwm_urb; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + if (devpriv->ao_urbs) { + for (i = 0; i < devpriv->n_ao_urbs; i++) { + urb = devpriv->ao_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ao_urbs); + } + if (devpriv->ai_urbs) { + for (i = 0; i < devpriv->n_ai_urbs; i++) { + urb = devpriv->ai_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ai_urbs); + } + kfree(devpriv->insn_buf); + kfree(devpriv->in_buf); + kfree(devpriv->dux_commands); +} + static int usbdux_auto_attach(struct comedi_device *dev, unsigned long context_unused) { - struct usb_interface *uinterf = comedi_to_usb_interface(dev); - struct usbduxsub *this_usbduxsub = usb_get_intfdata(uinterf); - struct usb_device *usb = usbduxsub->usbdev; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv; + struct comedi_subdevice *s; int ret; - dev->private = this_usbduxsub; /* This is temporary... */ - ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, - usbdux_firmware_upload, 0); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + sema_init(&devpriv->sem, 1); + + usb_set_intfdata(intf, devpriv); + + devpriv->high_speed = (usb->speed == USB_SPEED_HIGH); + if (devpriv->high_speed) { + devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH; + devpriv->pwm_buf_sz = 512; + } else { + devpriv->n_ai_urbs = NUMOFINBUFFERSFULL; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL; + } + + ret = usbdux_alloc_usb_buffers(dev); + if (ret) + return ret; + + /* setting to alternate setting 3: enabling iso ep and bulk ep. */ + ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber, + 3); if (ret < 0) { - dev->private = NULL; + dev_err(dev->class_dev, + "could not set alternate setting 3 in high speed\n"); return ret; } - dev->private = NULL; + ret = comedi_load_firmware(dev, &usb->dev, USBDUX_FIRMWARE, + usbdux_firmware_upload, 0); + if (ret < 0) + return ret; + + ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 5 : 4); + if (ret) + return ret; - down(&start_stop_sem); - if (!this_usbduxsub || !this_usbduxsub->probed) { - dev_err(dev->class_dev, - "usbdux: error: auto_attach failed, not connected\n"); - ret = -ENODEV; - } else if (this_usbduxsub->attached) { - dev_err(dev->class_dev, - "error: auto_attach failed, already attached\n"); - ret = -ENODEV; - } else - ret = usbdux_attach_common(dev, this_usbduxsub); - up(&start_stop_sem); - return ret; + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->len_chanlist = 8; + s->range_table = &range_usbdux_ai_range; + s->insn_read = usbdux_ai_insn_read; + s->do_cmdtest = usbdux_ai_cmdtest; + s->do_cmd = usbdux_ai_cmd; + s->cancel = usbdux_ai_cancel; + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + dev->write_subdev = s; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; + s->n_chan = USBDUX_NUM_AO_CHAN; + s->maxdata = 0x0fff; + s->len_chanlist = s->n_chan; + s->range_table = &range_usbdux_ao_range; + s->do_cmdtest = usbdux_ao_cmdtest; + s->do_cmd = usbdux_ao_cmd; + s->cancel = usbdux_ao_cancel; + s->insn_read = usbdux_ao_insn_read; + s->insn_write = usbdux_ao_insn_write; + + /* Digital I/O subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = usbdux_dio_insn_bits; + s->insn_config = usbdux_dio_insn_config; + + /* Counter subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->insn_read = usbdux_counter_read; + s->insn_write = usbdux_counter_write; + s->insn_config = usbdux_counter_config; + + if (devpriv->high_speed) { + /* PWM subdevice */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; + s->n_chan = 8; + s->maxdata = devpriv->pwm_buf_sz; + s->insn_write = usbdux_pwm_write; + s->insn_config = usbdux_pwm_config; + + usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD); + } + + return 0; } static void usbdux_detach(struct comedi_device *dev) { - struct usbduxsub *usb = dev->private; - - if (usb) { - down(&usb->sem); - dev->private = NULL; - usb->attached = 0; - usb->comedidev = NULL; - up(&usb->sem); - } + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usbdux_private *devpriv = dev->private; + + usb_set_intfdata(intf, NULL); + + if (!devpriv) + return; + + down(&devpriv->sem); + + /* force unlink all urbs */ + usbdux_pwm_stop(dev, 1); + usbdux_ao_stop(dev, 1); + usbdux_ai_stop(dev, 1); + + usbdux_free_usb_buffers(dev); + + up(&devpriv->sem); } static struct comedi_driver usbdux_driver = { @@ -2299,253 +1795,10 @@ static struct comedi_driver usbdux_driver = { .detach = usbdux_detach, }; -static int usbdux_usb_probe(struct usb_interface *uinterf, +static int usbdux_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(uinterf); - struct device *dev = &uinterf->dev; - int i; - int index; - - dev_dbg(dev, "comedi_: usbdux_: " - "finding a free structure for the usb-device\n"); - - down(&start_stop_sem); - /* look for a free place in the usbdux array */ - index = -1; - for (i = 0; i < NUMUSBDUX; i++) { - if (!(usbduxsub[i].probed)) { - index = i; - break; - } - } - - /* no more space */ - if (index == -1) { - dev_err(dev, "Too many usbdux-devices connected.\n"); - up(&start_stop_sem); - return -EMFILE; - } - dev_dbg(dev, "comedi_: usbdux: " - "usbduxsub[%d] is ready to connect to comedi.\n", index); - - sema_init(&(usbduxsub[index].sem), 1); - /* save a pointer to the usb device */ - usbduxsub[index].usbdev = udev; - - /* 2.6: save the interface itself */ - usbduxsub[index].interface = uinterf; - /* get the interface number from the interface */ - usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber; - /* hand the private data over to the usb subsystem */ - /* will be needed for disconnect */ - usb_set_intfdata(uinterf, &(usbduxsub[index])); - - dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum); - - /* test if it is high speed (USB 2.0) */ - usbduxsub[index].high_speed = - (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH); - - /* create space for the commands of the DA converter */ - usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); - if (!usbduxsub[index].dac_commands) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the commands going to the usb device */ - usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); - if (!usbduxsub[index].dux_commands) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the in buffer and set it to zero */ - usbduxsub[index].in_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); - if (!(usbduxsub[index].in_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space of the instruction buffer */ - usbduxsub[index].insn_buffer = kzalloc(SIZEINSNBUF, GFP_KERNEL); - if (!(usbduxsub[index].insn_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the outbuffer */ - usbduxsub[index].out_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); - if (!(usbduxsub[index].out_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* setting to alternate setting 3: enabling iso ep and bulk ep. */ - i = usb_set_interface(usbduxsub[index].usbdev, - usbduxsub[index].ifnum, 3); - if (i < 0) { - dev_err(dev, "comedi_: usbdux%d: " - "could not set alternate setting 3 in high speed.\n", - index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENODEV; - } - if (usbduxsub[index].high_speed) - usbduxsub[index].num_in_buffers = NUMOFINBUFFERSHIGH; - else - usbduxsub[index].num_in_buffers = NUMOFINBUFFERSFULL; - - usbduxsub[index].urb_in = - kcalloc(usbduxsub[index].num_in_buffers, sizeof(struct urb *), - GFP_KERNEL); - if (!(usbduxsub[index].urb_in)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - for (i = 0; i < usbduxsub[index].num_in_buffers; i++) { - /* one frame: 1ms */ - usbduxsub[index].urb_in[i] = usb_alloc_urb(1, GFP_KERNEL); - if (usbduxsub[index].urb_in[i] == NULL) { - dev_err(dev, "comedi_: usbdux%d: " - "Could not alloc. urb(%d)\n", index, i); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - usbduxsub[index].urb_in[i]->dev = usbduxsub[index].usbdev; - /* will be filled later with a pointer to the comedi-device */ - /* and ONLY then the urb should be submitted */ - usbduxsub[index].urb_in[i]->context = NULL; - usbduxsub[index].urb_in[i]->pipe = - usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP); - usbduxsub[index].urb_in[i]->transfer_flags = URB_ISO_ASAP; - usbduxsub[index].urb_in[i]->transfer_buffer = - kzalloc(SIZEINBUF, GFP_KERNEL); - if (!(usbduxsub[index].urb_in[i]->transfer_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - usbduxsub[index].urb_in[i]->complete = usbduxsub_ai_isoc_irq; - usbduxsub[index].urb_in[i]->number_of_packets = 1; - usbduxsub[index].urb_in[i]->transfer_buffer_length = SIZEINBUF; - usbduxsub[index].urb_in[i]->iso_frame_desc[0].offset = 0; - usbduxsub[index].urb_in[i]->iso_frame_desc[0].length = SIZEINBUF; - } - - /* out */ - if (usbduxsub[index].high_speed) - usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSHIGH; - else - usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSFULL; - - usbduxsub[index].urb_out = - kcalloc(usbduxsub[index].num_out_buffers, sizeof(struct urb *), - GFP_KERNEL); - if (!(usbduxsub[index].urb_out)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - for (i = 0; i < usbduxsub[index].num_out_buffers; i++) { - /* one frame: 1ms */ - usbduxsub[index].urb_out[i] = usb_alloc_urb(1, GFP_KERNEL); - if (usbduxsub[index].urb_out[i] == NULL) { - dev_err(dev, "comedi_: usbdux%d: " - "Could not alloc. urb(%d)\n", index, i); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - usbduxsub[index].urb_out[i]->dev = usbduxsub[index].usbdev; - /* will be filled later with a pointer to the comedi-device */ - /* and ONLY then the urb should be submitted */ - usbduxsub[index].urb_out[i]->context = NULL; - usbduxsub[index].urb_out[i]->pipe = - usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP); - usbduxsub[index].urb_out[i]->transfer_flags = URB_ISO_ASAP; - usbduxsub[index].urb_out[i]->transfer_buffer = - kzalloc(SIZEOUTBUF, GFP_KERNEL); - if (!(usbduxsub[index].urb_out[i]->transfer_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - usbduxsub[index].urb_out[i]->complete = usbduxsub_ao_isoc_irq; - usbduxsub[index].urb_out[i]->number_of_packets = 1; - usbduxsub[index].urb_out[i]->transfer_buffer_length = SIZEOUTBUF; - usbduxsub[index].urb_out[i]->iso_frame_desc[0].offset = 0; - usbduxsub[index].urb_out[i]->iso_frame_desc[0].length = - SIZEOUTBUF; - if (usbduxsub[index].high_speed) { - /* uframes */ - usbduxsub[index].urb_out[i]->interval = 8; - } else { - /* frames */ - usbduxsub[index].urb_out[i]->interval = 1; - } - } - - /* pwm */ - if (usbduxsub[index].high_speed) { - /* max bulk ep size in high speed */ - usbduxsub[index].size_pwm_buf = 512; - usbduxsub[index].urb_pwm = usb_alloc_urb(0, GFP_KERNEL); - if (usbduxsub[index].urb_pwm == NULL) { - dev_err(dev, "comedi_: usbdux%d: " - "Could not alloc. pwm urb\n", index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - usbduxsub[index].urb_pwm->transfer_buffer = - kzalloc(usbduxsub[index].size_pwm_buf, GFP_KERNEL); - if (!(usbduxsub[index].urb_pwm->transfer_buffer)) { - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - } else { - usbduxsub[index].urb_pwm = NULL; - usbduxsub[index].size_pwm_buf = 0; - } - - usbduxsub[index].ai_cmd_running = 0; - usbduxsub[index].ao_cmd_running = 0; - usbduxsub[index].pwm_cmd_running = 0; - - /* we've reached the bottom of the function */ - usbduxsub[index].probed = 1; - up(&start_stop_sem); - - return comedi_usb_auto_config(uinterf, &usbdux_driver, 0); -} - -static void usbdux_usb_disconnect(struct usb_interface *intf) -{ - struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf); - struct usb_device *udev = interface_to_usbdev(intf); - - if (!usbduxsub_tmp) { - dev_err(&intf->dev, - "comedi_: disconnect called with null pointer.\n"); - return; - } - if (usbduxsub_tmp->usbdev != udev) { - dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n"); - return; - } - comedi_usb_auto_unconfig(intf); - down(&start_stop_sem); - down(&usbduxsub_tmp->sem); - tidy_up(usbduxsub_tmp); - up(&usbduxsub_tmp->sem); - up(&start_stop_sem); - dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n"); + return comedi_usb_auto_config(intf, &usbdux_driver, 0); } static const struct usb_device_id usbdux_usb_table[] = { @@ -2553,13 +1806,12 @@ static const struct usb_device_id usbdux_usb_table[] = { { USB_DEVICE(0x13d8, 0x0002) }, { } }; - MODULE_DEVICE_TABLE(usb, usbdux_usb_table); static struct usb_driver usbdux_usb_driver = { .name = "usbdux", .probe = usbdux_usb_probe, - .disconnect = usbdux_usb_disconnect, + .disconnect = comedi_usb_auto_unconfig, .id_table = usbdux_usb_table, }; module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver); @@ -2567,4 +1819,4 @@ module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver); MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com"); MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"); MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FIRMWARE); +MODULE_FIRMWARE(USBDUX_FIRMWARE); diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 27898c44e54..85f9dcf5940 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -37,7 +37,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/usb.h> @@ -138,7 +137,10 @@ * comedi constants */ static const struct comedi_lrange range_usbduxfast_ai_range = { - 2, {BIP_RANGE(0.75), BIP_RANGE(0.5)} + 2, { + BIP_RANGE(0.75), + BIP_RANGE(0.5) + } }; /* @@ -152,7 +154,6 @@ struct usbduxfast_private { uint8_t *duxbuf; int8_t *inbuf; short int ai_cmd_running; /* asynchronous command is running */ - short int ai_continous; /* continous acquisition */ long int ai_sample_count; /* number of samples to acquire */ int ignore; /* counter which ignores the first buffers */ @@ -237,6 +238,7 @@ static void usbduxfast_ai_interrupt(struct urb *urb) struct comedi_device *dev = urb->context; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; struct usb_device *usb = comedi_to_usb_dev(dev); struct usbduxfast_private *devpriv = dev->private; int n, err; @@ -283,7 +285,7 @@ static void usbduxfast_ai_interrupt(struct urb *urb) } if (!devpriv->ignore) { - if (!devpriv->ai_continous) { + if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ n = urb->actual_length / sizeof(uint16_t); if (unlikely(devpriv->ai_sample_count < n)) { @@ -370,7 +372,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT | TRIG_INT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + TRIG_FOLLOW | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -396,8 +398,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_NOW) - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (!cmd->chanlist_len) err |= -EINVAL; @@ -422,9 +423,6 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, tmp); } - if (cmd->scan_begin_src == TRIG_TIMER) - err |= -EINVAL; - /* stop source */ switch (cmd->stop_src) { case TRIG_COUNT: @@ -452,21 +450,20 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, static int usbduxfast_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbduxfast_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; if (!devpriv) return -EFAULT; + if (trig_num != cmd->start_arg) + return -EINVAL; + down(&devpriv->sem); - if (trignum != 0) { - dev_err(dev->class_dev, "invalid trignum\n"); - up(&devpriv->sem); - return -EINVAL; - } if (!devpriv->ai_cmd_running) { devpriv->ai_cmd_running = 1; ret = usbduxfast_submit_urb(dev); @@ -512,36 +509,28 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ devpriv->ignore = PACKETS_TO_IGNORE; - if (cmd->chanlist_len > 0) { - gain = CR_RANGE(cmd->chanlist[0]); - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - if (chan != i) { - dev_err(dev->class_dev, - "channels are not consecutive\n"); - up(&devpriv->sem); - return -EINVAL; - } - if ((gain != CR_RANGE(cmd->chanlist[i])) - && (cmd->chanlist_len > 3)) { - dev_err(dev->class_dev, - "gain must be the same for all channels\n"); - up(&devpriv->sem); - return -EINVAL; - } - if (i >= NUMCHANNELS) { - dev_err(dev->class_dev, "chanlist too long\n"); - break; - } + gain = CR_RANGE(cmd->chanlist[0]); + for (i = 0; i < cmd->chanlist_len; ++i) { + chan = CR_CHAN(cmd->chanlist[i]); + if (chan != i) { + dev_err(dev->class_dev, + "channels are not consecutive\n"); + up(&devpriv->sem); + return -EINVAL; + } + if ((gain != CR_RANGE(cmd->chanlist[i])) + && (cmd->chanlist_len > 3)) { + dev_err(dev->class_dev, + "gain must be the same for all channels\n"); + up(&devpriv->sem); + return -EINVAL; + } + if (i >= NUMCHANNELS) { + dev_err(dev->class_dev, "chanlist too long\n"); + break; } } steps = 0; - if (cmd->scan_begin_src == TRIG_TIMER) { - dev_err(dev->class_dev, - "scan_begin_src==TRIG_TIMER not valid\n"); - up(&devpriv->sem); - return -EINVAL; - } if (cmd->convert_src == TRIG_TIMER) steps = (cmd->convert_arg * 30) / 1000; @@ -820,20 +809,11 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, up(&devpriv->sem); return result; } - if (cmd->stop_src == TRIG_COUNT) { + + if (cmd->stop_src == TRIG_COUNT) devpriv->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg; - if (devpriv->ai_sample_count < 1) { - dev_err(dev->class_dev, - "(cmd->stop_arg)*(cmd->scan_end_arg)<1, aborting\n"); - up(&devpriv->sem); - return -EFAULT; - } - devpriv->ai_continous = 0; - } else { - /* continous acquisition */ - devpriv->ai_continous = 1; + else /* TRIG_NONE */ devpriv->ai_sample_count = 0; - } if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) { /* enable this acquisition operation */ @@ -846,12 +826,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, return ret; } s->async->inttrig = NULL; - } else { - /* - * TRIG_INT - * don't enable the acquision operation - * wait for an internal signal - */ + } else { /* TRIG_INT */ s->async->inttrig = usbduxfast_ai_inttrig; } up(&devpriv->sem); @@ -1061,10 +1036,9 @@ static int usbduxfast_auto_attach(struct comedi_device *dev, return -ENODEV; } - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; sema_init(&devpriv->sem, 1); usb_set_intfdata(intf, devpriv); diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 898c3c45040..ccc3ef7ba55 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -43,12 +43,12 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> +#include <asm/unaligned.h> #include "comedi_fc.h" #include "../comedidev.h" @@ -66,13 +66,6 @@ /* internal addresses of the 8051 processor */ #define USBDUXSUB_CPUCS 0xE600 -/* USB endpoints */ -#define USBDUXSIGMA_CMD_OUT_EP 1 /* command output */ -#define USBDUXSIGMA_ISO_OUT_EP 2 /* analog output ISO/IRQ */ -#define USBDUXSIGMA_PWM_OUT_EP 4 /* pwm output */ -#define USBDUXSIGMA_ISO_IN_EP 6 /* analog input ISO/IRQ */ -#define USBDUXSIGMA_CMD_IN_EP 8 /* command input */ - /* 300Hz max frequ under PWM */ #define MIN_PWM_PERIOD ((long)(1E9/300)) @@ -85,7 +78,7 @@ #define USBDUXSIGMA_NUM_AO_CHAN 4 /* Size of one A/D value */ -#define SIZEADIN ((sizeof(int32_t))) +#define SIZEADIN ((sizeof(uint32_t))) /* * Size of the async input-buffer IN BYTES, the DIO state is transmitted @@ -100,7 +93,7 @@ #define NUMOUTCHANNELS 8 /* size of one value for the D/A converter: channel and value */ -#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(int16_t))) +#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) /* * Size of the output-buffer in bytes @@ -164,17 +157,15 @@ struct usbduxsigma_private { /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */ - int32_t *in_buf; + uint32_t *in_buf; /* input buffer for single insn */ - int8_t *insn_buf; + uint8_t *insn_buf; unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN]; unsigned high_speed:1; unsigned ai_cmd_running:1; - unsigned ai_continuous:1; unsigned ao_cmd_running:1; - unsigned ao_continuous:1; unsigned pwm_cmd_running:1; /* number of samples to acquire */ @@ -188,25 +179,25 @@ struct usbduxsigma_private { unsigned int ao_counter; /* interval in frames/uframes */ unsigned int ai_interval; - /* D/A commands */ - uint8_t *dac_commands; /* commands */ uint8_t *dux_commands; struct semaphore sem; }; +static void usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs) +{ + int i; + + for (i = 0; i < num_urbs; i++) + usb_kill_urb(urbs[i]); +} + static void usbduxsigma_ai_stop(struct comedi_device *dev, int do_unlink) { struct usbduxsigma_private *devpriv = dev->private; - if (do_unlink) { - int i; - - for (i = 0; i < devpriv->n_ai_urbs; i++) { - if (devpriv->ai_urbs[i]) - usb_kill_urb(devpriv->ai_urbs[i]); - } - } + if (do_unlink && devpriv->ai_urbs) + usbduxsigma_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs); devpriv->ai_cmd_running = 0; } @@ -229,8 +220,9 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb) struct comedi_device *dev = urb->context; struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int dio_state; - int32_t val; + uint32_t val; int ret; int i; @@ -307,7 +299,7 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb) /* timer zero, transfer measurements to comedi */ devpriv->ai_counter = devpriv->ai_timer; - if (!devpriv->ai_continuous) { + if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ devpriv->ai_sample_count--; if (devpriv->ai_sample_count < 0) { @@ -320,7 +312,7 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb) } /* get the data from the USB bus and hand it over to comedi */ - for (i = 0; i < s->async->cmd.chanlist_len; i++) { + for (i = 0; i < cmd->chanlist_len; i++) { /* transfer data, note first byte is the DIO state */ val = be32_to_cpu(devpriv->in_buf[i+1]); val &= 0x00ffffff; /* strip status byte */ @@ -342,14 +334,8 @@ static void usbduxsigma_ao_stop(struct comedi_device *dev, int do_unlink) { struct usbduxsigma_private *devpriv = dev->private; - if (do_unlink) { - int i; - - for (i = 0; i < devpriv->n_ao_urbs; i++) { - if (devpriv->ao_urbs[i]) - usb_kill_urb(devpriv->ao_urbs[i]); - } - } + if (do_unlink && devpriv->ao_urbs) + usbduxsigma_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs); devpriv->ao_cmd_running = 0; } @@ -372,8 +358,8 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb) struct comedi_device *dev = urb->context; struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s = dev->write_subdev; + struct comedi_cmd *cmd = &s->async->cmd; uint8_t *datap; - int len; int ret; int i; @@ -415,7 +401,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb) /* timer zero, transfer from comedi */ devpriv->ao_counter = devpriv->ao_timer; - if (!devpriv->ao_continuous) { + if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ devpriv->ao_sample_count--; if (devpriv->ao_sample_count < 0) { @@ -429,13 +415,12 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb) /* transmit data to the USB bus */ datap = urb->transfer_buffer; - len = s->async->cmd.chanlist_len; - *datap++ = len; - for (i = 0; i < len; i++) { - unsigned int chan = devpriv->dac_commands[i]; - short val; + *datap++ = cmd->chanlist_len; + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned short val; - ret = comedi_buf_get(s->async, &val); + ret = comedi_buf_get(s, &val); if (ret < 0) { dev_err(dev->class_dev, "buffer underflow\n"); s->async->events |= (COMEDI_CB_EOA | @@ -608,10 +593,8 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, if (cmd->stop_src == TRIG_COUNT) { /* data arrives as one packet */ devpriv->ai_sample_count = cmd->stop_arg; - devpriv->ai_continuous = 0; } else { /* continuous acquisition */ - devpriv->ai_continuous = 1; devpriv->ai_sample_count = 0; } @@ -643,7 +626,7 @@ static int usbbuxsigma_send_cmd(struct comedi_device *dev, int cmd_type) devpriv->dux_commands[0] = cmd_type; - return usb_bulk_msg(usb, usb_sndbulkpipe(usb, USBDUXSIGMA_CMD_OUT_EP), + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1), devpriv->dux_commands, SIZEOFDUXBUFFER, &nsent, BULK_TIMEOUT); } @@ -657,8 +640,7 @@ static int usbduxsigma_receive_cmd(struct comedi_device *dev, int command) int i; for (i = 0; i < RETRIES; i++) { - ret = usb_bulk_msg(usb, - usb_rcvbulkpipe(usb, USBDUXSIGMA_CMD_IN_EP), + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8), devpriv->insn_buf, SIZEINSNBUF, &nrec, BULK_TIMEOUT); if (ret < 0) @@ -676,23 +658,25 @@ static int usbduxsigma_receive_cmd(struct comedi_device *dev, int command) static int usbduxsigma_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; down(&devpriv->sem); if (!devpriv->ai_cmd_running) { + devpriv->ai_cmd_running = 1; ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs, devpriv->n_ai_urbs, 1); if (ret < 0) { + devpriv->ai_cmd_running = 0; up(&devpriv->sem); return ret; } - devpriv->ai_cmd_running = 1; s->async->inttrig = NULL; } up(&devpriv->sem); @@ -740,16 +724,16 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ + devpriv->ai_cmd_running = 1; ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs, devpriv->n_ai_urbs, 1); if (ret < 0) { + devpriv->ai_cmd_running = 0; up(&devpriv->sem); return ret; } s->async->inttrig = NULL; - devpriv->ai_cmd_running = 1; } else { /* TRIG_INT */ - /* wait for an internal signal and submit the urbs later */ s->async->inttrig = usbduxsigma_ai_inttrig; } @@ -795,7 +779,7 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, } for (i = 0; i < insn->n; i++) { - int32_t val; + uint32_t val; ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); if (ret < 0) { @@ -804,7 +788,8 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, } /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((int32_t *)((devpriv->insn_buf) + 1))); + val = be32_to_cpu(get_unaligned((uint32_t + *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ @@ -866,23 +851,25 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev, static int usbduxsigma_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; down(&devpriv->sem); if (!devpriv->ao_cmd_running) { + devpriv->ao_cmd_running = 1; ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs, devpriv->n_ao_urbs, 0); if (ret < 0) { + devpriv->ao_cmd_running = 0; up(&devpriv->sem); return ret; } - devpriv->ao_cmd_running = 1; s->async->inttrig = NULL; } up(&devpriv->sem); @@ -994,10 +981,8 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, */ devpriv->ao_sample_count = cmd->stop_arg; } - devpriv->ao_continuous = 0; } else { /* continuous acquisition */ - devpriv->ao_continuous = 1; devpriv->ao_sample_count = 0; } @@ -1013,29 +998,26 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int ret; - int i; down(&devpriv->sem); /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; - for (i = 0; i < cmd->chanlist_len; ++i) - devpriv->dac_commands[i] = CR_CHAN(cmd->chanlist[i]); devpriv->ao_counter = devpriv->ao_timer; if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ + devpriv->ao_cmd_running = 1; ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs, devpriv->n_ao_urbs, 0); if (ret < 0) { + devpriv->ao_cmd_running = 0; up(&devpriv->sem); return ret; } s->async->inttrig = NULL; - devpriv->ao_cmd_running = 1; } else { /* TRIG_INT */ - /* wait for an internal signal and submit the urbs later */ s->async->inttrig = usbduxsigma_ao_inttrig; } @@ -1049,23 +1031,11 @@ static int usbduxsigma_dio_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask = 1 << chan; + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - break; - default: - return -EINVAL; - break; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; /* * We don't tell the firmware here as it would take 8 frames @@ -1080,15 +1050,13 @@ static int usbduxsigma_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { struct usbduxsigma_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; int ret; down(&devpriv->sem); - s->state &= ~mask; - s->state |= (bits & mask); + comedi_dio_update_state(s, data); + /* Always update the hardware. See the (*insn_config). */ devpriv->dux_commands[1] = s->io_bits & 0xff; devpriv->dux_commands[4] = s->state & 0xff; devpriv->dux_commands[2] = (s->io_bits >> 8) & 0xff; @@ -1194,8 +1162,7 @@ static int usbduxsigma_submit_pwm_urb(struct comedi_device *dev) struct urb *urb = devpriv->pwm_urb; /* in case of a resubmission after an unlink... */ - usb_fill_bulk_urb(urb, - usb, usb_sndbulkpipe(usb, USBDUXSIGMA_PWM_OUT_EP), + usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4), urb->transfer_buffer, devpriv->pwm_buf_sz, usbduxsigma_pwm_urb_complete, dev); @@ -1237,19 +1204,21 @@ static int usbduxsigma_pwm_start(struct comedi_device *dev, memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz); + devpriv->pwm_cmd_running = 1; ret = usbduxsigma_submit_pwm_urb(dev); - if (ret < 0) + if (ret < 0) { + devpriv->pwm_cmd_running = 0; return ret; - devpriv->pwm_cmd_running = 1; + } return 0; } -static int usbduxsigma_pwm_pattern(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int chan, - unsigned int value, - unsigned int sign) +static void usbduxsigma_pwm_pattern(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int value, + unsigned int sign) { struct usbduxsigma_private *devpriv = dev->private; char pwm_mask = (1 << chan); /* DIO bit for the PWM data */ @@ -1270,7 +1239,6 @@ static int usbduxsigma_pwm_pattern(struct comedi_device *dev, c |= sgn_mask; *buf++ = c; } - return 1; } static int usbduxsigma_pwm_write(struct comedi_device *dev, @@ -1291,7 +1259,9 @@ static int usbduxsigma_pwm_write(struct comedi_device *dev, * The sign is set via a special INSN only, this gives us 8 bits * for normal operation, sign is 0 by default. */ - return usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0); + usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0); + + return insn->n; } static int usbduxsigma_pwm_config(struct comedi_device *dev, @@ -1326,8 +1296,8 @@ static int usbduxsigma_pwm_config(struct comedi_device *dev, * data[1] = value * data[2] = sign (for a relay) */ - return usbduxsigma_pwm_pattern(dev, s, chan, - data[1], (data[2] != 0)); + usbduxsigma_pwm_pattern(dev, s, chan, data[1], (data[2] != 0)); + return 0; case INSN_CONFIG_PWM_GET_H_BRIDGE: /* values are not kept in this driver, nothing to return */ return -EINVAL; @@ -1379,97 +1349,13 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) return ret; /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((int32_t *)((devpriv->insn_buf)+1))); + val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ return (int)val; } -static int usbduxsigma_attach_common(struct comedi_device *dev) -{ - struct usbduxsigma_private *devpriv = dev->private; - struct comedi_subdevice *s; - int n_subdevs; - int offset; - int ret; - - down(&devpriv->sem); - - if (devpriv->high_speed) - n_subdevs = 4; /* with pwm */ - else - n_subdevs = 3; /* without pwm */ - ret = comedi_alloc_subdevices(dev, n_subdevs); - if (ret) { - up(&devpriv->sem); - return ret; - } - - /* Analog Input subdevice */ - s = &dev->subdevices[0]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL; - s->n_chan = NUMCHANNELS; - s->len_chanlist = NUMCHANNELS; - s->maxdata = 0x00ffffff; - s->range_table = &usbduxsigma_ai_range; - s->insn_read = usbduxsigma_ai_insn_read; - s->do_cmdtest = usbduxsigma_ai_cmdtest; - s->do_cmd = usbduxsigma_ai_cmd; - s->cancel = usbduxsigma_ai_cancel; - - /* Analog Output subdevice */ - s = &dev->subdevices[1]; - dev->write_subdev = s; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; - s->n_chan = USBDUXSIGMA_NUM_AO_CHAN; - s->len_chanlist = s->n_chan; - s->maxdata = 0x00ff; - s->range_table = &range_unipolar2_5; - s->insn_write = usbduxsigma_ao_insn_write; - s->insn_read = usbduxsigma_ao_insn_read; - s->do_cmdtest = usbduxsigma_ao_cmdtest; - s->do_cmd = usbduxsigma_ao_cmd; - s->cancel = usbduxsigma_ao_cancel; - - /* Digital I/O subdevice */ - s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 24; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = usbduxsigma_dio_insn_bits; - s->insn_config = usbduxsigma_dio_insn_config; - - if (devpriv->high_speed) { - /* Timer / pwm subdevice */ - s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; - s->n_chan = 8; - s->maxdata = devpriv->pwm_buf_sz; - s->insn_write = usbduxsigma_pwm_write; - s->insn_config = usbduxsigma_pwm_config; - - usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD); - } - - up(&devpriv->sem); - - offset = usbduxsigma_getstatusinfo(dev, 0); - if (offset < 0) - dev_err(dev->class_dev, - "Communication to USBDUXSIGMA failed! Check firmware and cabling\n"); - - dev_info(dev->class_dev, "attached, ADC_zero = %x\n", offset); - - return 0; -} - static int usbduxsigma_firmware_upload(struct comedi_device *dev, const u8 *data, size_t size, unsigned long context) @@ -1548,7 +1434,6 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) struct urb *urb; int i; - devpriv->dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL); devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL); @@ -1556,8 +1441,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) GFP_KERNEL); devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(*urb), GFP_KERNEL); - if (!devpriv->dac_commands || !devpriv->dux_commands || - !devpriv->in_buf || !devpriv->insn_buf || + if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf || !devpriv->ai_urbs || !devpriv->ao_urbs) return -ENOMEM; @@ -1571,7 +1455,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) /* will be filled later with a pointer to the comedi-device */ /* and ONLY then the urb should be submitted */ urb->context = NULL; - urb->pipe = usb_rcvisocpipe(usb, USBDUXSIGMA_ISO_IN_EP); + urb->pipe = usb_rcvisocpipe(usb, 6); urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); if (!urb->transfer_buffer) @@ -1593,7 +1477,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) /* will be filled later with a pointer to the comedi-device */ /* and ONLY then the urb should be submitted */ urb->context = NULL; - urb->pipe = usb_sndisocpipe(usb, USBDUXSIGMA_ISO_OUT_EP); + urb->pipe = usb_sndisocpipe(usb, 2); urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); if (!urb->transfer_buffer) @@ -1609,19 +1493,16 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) urb->interval = 1; /* frames */ } - if (devpriv->high_speed) { - /* max bulk ep size in high speed */ - devpriv->pwm_buf_sz = 512; + if (devpriv->pwm_buf_sz) { urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; devpriv->pwm_urb = urb; - urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, GFP_KERNEL); + + urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, + GFP_KERNEL); if (!urb->transfer_buffer) return -ENOMEM; - } else { - devpriv->pwm_urb = NULL; - devpriv->pwm_buf_sz = 0; } return 0; @@ -1633,11 +1514,6 @@ static void usbduxsigma_free_usb_buffers(struct comedi_device *dev) struct urb *urb; int i; - /* force unlink all urbs */ - usbduxsigma_ai_stop(dev, 1); - usbduxsigma_ao_stop(dev, 1); - usbduxsigma_pwm_stop(dev, 1); - urb = devpriv->pwm_urb; if (urb) { kfree(urb->transfer_buffer); @@ -1666,7 +1542,6 @@ static void usbduxsigma_free_usb_buffers(struct comedi_device *dev) kfree(devpriv->insn_buf); kfree(devpriv->in_buf); kfree(devpriv->dux_commands); - kfree(devpriv->dac_commands); } static int usbduxsigma_auto_attach(struct comedi_device *dev, @@ -1675,29 +1550,23 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev, struct usb_interface *intf = comedi_to_usb_interface(dev); struct usb_device *usb = comedi_to_usb_dev(dev); struct usbduxsigma_private *devpriv; + struct comedi_subdevice *s; + int offset; int ret; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; sema_init(&devpriv->sem, 1); - usb_set_intfdata(intf, devpriv); - ret = usb_set_interface(usb, - intf->altsetting->desc.bInterfaceNumber, 3); - if (ret < 0) { - dev_err(dev->class_dev, - "could not set alternate setting 3 in high speed\n"); - return -ENODEV; - } + usb_set_intfdata(intf, devpriv); - /* test if it is high speed (USB 2.0) */ devpriv->high_speed = (usb->speed == USB_SPEED_HIGH); if (devpriv->high_speed) { devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH; devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH; + devpriv->pwm_buf_sz = 512; } else { devpriv->n_ai_urbs = NUMOFINBUFFERSFULL; devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL; @@ -1707,12 +1576,86 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev, if (ret) return ret; + /* setting to alternate setting 3: enabling iso ep and bulk ep. */ + ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber, + 3); + if (ret < 0) { + dev_err(dev->class_dev, + "could not set alternate setting 3 in high speed\n"); + return ret; + } + ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, usbduxsigma_firmware_upload, 0); if (ret) return ret; - return usbduxsigma_attach_common(dev); + ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 4 : 3); + if (ret) + return ret; + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL; + s->n_chan = NUMCHANNELS; + s->len_chanlist = NUMCHANNELS; + s->maxdata = 0x00ffffff; + s->range_table = &usbduxsigma_ai_range; + s->insn_read = usbduxsigma_ai_insn_read; + s->do_cmdtest = usbduxsigma_ai_cmdtest; + s->do_cmd = usbduxsigma_ai_cmd; + s->cancel = usbduxsigma_ai_cancel; + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + dev->write_subdev = s; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; + s->n_chan = USBDUXSIGMA_NUM_AO_CHAN; + s->len_chanlist = s->n_chan; + s->maxdata = 0x00ff; + s->range_table = &range_unipolar2_5; + s->insn_write = usbduxsigma_ao_insn_write; + s->insn_read = usbduxsigma_ao_insn_read; + s->do_cmdtest = usbduxsigma_ao_cmdtest; + s->do_cmd = usbduxsigma_ao_cmd; + s->cancel = usbduxsigma_ao_cancel; + + /* Digital I/O subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = usbduxsigma_dio_insn_bits; + s->insn_config = usbduxsigma_dio_insn_config; + + if (devpriv->high_speed) { + /* Timer / pwm subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; + s->n_chan = 8; + s->maxdata = devpriv->pwm_buf_sz; + s->insn_write = usbduxsigma_pwm_write; + s->insn_config = usbduxsigma_pwm_config; + + usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD); + } + + offset = usbduxsigma_getstatusinfo(dev, 0); + if (offset < 0) { + dev_err(dev->class_dev, + "Communication to USBDUXSIGMA failed! Check firmware and cabling.\n"); + return offset; + } + + dev_info(dev->class_dev, "ADC_zero = %x\n", offset); + + return 0; } static void usbduxsigma_detach(struct comedi_device *dev) @@ -1720,13 +1663,20 @@ static void usbduxsigma_detach(struct comedi_device *dev) struct usb_interface *intf = comedi_to_usb_interface(dev); struct usbduxsigma_private *devpriv = dev->private; + usb_set_intfdata(intf, NULL); + if (!devpriv) return; - usb_set_intfdata(intf, NULL); - down(&devpriv->sem); + + /* force unlink all urbs */ + usbduxsigma_ai_stop(dev, 1); + usbduxsigma_ao_stop(dev, 1); + usbduxsigma_pwm_stop(dev, 1); + usbduxsigma_free_usb_buffers(dev); + up(&devpriv->sem); } diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 0ab04c0dd41..0adf3cffddb 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -462,9 +462,10 @@ static int vmk80xx_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct vmk80xx_private *devpriv = dev->private; - unsigned char *rx_buf, *tx_buf; + unsigned char *rx_buf = devpriv->usb_rx_buf; + unsigned char *tx_buf = devpriv->usb_tx_buf; int reg, cmd; - int retval; + int ret = 0; if (devpriv->model == VMK8061_MODEL) { reg = VMK8061_DO_REG; @@ -476,37 +477,27 @@ static int vmk80xx_do_insn_bits(struct comedi_device *dev, down(&devpriv->limit_sem); - rx_buf = devpriv->usb_rx_buf; - tx_buf = devpriv->usb_tx_buf; - - if (data[0]) { - tx_buf[reg] &= ~data[0]; - tx_buf[reg] |= (data[0] & data[1]); - - retval = vmk80xx_write_packet(dev, cmd); - - if (retval) + if (comedi_dio_update_state(s, data)) { + tx_buf[reg] = s->state; + ret = vmk80xx_write_packet(dev, cmd); + if (ret) goto out; } if (devpriv->model == VMK8061_MODEL) { tx_buf[0] = VMK8061_CMD_RD_DO; - - retval = vmk80xx_read_packet(dev); - - if (!retval) { - data[1] = rx_buf[reg]; - retval = 2; - } + ret = vmk80xx_read_packet(dev); + if (ret) + goto out; + data[1] = rx_buf[reg]; } else { - data[1] = tx_buf[reg]; - retval = 2; + data[1] = s->state; } out: up(&devpriv->limit_sem); - return retval; + return ret ? ret : insn->n; } static int vmk80xx_cnt_insn_read(struct comedi_device *dev, @@ -875,10 +866,9 @@ static int vmk80xx_auto_attach(struct comedi_device *dev, dev->board_ptr = boardinfo; dev->board_name = boardinfo->name; - devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - dev->private = devpriv; devpriv->model = boardinfo->model; diff --git a/drivers/staging/comedi/kcomedilib/Makefile b/drivers/staging/comedi/kcomedilib/Makefile index 18ee99bdde0..3aff8ed08e2 100644 --- a/drivers/staging/comedi/kcomedilib/Makefile +++ b/drivers/staging/comedi/kcomedilib/Makefile @@ -1,3 +1,5 @@ +ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG + obj-$(CONFIG_COMEDI_KCOMEDILIB) += kcomedilib.o kcomedilib-objs := kcomedilib_main.o diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index da8988c6bf5..8777f958c04 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -22,8 +22,6 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/fcntl.h> -#include <linux/delay.h> -#include <linux/ioport.h> #include <linux/mm.h> #include <linux/io.h> @@ -37,35 +35,39 @@ MODULE_LICENSE("GPL"); struct comedi_device *comedi_open(const char *filename) { - struct comedi_device *dev; + struct comedi_device *dev, *retval = NULL; unsigned int minor; if (strncmp(filename, "/dev/comedi", 11) != 0) return NULL; - minor = simple_strtoul(filename + 11, NULL, 0); + if (kstrtouint(filename + 11, 0, &minor)) + return NULL; if (minor >= COMEDI_NUM_BOARD_MINORS) return NULL; - dev = comedi_dev_from_minor(minor); - - if (!dev || !dev->attached) + dev = comedi_dev_get_from_minor(minor); + if (!dev) return NULL; - if (!try_module_get(dev->driver->module)) - return NULL; + down_read(&dev->attach_lock); + if (dev->attached) + retval = dev; + else + retval = NULL; + up_read(&dev->attach_lock); - return dev; + if (retval == NULL) + comedi_dev_put(dev); + + return retval; } EXPORT_SYMBOL_GPL(comedi_open); -int comedi_close(struct comedi_device *d) +int comedi_close(struct comedi_device *dev) { - struct comedi_device *dev = (struct comedi_device *)d; - - module_put(dev->driver->module); - + comedi_dev_put(dev); return 0; } EXPORT_SYMBOL_GPL(comedi_close); @@ -75,7 +77,14 @@ static int comedi_do_insn(struct comedi_device *dev, unsigned int *data) { struct comedi_subdevice *s; - int ret = 0; + int ret; + + mutex_lock(&dev->mutex); + + if (!dev->attached) { + ret = -EINVAL; + goto error; + } /* a subdevice instruction */ if (insn->subdev >= dev->n_subdevices) { @@ -122,8 +131,30 @@ static int comedi_do_insn(struct comedi_device *dev, s->busy = NULL; error: + mutex_unlock(&dev->mutex); + return ret; +} + +int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev, + unsigned int chan, unsigned int *io) +{ + struct comedi_insn insn; + unsigned int data[2]; + int ret; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_CONFIG; + insn.n = 2; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, 0, 0); + data[0] = INSN_CONFIG_DIO_QUERY; + data[1] = 0; + ret = comedi_do_insn(dev, &insn, data); + if (ret >= 0) + *io = data[1]; return ret; } +EXPORT_SYMBOL_GPL(comedi_dio_get_config); int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, unsigned int chan, unsigned int io) @@ -140,50 +171,82 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, } EXPORT_SYMBOL_GPL(comedi_dio_config); -int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, - unsigned int mask, unsigned int *bits) +int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev, + unsigned int mask, unsigned int *bits, + unsigned int base_channel) { struct comedi_insn insn; unsigned int data[2]; + unsigned int n_chan; + unsigned int shift; int ret; + base_channel = CR_CHAN(base_channel); + n_chan = comedi_get_n_channels(dev, subdev); + if (base_channel >= n_chan) + return -EINVAL; + memset(&insn, 0, sizeof(insn)); insn.insn = INSN_BITS; + insn.chanspec = base_channel; insn.n = 2; insn.subdev = subdev; data[0] = mask; data[1] = *bits; - ret = comedi_do_insn(dev, &insn, data); - - *bits = data[1]; + /* + * Most drivers ignore the base channel in insn->chanspec. + * Fix this here if the subdevice has <= 32 channels. + */ + if (n_chan <= 32) { + shift = base_channel; + if (shift) { + insn.chanspec = 0; + data[0] <<= shift; + data[1] <<= shift; + } + } else { + shift = 0; + } + ret = comedi_do_insn(dev, &insn, data); + *bits = data[1] >> shift; return ret; } -EXPORT_SYMBOL_GPL(comedi_dio_bitfield); +EXPORT_SYMBOL_GPL(comedi_dio_bitfield2); int comedi_find_subdevice_by_type(struct comedi_device *dev, int type, unsigned int subd) { struct comedi_subdevice *s; - - if (subd > dev->n_subdevices) - return -ENODEV; - - for (; subd < dev->n_subdevices; subd++) { - s = &dev->subdevices[subd]; - if (s->type == type) - return subd; - } - return -1; + int ret = -ENODEV; + + down_read(&dev->attach_lock); + if (dev->attached) + for (; subd < dev->n_subdevices; subd++) { + s = &dev->subdevices[subd]; + if (s->type == type) { + ret = subd; + break; + } + } + up_read(&dev->attach_lock); + return ret; } EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type); int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice) { - struct comedi_subdevice *s = &dev->subdevices[subdevice]; + int n; + + down_read(&dev->attach_lock); + if (!dev->attached || subdevice >= dev->n_subdevices) + n = 0; + else + n = dev->subdevices[subdevice].n_chan; + up_read(&dev->attach_lock); - return s->n_chan; + return n; } EXPORT_SYMBOL_GPL(comedi_get_n_channels); diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c index 8ee94424bc8..91dea25b572 100644 --- a/drivers/staging/comedi/proc.c +++ b/drivers/staging/comedi/proc.c @@ -1,27 +1,26 @@ /* - module/proc.c - /proc interface for comedi - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * /proc interface for comedi + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* - This is some serious bloatware. - - Taken from Dave A.'s PCL-711 driver, 'cuz I thought it - was cool. -*/ + * This is some serious bloatware. + * + * Taken from Dave A.'s PCL-711 driver, 'cuz I thought it + * was cool. + */ #include "comedidev.h" #include "comedi_internal.h" @@ -34,27 +33,29 @@ static int comedi_read(struct seq_file *m, void *v) int devices_q = 0; struct comedi_driver *driv; - seq_printf(m, - "comedi version " COMEDI_RELEASE "\n" - "format string: %s\n", - "\"%2d: %-20s %-20s %4d\", i, " - "driver_name, board_name, n_subdevices"); + seq_printf(m, "comedi version " COMEDI_RELEASE "\nformat string: %s\n", + "\"%2d: %-20s %-20s %4d\", i, driver_name, board_name, n_subdevices"); for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { - struct comedi_device *dev = comedi_dev_from_minor(i); + struct comedi_device *dev = comedi_dev_get_from_minor(i); + if (!dev) continue; + down_read(&dev->attach_lock); if (dev->attached) { devices_q = 1; seq_printf(m, "%2d: %-20s %-20s %4d\n", i, dev->driver->driver_name, dev->board_name, dev->n_subdevices); } + up_read(&dev->attach_lock); + comedi_dev_put(dev); } if (!devices_q) seq_puts(m, "no devices\n"); + mutex_lock(&comedi_drivers_list_lock); for (driv = comedi_drivers; driv; driv = driv->next) { seq_printf(m, "%s:\n", driv->driver_name); for (i = 0; i < driv->num_names; i++) @@ -65,6 +66,7 @@ static int comedi_read(struct seq_file *m, void *v) if (!driv->num_names) seq_printf(m, " %s\n", driv->driver_name); } + mutex_unlock(&comedi_drivers_list_lock); return 0; } diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index 1f20332cc45..b6849545b81 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -83,8 +83,10 @@ int do_rangeinfo_ioctl(struct comedi_device *dev, } if (RANGE_LENGTH(it.range_type) != lr->length) { - DPRINTK("wrong length %d should be %d (0x%08x)\n", - RANGE_LENGTH(it.range_type), lr->length, it.range_type); + dev_dbg(dev->class_dev, + "wrong length %d should be %d (0x%08x)\n", + RANGE_LENGTH(it.range_type), + lr->length, it.range_type); return -EINVAL; } @@ -123,48 +125,41 @@ static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec) default: break; } - DPRINTK("subdevice does not support aref %i", aref); + dev_dbg(s->device->class_dev, "subdevice does not support aref %i", + aref); return 1; } -/* - This function checks each element in a channel/gain list to make - make sure it is valid. +/** + * comedi_check_chanlist() - Validate each element in a chanlist. + * @s: comedi_subdevice struct + * @n: number of elements in the chanlist + * @chanlist: the chanlist to validate */ int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist) { struct comedi_device *dev = s->device; - int i; - int chan; - - if (s->range_table) { - for (i = 0; i < n; i++) - if (CR_CHAN(chanlist[i]) >= s->n_chan || - CR_RANGE(chanlist[i]) >= s->range_table->length - || aref_invalid(s, chanlist[i])) { - dev_warn(dev->class_dev, - "bad chanlist[%d]=0x%08x in_chan=%d range length=%d\n", - i, chanlist[i], s->n_chan, - s->range_table->length); - return -EINVAL; - } - } else if (s->range_table_list) { - for (i = 0; i < n; i++) { - chan = CR_CHAN(chanlist[i]); - if (chan >= s->n_chan || - CR_RANGE(chanlist[i]) >= - s->range_table_list[chan]->length - || aref_invalid(s, chanlist[i])) { - dev_warn(dev->class_dev, - "bad chanlist[%d]=0x%08x\n", - i, chanlist[i]); - return -EINVAL; - } + unsigned int chanspec; + int chan, range_len, i; + + for (i = 0; i < n; i++) { + chanspec = chanlist[i]; + chan = CR_CHAN(chanspec); + if (s->range_table) + range_len = s->range_table->length; + else if (s->range_table_list && chan < s->n_chan) + range_len = s->range_table_list[chan]->length; + else + range_len = 0; + if (chan >= s->n_chan || + CR_RANGE(chanspec) >= range_len || + aref_invalid(s, chanspec)) { + dev_warn(dev->class_dev, + "bad chanlist[%d]=0x%08x chan=%d range length=%d\n", + i, chanspec, chan, range_len); + return -EINVAL; } - } else { - dev_err(dev->class_dev, "(bug) no range type list!\n"); - return -EINVAL; } return 0; } |
