diff options
Diffstat (limited to 'drivers/staging/comedi')
130 files changed, 8577 insertions, 10709 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 89e25b4203a..a2f6957e7ee 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -160,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. @@ -177,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, @@ -188,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 @@ -197,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 @@ -257,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 @@ -559,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--- @@ -647,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 @@ -753,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 @@ -856,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 @@ -1101,6 +1108,7 @@ config COMEDI_S626 config COMEDI_MITE depends on HAS_DMA + select COMEDI_FC tristate config COMEDI_NI_TIOCMD @@ -1179,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 diff --git a/drivers/staging/comedi/TODO b/drivers/staging/comedi/TODO index fa8da9aada3..b68fbdb5eeb 100644 --- a/drivers/staging/comedi/TODO +++ b/drivers/staging/comedi/TODO @@ -3,7 +3,6 @@ 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 diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index 924fce97798..df4a9c4bca3 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -61,6 +61,8 @@ 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); @@ -68,8 +70,11 @@ static void __comedi_buf_free(struct comedi_device *dev, async->prealloc_bufsz = 0; } - comedi_buf_map_put(async->buf_map); + 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, @@ -80,6 +85,7 @@ static void __comedi_buf_alloc(struct comedi_device *dev, 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) { @@ -92,8 +98,10 @@ static void __comedi_buf_alloc(struct comedi_device *dev, if (!bm) return; - async->buf_map = bm; 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. */ @@ -127,7 +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) @@ -150,9 +160,32 @@ int comedi_buf_map_put(struct comedi_buf_map *bm) return 1; } -bool comedi_buf_is_mmapped(struct comedi_async *async) +/* 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 = async->buf_map; + struct comedi_buf_map *bm = s->async->buf_map; return bm && (atomic_read(&bm->refcount.refcount) > 1); } @@ -189,8 +222,10 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, 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; @@ -208,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; @@ -236,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); @@ -247,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); @@ -290,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; @@ -314,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) @@ -334,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; @@ -361,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; /* @@ -383,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, unsigned 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; } *(unsigned short *)(async->prealloc_buf + async->buf_write_ptr) = x; - comedi_buf_write_free(async, sizeof(short)); + comedi_buf_write_free(s, sizeof(short)); return 1; } EXPORT_SYMBOL_GPL(comedi_buf_put); -int comedi_buf_get(struct comedi_async *async, unsigned 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)); + comedi_buf_read_alloc(s, sizeof(short)); *x = *(unsigned short *)(async->prealloc_buf + async->buf_read_ptr); - comedi_buf_read_free(async, sizeof(short)); + 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) @@ -436,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_fops.c b/drivers/staging/comedi/comedi_fops.c index c22c617b0da..9d99fb3c18a 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -238,9 +238,9 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor) } 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) @@ -251,7 +251,7 @@ static int resize_async_buffer(struct comedi_device *dev, "subdevice is busy, cannot resize buffer\n"); return -EBUSY; } - if (comedi_buf_is_mmapped(async)) { + if (comedi_buf_is_mmapped(s)) { dev_dbg(dev->class_dev, "subdevice is mmapped, cannot resize buffer\n"); return -EBUSY; @@ -297,7 +297,7 @@ static ssize_t max_read_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t max_read_buffer_kb_store(struct device *csdev, @@ -353,7 +353,7 @@ static ssize_t read_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t read_buffer_kb_store(struct device *csdev, @@ -380,7 +380,7 @@ static ssize_t read_buffer_kb_store(struct device *csdev, 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); @@ -410,7 +410,7 @@ static ssize_t max_write_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t max_write_buffer_kb_store(struct device *csdev, @@ -466,7 +466,7 @@ static ssize_t write_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t write_buffer_kb_store(struct device *csdev, @@ -493,7 +493,7 @@ static ssize_t write_buffer_kb_store(struct device *csdev, 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); @@ -583,7 +583,7 @@ 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; @@ -635,7 +635,7 @@ static int is_device_busy(struct comedi_device *dev) s = &dev->subdevices[i]; if (s->busy) return 1; - if (s->async && comedi_buf_is_mmapped(s->async)) + if (s->async && comedi_buf_is_mmapped(s)) return 1; } @@ -668,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); } @@ -740,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; } @@ -992,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) { @@ -1003,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: @@ -1194,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 @@ -1207,8 +1213,14 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, 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) { @@ -1405,41 +1417,96 @@ 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))) { + 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) { - dev_dbg(dev->class_dev, "%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) { - dev_dbg(dev->class_dev, "%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) { dev_dbg(dev->class_dev, - "subdevice %i does not support commands\n", cmd.subdev); + "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) { dev_dbg(dev->class_dev, "subdevice locked\n"); @@ -1452,13 +1519,6 @@ static int do_cmd_ioctl(struct comedi_device *dev, return -EBUSY; } - /* 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 %u > %d\n", - cmd.chanlist_len, s->len_chanlist); - return -EINVAL; - } - /* make sure channel/gain list isn't too short */ if (cmd.chanlist_len < 1) { dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n", @@ -1468,25 +1528,11 @@ static int do_cmd_ioctl(struct comedi_device *dev, async->cmd = cmd; async->cmd.data = NULL; - /* load channel/gain list */ - async->cmd.chanlist = memdup_user(user_chanlist, - async->cmd.chanlist_len * sizeof(int)); - if (IS_ERR(async->cmd.chanlist)) { - ret = PTR_ERR(async->cmd.chanlist); - async->cmd.chanlist = NULL; - dev_dbg(dev->class_dev, "memdup_user failed with code %d\n", - ret); - 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) { - dev_dbg(dev->class_dev, "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); @@ -1511,7 +1557,7 @@ static int do_cmd_ioctl(struct comedi_device *dev, goto cleanup; } - comedi_buf_reset(async); + comedi_buf_reset(s); async->cb_mask = COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | @@ -1554,63 +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))) { - 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) { - dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd.subdev); - return -ENODEV; - } - s = &dev->subdevices[cmd.subdev]; - if (s->type == COMEDI_SUBD_UNUSED) { - dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd.subdev); - return -EIO; - } - - if (!s->do_cmd || !s->do_cmdtest) { - dev_dbg(dev->class_dev, - "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) { - dev_dbg(dev->class_dev, "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 = memdup_user(user_chanlist, - cmd.chanlist_len * sizeof(int)); - if (IS_ERR(chanlist)) { - ret = PTR_ERR(chanlist); - chanlist = NULL; - dev_dbg(dev->class_dev, - "memdup_user exited with code %d", ret); - goto cleanup; - } - - /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist); - if (ret < 0) { - dev_dbg(dev->class_dev, "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); @@ -1620,10 +1626,7 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, if (copy_to_user(arg, &cmd, sizeof(cmd))) { dev_dbg(dev->class_dev, "bad cmd address\n"); ret = -EFAULT; - goto cleanup; } -cleanup: - kfree(chanlist); return ret; } @@ -1923,14 +1926,21 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) struct comedi_device *dev = file->private_data; struct comedi_subdevice *s; struct comedi_async *async; - struct comedi_buf_map *bm; + struct comedi_buf_map *bm = NULL; unsigned long start = vma->vm_start; unsigned long size; int n_pages; int i; int retval; - 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) { dev_dbg(dev->class_dev, "no driver attached\n"); @@ -1970,7 +1980,9 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } n_pages = size >> PAGE_SHIFT; - bm = async->buf_map; + + /* 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; @@ -1994,7 +2006,8 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *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; } @@ -2016,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; } @@ -2123,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; @@ -2154,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; @@ -2216,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; @@ -2259,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; @@ -2314,46 +2327,12 @@ static int comedi_open(struct inode *inode, struct file *file) 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) { - dev_dbg(dev->class_dev, "in request module\n"); - rc = -ENODEV; - goto out; - } - 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)) { dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n"); rc = -ENODEV; goto out; } -ok: if (dev->attached && dev->use_count == 0) { if (!try_module_get(dev->driver->module)) { rc = -ENOSYS; @@ -2641,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 9a746570f16..e978c223f5b 100644 --- a/drivers/staging/comedi/comedi_internal.h +++ b/drivers/staging/comedi/comedi_internal.h @@ -15,11 +15,13 @@ 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); -bool comedi_buf_is_mmapped(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); -unsigned int comedi_buf_write_n_allocated(struct comedi_async *async); +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; diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index f82bd4256d5..8f4e44bfbe0 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -61,31 +61,31 @@ struct comedi_subdevice { 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; @@ -108,8 +108,6 @@ struct comedi_buf_map { }; struct comedi_async { - struct comedi_subdevice *subdevice; - void *prealloc_buf; /* pre-allocated buffer */ unsigned int prealloc_bufsz; /* buffer size, in bytes */ struct comedi_buf_map *buf_map; /* map of buffer pages */ @@ -146,8 +144,8 @@ struct comedi_async { unsigned int cb_mask; - 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 { @@ -155,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; @@ -182,7 +180,6 @@ 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; @@ -202,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) @@ -336,23 +333,31 @@ 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 *, unsigned short); -int comedi_buf_get(struct comedi_async *, unsigned 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); diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 5b15033a94b..299726f39e2 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -155,6 +155,36 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, } /** + * 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 @@ -228,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; @@ -276,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; diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index e3d737cf730..5829b46b757 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -30,106 +30,11 @@ #define I8254_OSC_BASE_2MHZ 500 #define I8254_OSC_BASE_1MHZ 1000 -#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) +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; @@ -386,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; @@ -406,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 48817f087d9..46113a37413 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -117,7 +117,7 @@ void subdev_8255_interrupt(struct comedi_device *dev, 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); @@ -231,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) @@ -298,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 8a57c3c1ade..46a385c29ba 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -56,6 +56,7 @@ Configuration Options: not applicable, uses PCI auto config #include "../comedidev.h" #include "8255.h" +#include "mite.h" enum pci_8255_boardid { BOARD_ADLINK_PCI7224, @@ -79,6 +80,7 @@ struct pci_8255_boardinfo { const char *name; int dio_badr; int n_8255; + unsigned int has_mite:1; }; static const struct pci_8255_boardinfo pci_8255_boards[] = { @@ -126,36 +128,43 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { .name = "ni_pci-dio-96", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCIDIO96B] = { .name = "ni_pci-dio-96b", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PXI6508] = { .name = "ni_pxi-6508", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCI6503] = { .name = "ni_pci-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503B] = { .name = "ni_pci-6503b", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503X] = { .name = "ni_pci-6503x", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PXI_6503] = { .name = "ni_pxi-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, }; @@ -163,6 +172,25 @@ struct pci_8255_private { void __iomem *mmio_base; }; +static int pci_8255_mite_init(struct pci_dev *pcidev) +{ + void __iomem *mite_base; + u32 main_phys_addr; + + /* ioremap the MITE registers (BAR 0) temporarily */ + mite_base = pci_ioremap_bar(pcidev, 0); + if (!mite_base) + return -ENOMEM; + + /* set data window to main registers (BAR 1) */ + main_phys_addr = pci_resource_start(pcidev, 1); + writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR); + + /* finished with MITE registers */ + iounmap(mite_base); + return 0; +} + static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase) { void __iomem *mmio_base = (void __iomem *)iobase; @@ -201,6 +229,12 @@ static int pci_8255_auto_attach(struct comedi_device *dev, if (ret) return ret; + if (board->has_mite) { + ret = pci_8255_mite_init(pcidev); + if (ret) + return ret; + } + is_mmio = (pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM) != 0; if (is_mmio) { @@ -235,9 +269,6 @@ static int pci_8255_auto_attach(struct comedi_device *dev, return ret; } - dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n", - dev->board_name, board->n_8255 * 24); - return 0; } diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 2706f583d8f..0757a82ddcf 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_COMEDI_PCL818) += pcl818.o obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o +obj-$(CONFIG_COMEDI_DAC02) += dac02.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o obj-$(CONFIG_COMEDI_DAS16) += das16.o @@ -53,7 +54,6 @@ obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o -obj-$(CONFIG_COMEDI_POC) += poc.o obj-$(CONFIG_COMEDI_S526) += s526.o # Comedi PCI drivers diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index 2ed2da3499f..5c6a11c35de 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -118,18 +118,10 @@ struct addi_private { 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 */ @@ -145,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; 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 84668544f52..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,90 +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; - - s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - - if (comedi_dio_update_state(s, data)) - 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; @@ -316,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 */ @@ -406,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; @@ -472,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; @@ -677,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; @@ -757,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; @@ -779,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; @@ -801,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; @@ -823,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 bd05857b82f..764c8f17f8f 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -248,10 +248,10 @@ static const struct comedi_lrange range_apci3120_ao = { +----------------------------------------------------------------------------+ */ -static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -304,11 +304,11 @@ static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, * If the last argument of function "check"is 1 then it only checks * the channel list is ok or not. */ -static int i_APCI3120_SetupChannelList(struct comedi_device *dev, - struct comedi_subdevice *s, - int n_chan, - unsigned int *chanlist, - char check) +static int apci3120_setup_chan_list(struct comedi_device *dev, + struct comedi_subdevice *s, + int n_chan, + unsigned int *chanlist, + char check) { struct addi_private *devpriv = dev->private; unsigned int i; /* , differencial=0, bipolar=0; */ @@ -358,10 +358,10 @@ static int i_APCI3120_SetupChannelList(struct comedi_device *dev, * as per configured if no conversion time is set uses default * conversion time 10 microsec. */ -static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -417,10 +417,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, inw(devpriv->iobase + APCI3120_RESET_FIFO); /* Initialize the sequence array */ - - /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */ - - if (!i_APCI3120_SetupChannelList(dev, s, 1, + if (!apci3120_setup_chan_list(dev, s, 1, &insn->chanspec, 0)) return -EINVAL; @@ -512,7 +509,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - if (!i_APCI3120_SetupChannelList(dev, s, + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, devpriv->ui_AiChannelList, 0)) return -EINVAL; @@ -606,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; @@ -663,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; @@ -672,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; @@ -681,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; @@ -705,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 */ @@ -723,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 */ @@ -770,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); @@ -795,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) @@ -818,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 */ /*******************/ @@ -843,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; @@ -895,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); @@ -957,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 */ @@ -1042,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) @@ -1110,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 */ @@ -1128,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; @@ -1296,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; @@ -1333,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); } /* @@ -1395,11 +1341,12 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, 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)); } @@ -1410,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->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; @@ -1429,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 */ @@ -1492,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; @@ -1565,7 +1510,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) * This function handles EOS interrupt. * This function copies the acquired data(from FIFO) to Comedi buffer. */ -static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) +static int apci3120_interrupt_handle_eos(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -1574,10 +1519,8 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) n_chan = devpriv->ui_AiNbrofChannels; - s->async->events = 0; - for (i = 0; i < n_chan; i++) - err &= comedi_buf_put(s->async, inw(dev->iobase + 0)); + err &= comedi_buf_put(s, inw(dev->iobase + 0)); s->async->events |= COMEDI_CB_EOS; @@ -1589,7 +1532,7 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) return 0; } -static void v_APCI3120_Interrupt(int irq, void *d) +static void apci3120_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -1615,7 +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 */ @@ -1653,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-> @@ -1695,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; @@ -1711,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; @@ -1751,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 */ @@ -1765,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-> @@ -1787,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) @@ -1932,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) @@ -2104,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) @@ -2189,10 +2130,10 @@ static int apci3120_do_insn_bits(struct comedi_device *dev, return insn->n; } -static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Range, ui_Channel; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 8c85a09d1c6..f540394d17b 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -1268,7 +1268,7 @@ static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, return 0; } -static int i_APCI3200_Reset(struct comedi_device *dev) +static int apci3200_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_Temp; @@ -1322,10 +1322,10 @@ static int i_APCI3200_Reset(struct comedi_device *dev) * data[7] : Channel current source from eeprom * data[8] : Channle gain factor from eeprom */ -static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { unsigned int ui_DummyValue = 0; int i_ConvertCJCCalibration; @@ -1336,7 +1336,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, if (s_BoardInfos[dev->minor].i_Initialised == 0) /* END JK 06.07.04: Management of sevrals boards */ { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ @@ -1586,7 +1586,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, break; default: printk("\nThe parameters passed are in error\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* switch(insn->unused[0]) */ @@ -1626,10 +1626,10 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, * = 2 RTD 3 wire connection * = 3 RTD 4 wire connection */ -static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Config = 0, ul_Temp = 0; @@ -1970,7 +1970,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, } /* switch(data[11]) */ } /* elseif(data[12]==0 || data[12]==1) */ if (i_err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_ScanType!=1) */ @@ -2079,7 +2079,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, /* END JK 06.07.04: Management of sevrals boards */ insn->unused[0] = 0; - i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy); + apci3200_ai_read(dev, s, insn, &ui_Dummy); } return insn->n; @@ -2095,10 +2095,10 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, * data[1] : calibration offset * data[2] : calibration gain */ -static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_bits_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; @@ -2107,12 +2107,12 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, /* if(i_Initialised==0) */ if (s_BoardInfos[dev->minor].i_Initialised == 0) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ if (data[0] != 0 && data[0] != 1) { printk("\nError in selection of functionality\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(data[0]!=0 && data[0]!=1) */ @@ -2202,18 +2202,18 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, return insn->n; } -static int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return insn->n; } -static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3200_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; @@ -2221,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 */ @@ -2241,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; } @@ -2253,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]; */ @@ -2308,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(); @@ -2366,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; @@ -2410,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; @@ -2619,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 */ /*************************************/ @@ -2690,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 */ @@ -2700,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 */ @@ -2730,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 ccd49211ea1..4da9db35b8e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -27,13 +27,13 @@ static const struct addi_board apci035_boardtypes[] = { .i_Timer = 1, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI035_Interrupt, - .reset = i_APCI035_Reset, - .ai_config = i_APCI035_ConfigAnalogInput, - .ai_read = i_APCI035_ReadAnalogInput, - .timer_config = i_APCI035_ConfigTimerWatchdog, - .timer_write = i_APCI035_StartStopWriteTimerWatchdog, - .timer_read = i_APCI035_ReadTimerWatchdog, + .interrupt = apci035_interrupt, + .reset = apci035_reset, + .ai_config = apci035_ai_config, + .ai_read = apci035_ai_read, + .timer_config = apci035_timer_config, + .timer_write = apci035_timer_write, + .timer_read = apci035_timer_read, }, }; diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 0daa0ea63b5..1b2e7c040c9 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -198,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) @@ -262,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); @@ -332,6 +332,7 @@ static int apci1032_auto_attach(struct comedi_device *dev, 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; @@ -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 74f7ace8adb..eab75eb2647 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -20,19 +20,19 @@ static const struct addi_board apci1500_boardtypes[] = { .i_NbrDoChannel = 16, .i_DoMaxdata = 0xffff, .i_Timer = 1, - .interrupt = v_APCI1500_Interrupt, - .reset = i_APCI1500_Reset, - .di_config = i_APCI1500_ConfigDigitalInputEvent, - .di_read = i_APCI1500_Initialisation, - .di_write = i_APCI1500_StartStopInputEvent, + .interrupt = apci1500_interrupt, + .reset = apci1500_reset, + .di_config = apci1500_di_config, + .di_read = apci1500_di_read, + .di_write = apci1500_di_write, .di_bits = apci1500_di_insn_bits, - .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt, - .do_write = i_APCI1500_WriteDigitalOutput, - .do_bits = i_APCI1500_ConfigureInterrupt, - .timer_config = i_APCI1500_ConfigCounterTimerWatchdog, - .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog, - .timer_read = i_APCI1500_ReadInterruptMask, - .timer_bits = i_APCI1500_ReadCounterTimerWatchdog, + .do_config = apci1500_do_config, + .do_write = apci1500_do_write, + .do_bits = apci1500_do_bits, + .timer_config = apci1500_timer_config, + .timer_write = apci1500_timer_write, + .timer_read = apci1500_timer_read, + .timer_bits = apci1500_timer_bits, }, }; @@ -72,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_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 6248284caaf..13d9962b47e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -3,50 +3,168 @@ #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, @@ -70,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_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index c9b933cb598..be0a8a7bd3b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -197,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; @@ -222,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) { @@ -374,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_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 1e6fa56c516..0cfb12fa1cb 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -26,7 +26,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, [BOARD_APCI3001] = { .pc_DriverName = "apci3001", @@ -37,7 +37,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, }; @@ -136,11 +136,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = this_board->i_AiChannelList; s->range_table = &range_apci3120_ai; - s->insn_config = i_APCI3120_InsnConfigAnalogInput; - s->insn_read = i_APCI3120_InsnReadAnalogInput; - s->do_cmdtest = i_APCI3120_CommandTestAnalogInput; - s->do_cmd = i_APCI3120_CommandAnalogInput; - s->cancel = i_APCI3120_StopCyclicAcquisition; + s->insn_config = apci3120_ai_insn_config; + s->insn_read = apci3120_ai_insn_read; + s->do_cmdtest = apci3120_ai_cmdtest; + s->do_cmd = apci3120_ai_cmd; + s->cancel = apci3120_cancel; /* Allocate and Initialise AO Subdevice Structures */ s = &dev->subdevices[1]; @@ -151,7 +151,7 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = this_board->i_AoMaxdata; s->len_chanlist = this_board->i_NbrAoChannel; s->range_table = &range_apci3120_ao; - s->insn_write = i_APCI3120_InsnWriteAnalogOutput; + s->insn_write = apci3120_ao_insn_write; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -186,11 +186,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3120_InsnWriteTimer; - s->insn_read = i_APCI3120_InsnReadTimer; - s->insn_config = i_APCI3120_InsnConfigTimer; + s->insn_write = apci3120_write_insn_timer; + s->insn_read = apci3120_read_insn_timer; + s->insn_config = apci3120_config_insn_timer; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } @@ -200,7 +200,7 @@ static void apci3120_detach(struct comedi_device *dev) if (devpriv) { if (dev->iobase) - i_APCI3120_Reset(dev); + apci3120_reset(dev); if (dev->irq) free_irq(dev->irq, dev); if (devpriv->ul_DmaBufferVirtual[0]) { @@ -246,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 9868a5369af..f0f891a482a 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ b/drivers/staging/comedi/drivers/addi_apci_3200.c @@ -43,15 +43,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, @@ -68,15 +68,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index 4cb69ec54c9..49bf1fb840f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -390,9 +390,9 @@ static int apci3501_auto_attach(struct comedi_device *dev, s->maxdata = 0; s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog; - s->insn_read = i_APCI3501_ReadTimerCounterWatchdog; - s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog; + s->insn_write = apci3501_write_insn_timer; + s->insn_read = apci3501_read_insn_timer; + s->insn_config = apci3501_config_insn_timer; /* Initialize the eeprom subdevice */ s = &dev->subdevices[4]; diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index ceadf8eff47..0532b6cc40e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -373,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); @@ -434,13 +434,26 @@ static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec) return 0; } +static int apci3xxx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 20); + if (status & 0x1) + return 0; + return -EBUSY; +} + static int apci3xxx_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct apci3xxx_private *devpriv = dev->private; - unsigned int val; int ret; int i; @@ -453,10 +466,9 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev, writel(0x80000, devpriv->mmio + 8); /* Wait the EOS */ - do { - val = readl(devpriv->mmio + 20); - val &= 0x1; - } while (!val); + ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0); + if (ret) + return ret; /* Read the analog value */ data[i] = readl(devpriv->mmio + 28); @@ -521,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 */ @@ -561,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; @@ -622,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, @@ -630,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++) { @@ -641,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; @@ -680,7 +684,7 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask; + unsigned int mask = 0; int ret; /* @@ -688,12 +692,14 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, * Port 1 (channels 8-15) are always outputs * Port 2 (channels 16-23) are programmable i/o */ - if (chan < 16) { - if (data[0] != INSN_CONFIG_DIO_QUERY) + if (data[0] != INSN_CONFIG_DIO_QUERY) { + /* ignore all other instructions for ports 0 and 1 */ + if (chan < 16) return -EINVAL; - } else { - /* changing any channel in port 2 changes the entire port */ - mask = 0xff0000; + else + /* changing any channel in port 2 */ + /* changes the entire port */ + mask = 0xff0000; } ret = comedi_dio_insn_config(dev, s, insn, data, mask); @@ -815,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; diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 5c1413abc52..921f6942dfc 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -73,19 +73,17 @@ struct pci6208_private { unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS]; }; -static int pci6208_ao_wait_for_data_send(struct comedi_device *dev, - unsigned int timeout) +static int pci6208_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; - while (timeout--) { - status = inw(dev->iobase + PCI6208_AO_STATUS); - if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) - return 0; - udelay(1); - } - - return -ETIME; + status = inw(dev->iobase + PCI6208_AO_STATUS); + if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) + return 0; + return -EBUSY; } static int pci6208_ao_insn_write(struct comedi_device *dev, @@ -102,8 +100,8 @@ static int pci6208_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - /* D/A transfer rate is 2.2us, wait up to 10us */ - ret = pci6208_ao_wait_for_data_send(dev, 10); + /* D/A transfer rate is 2.2us */ + ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index 6f622b4de69..5e3cc77a8a0 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -239,9 +239,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev, } } - dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n", - dev->board_name, board->di_nchan, board->do_nchan); - return 0; } diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index 363f2e42a27..584fd57ecb7 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -84,7 +84,6 @@ TODO: #define PCI9111_RANGE_SETTING_DELAY 10 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2 -#define PCI9111_AI_INSTANT_READ_TIMEOUT 100 /* * IO address map and bit defines @@ -138,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; @@ -315,148 +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; + arg = cmd->convert_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, &dev_private->div1, &dev_private->div2, - &cmd->convert_arg, cmd->flags); - if (tmp != cmd->convert_arg) - error++; + &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; @@ -467,18 +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; /* 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); } @@ -486,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); @@ -522,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, @@ -540,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; } @@ -572,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; @@ -589,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); @@ -613,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) @@ -717,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); @@ -734,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; } @@ -906,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; } diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 4bdd9720e9e..59a65cbc6db 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -96,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 :-( @@ -320,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 @@ -341,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 @@ -353,9 +345,7 @@ struct pci9118_private { * divisors for start of measure * on external start */ - unsigned int ai_data_len; unsigned short ao_data[2]; /* data output buffer */ - unsigned int ai_scans; /* number of scans to do */ char dma_doublebuf; /* we can use double buffering */ unsigned int dma_actbuf; /* which buffer is used now */ unsigned short *dmabuf_virt[2]; /* @@ -372,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 @@ -411,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, @@ -468,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; @@ -552,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 */ @@ -571,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; @@ -589,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 */ @@ -597,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; @@ -705,10 +671,11 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev, 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++) { @@ -729,13 +696,14 @@ static int move_block_from_dma(struct comedi_device *dev, 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)); @@ -783,47 +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, + 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); */ @@ -847,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); /* @@ -874,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; @@ -911,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; } @@ -931,7 +901,7 @@ static void pci9118_ai_munge(struct comedi_device *dev, 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; @@ -946,10 +916,9 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, unsigned short int_daq) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned short sampl; - s->async->events = 0; - if (int_adstat & devpriv->ai_maskerr) if (pci9118_decode_error_status(dev, s, int_adstat)) return; @@ -957,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, @@ -965,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, @@ -996,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) @@ -1037,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; @@ -1066,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->read_subdev, 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; @@ -1149,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); @@ -1166,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 */ @@ -1222,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); @@ -1260,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); @@ -1278,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, + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, &divisor1, &divisor2, - &cmd->scan_begin_arg, cmd->flags); - 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->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, + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, &divisor1, &divisor2, - &cmd->convert_arg, cmd->flags); - 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->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); } } @@ -1331,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? */ @@ -1361,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", @@ -1381,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", @@ -1417,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 @@ -1428,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; } } @@ -1443,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 @@ -1501,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 */ @@ -1521,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); @@ -1535,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: @@ -1549,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; @@ -1581,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); @@ -1591,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); @@ -1611,12 +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_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; @@ -1630,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 @@ -1662,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) { @@ -1678,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 @@ -1704,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 */ @@ -1721,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 */ @@ -1730,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 */ @@ -1766,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) && @@ -1788,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) @@ -1799,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, @@ -1825,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); @@ -1846,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); /* @@ -1889,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; @@ -1936,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) @@ -1994,8 +1869,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, 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]); @@ -2038,7 +1911,7 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, /* Enable parity check for parity error */ if (!disable_irq && pcidev->irq) { - ret = request_irq(pcidev->irq, interrupt_pci9118, IRQF_SHARED, + ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED, dev->board_name, dev); if (ret == 0) dev->irq = pcidev->irq; @@ -2097,23 +1970,11 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, s->range_table = &range_digital; s->insn_bits = pci9118_insn_bits_do; - devpriv->valid = 1; - devpriv->i8254_osc_base = I8254_OSC_BASE_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; - } - - pci9118_report_attach(dev, dev->irq); return 0; } @@ -2176,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); diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 3190ef7d285..b4ea37704ea 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -94,8 +94,6 @@ If you do not specify any options, they will default to /* mask of the bit at STINR to check end of conversion */ #define ADQ12B_EOC 0x20 -#define TIMEOUT 20 - /* available ranges through the PGA gains */ static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, { @@ -122,19 +120,28 @@ struct adq12b_private { int last_range; }; -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int adq12b_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + ADQ12B_STINR); + if (status & ADQ12B_EOC) + return 0; + return -EBUSY; +} static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct adq12b_private *devpriv = dev->private; - int n, i; + int n; int range, channel; unsigned char hi, lo, status; + int ret; /* change channel and range only if it is different from the previous */ range = CR_RANGE(insn->chanspec); @@ -151,13 +158,9 @@ static int adq12b_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* wait for end of conversion */ - i = 0; - do { - /* udelay(1); */ - status = inb(dev->iobase + ADQ12B_STINR); - status = status & ADQ12B_EOC; - } while (status == 0 && ++i < TIMEOUT); - /* } while (++i < 10); */ + ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0); + if (ret) + return ret; /* read data */ hi = inb(dev->iobase + ADQ12B_ADHIG); diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index d9ad2c0fdda..602b7a1e40e 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -51,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 @@ -73,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 */ @@ -298,29 +297,18 @@ 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 */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; unsigned short ao_data[4]; /* data output buffer */ unsigned int cnt0_write_wait; /* after a write, wait for update of the * internal state */ @@ -334,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, @@ -401,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 */ @@ -411,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); @@ -429,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 */ @@ -451,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; } /* @@ -565,20 +570,18 @@ static int pci171x_insn_bits_do(struct comedi_device *dev, 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); } } @@ -721,100 +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->read_subdev; - int m; -#ifdef PCI171x_PARANOIDCHECK - const struct boardtype *this_board = comedi_board(dev); - unsigned 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) { - dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", 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) { + if (status & Status_FF) { dev_dbg(dev->class_dev, - "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); - pci171x_ai_cancel(dev, s); + "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; + } + + comedi_buf_put(s, val & s->maxdata); - if (s->async->cur_chan >= devpriv->ai_n_chan) + 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); } /* @@ -824,76 +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); - unsigned short 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]) { - dev_dbg(dev->class_dev, - "A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n", - (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->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; int m, samplesinbuf; m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (m & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } 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; @@ -904,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); } /* @@ -924,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 */ @@ -941,95 +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); 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; @@ -1045,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 */ @@ -1094,64 +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); - 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 */ + /* Step 5: check channel list */ - if (cmd->chanlist) { - if (!check_channel_list(dev, s, cmd->chanlist, - cmd->chanlist_len)) - return 5; /* incorrect channels list */ - } + err |= pci171x_ai_check_chanlist(dev, s, cmd); - 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; - - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; - - 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; } /* @@ -1167,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 */ @@ -1292,7 +1178,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, s->do_cmd = pci171x_ai_cmd; s->cancel = pci171x_ai_cancel; } - devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ; 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; } diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 72394267ddf..07b107d1ab3 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -280,8 +280,6 @@ static int pci1723_auto_attach(struct comedi_device *dev, pci1723_reset(dev); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index d4bd61d84da..2d966a87f2e 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -1130,10 +1130,12 @@ static int pci_dio_auto_attach(struct comedi_device *dev, for (i = 0; i < MAX_DIO_SUBDEVG; i++) for (j = 0; j < this_board->sdio[i].regs; j++) { s = &dev->subdevices[subdev]; - subdev_8255_init(dev, s, NULL, - dev->iobase + - this_board->sdio[i].addr + - SIZE_8255 * j); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + + this_board->sdio[i].addr + + SIZE_8255 * j); + if (ret) + return ret; subdev++; } diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index 68c3fb3226c..324746b1493 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -101,14 +101,27 @@ struct aio12_8_private { unsigned int ao_readback[4]; }; +static int aio_aio12_8_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + AIO12_8_STATUS_REG); + if (status & AIO12_8_STATUS_ADC_EOC) + return 0; + return -EBUSY; +} + static int aio_aio12_8_ai_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val; unsigned char control; + int ret; int n; /* @@ -122,20 +135,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, inb(dev->iobase + AIO12_8_STATUS_REG); for (n = 0; n < insn->n; n++) { - int timeout = 5; - /* Setup and start conversion */ outb(control, dev->iobase + AIO12_8_ADC_REG); /* Wait for conversion to complete */ - do { - val = inb(dev->iobase + AIO12_8_STATUS_REG); - timeout--; - if (timeout == 0) { - dev_err(dev->class_dev, "ADC timeout\n"); - return -ETIMEDOUT; - } - } while (!(val & AIO12_8_STATUS_ADC_EOC)); + ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0); + if (ret) + return ret; data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; } @@ -247,9 +253,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev, /* 8254 counter/timer subdevice */ s->type = COMEDI_SUBD_UNUSED; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 22b3dda135f..781104aa533 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -98,7 +98,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = aio_iiro_16_dio_insn_bits_read; - return 1; + return 0; } static struct comedi_driver aio_iiro_16_driver = { diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index 9c9559ffc64..3edaa4028da 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -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) { @@ -516,28 +510,16 @@ static int dio200_subdev_intr_cmd(struct comedi_device *dev, 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]); @@ -1208,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_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 31734e1142f..c9a96ad0055 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -314,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) @@ -361,39 +361,13 @@ static irqreturn_t pc236_interrupt(int irq, void *d) 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) { @@ -411,10 +385,9 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s = &dev->subdevices[0]; /* digital i/o subdevice (8255) */ ret = subdev_8255_init(dev, s, NULL, iobase); - if (ret < 0) { - dev_err(dev->class_dev, "error! out of memory!\n"); + if (ret) return ret; - } + s = &dev->subdevices[1]; dev->read_subdev = s; s->type = COMEDI_SUBD_UNUSED; @@ -429,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, diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 5b4b5ab34e2..7c10d28d278 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -94,8 +94,6 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (base %#lx) attached\n", dev->board_name, - dev->iobase); return 0; } diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index ae4048a624f..339c47c1eb9 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -377,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; }; @@ -467,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, @@ -531,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); @@ -557,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; @@ -583,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; @@ -605,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) @@ -627,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) { /* @@ -670,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; @@ -691,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 @@ -704,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 */ @@ -731,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) @@ -771,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. */ @@ -825,98 +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 = I8254_OSC_BASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = I8254_OSC_BASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) / - I8254_OSC_BASE_10MHZ; - if (div2 <= 0x10000) { - /* A single timer will suffice. */ - if (div2 < 2) - div2 = 2; - cmd->scan_begin_arg = div2 * I8254_OSC_BASE_10MHZ; - if (cmd->scan_begin_arg < div2 || - cmd->scan_begin_arg < I8254_OSC_BASE_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(I8254_OSC_BASE_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) { - dev_dbg(dev->class_dev, - "%s: entries in chanlist must contain no duplicate channels\n", - __func__); - } - if (errors & range_err) { - dev_dbg(dev->class_dev, - "%s: entries in chanlist must all have the same range index\n", - __func__); - } - 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; @@ -924,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; @@ -982,106 +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 = I8254_OSC_BASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = I8254_OSC_BASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) / - I8254_OSC_BASE_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(I8254_OSC_BASE_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; } @@ -1105,7 +980,7 @@ 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; + struct comedi_cmd *cmd = &s->async->cmd; unsigned short *array = data; unsigned int length = num_bytes / sizeof(*array); unsigned int offset; @@ -1115,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; @@ -1237,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. */ @@ -1399,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) diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index c08dfbbe406..3895bc7cb3e 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -519,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 @@ -799,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); @@ -883,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); @@ -951,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) { @@ -1063,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) { - dev_dbg(dev->class_dev, - "%s: channel numbers must increase\n", - __func__); - } - if ((errors & range_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channels must have the same range\n", - __func__); - } - } - } + /* 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; @@ -1173,11 +1160,11 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, 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); @@ -1188,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. */ @@ -1210,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; @@ -1263,13 +1248,13 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, for (i = 0; i < cmd->chanlist_len; i++) { 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 @@ -1347,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); @@ -1432,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; @@ -1458,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 */ @@ -1550,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) { @@ -1738,136 +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) { - dev_dbg(dev->class_dev, - "%s: channel numbers must increase or sequence must repeat exactly\n", - __func__); - } - if ((errors & rangepair_err) != 0) { - dev_dbg(dev->class_dev, - "%s: single-ended channel pairs must have the same range\n", - __func__); - } - if ((errors & polarity_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channel sequence ranges must be all bipolar or all unipolar\n", - __func__); - } - if ((errors & aref_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channel sequence analogue references must be all the same (single-ended or differential)\n", - __func__); - } - if ((errors & diffchan_err) != 0) { - dev_dbg(dev->class_dev, - "%s: differential channel number out of range 0 to %u\n", - __func__, (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; } @@ -2762,14 +2718,14 @@ static int pci230_attach_common(struct comedi_device *dev, /* digital i/o subdevice */ if (thisboard->have_dio) { rc = subdev_8255_init(dev, s, NULL, - (devpriv->iobase1 + PCI230_PPI_X_BASE)); - if (rc < 0) + devpriv->iobase1 + PCI230_PPI_X_BASE); + if (rc) return rc; } else { s->type = COMEDI_SUBD_UNUSED; } - dev_info(dev->class_dev, "attached\n"); - return 1; + + return 0; } static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index be28e6cbea2..93ed03ee416 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -84,8 +84,6 @@ static int pci263_auto_attach(struct comedi_device *dev, /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (pci %s) attached\n", dev->board_name, - pci_name(pci_dev)); return 0; } diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index 5034f663eec..e03dd6e7141 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -1,34 +1,33 @@ /* - comedi/drivers/c6xdigio.c - - Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. - (http://robot0.ge.uiuc.edu/~spong/mecha/) - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Dan Block - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * c6xdigio.c + * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. + * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/ + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Dan Block + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: c6xdigio -Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card -Author: Dan Block -Status: unknown -Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio) -Updated: Sun Nov 20 20:18:34 EST 2005 - -This driver will not work with a 2.4 kernel. -http://robot0.ge.uiuc.edu/~spong/mecha/ -*/ +/* + * Driver: c6xdigio + * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card + * Author: Dan Block + * Status: unknown + * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio] + * Updated: Sun Nov 20 20:18:34 EST 2005 + * + * Configuration Options: + * [0] - base address + */ #include <linux/kernel.h> #include <linux/module.h> @@ -43,309 +42,194 @@ http://robot0.ge.uiuc.edu/~spong/mecha/ #include "../comedidev.h" -static u8 ReadByteFromHwPort(unsigned long addr) -{ - u8 result = inb(addr); - return result; -} - -static void WriteByteToHwPort(unsigned long addr, u8 val) -{ - outb_p(val, addr); -} - -#define C6XDIGIO_SIZE 3 - /* - * port offsets + * Register I/O map */ -#define C6XDIGIO_PARALLEL_DATA 0 -#define C6XDIGIO_PARALLEL_STATUS 1 -#define C6XDIGIO_PARALLEL_CONTROL 2 -struct pwmbitstype { - unsigned sb0:2; - unsigned sb1:2; - unsigned sb2:2; - unsigned sb3:2; - unsigned sb4:2; -}; -union pwmcmdtype { - unsigned cmd; /* assuming here that int is 32bit */ - struct pwmbitstype bits; -}; -struct encbitstype { - unsigned sb0:3; - unsigned sb1:3; - unsigned sb2:3; - unsigned sb3:3; - unsigned sb4:3; - unsigned sb5:3; - unsigned sb6:3; - unsigned sb7:3; -}; -union encvaluetype { - unsigned value; - struct encbitstype bits; -}; +#define C6XDIGIO_DATA_REG 0x00 +#define C6XDIGIO_DATA_CHAN(x) (((x) + 1) << 4) +#define C6XDIGIO_DATA_PWM (1 << 5) +#define C6XDIGIO_DATA_ENCODER (1 << 6) +#define C6XDIGIO_STATUS_REG 0x01 +#define C6XDIGIO_CTRL_REG 0x02 #define C6XDIGIO_TIME_OUT 20 -static void C6X_pwmInit(unsigned long baseAddr) +static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context) { + unsigned int status; int timeout = 0; - WriteByteToHwPort(baseAddr, 0x70); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { + do { + status = inb(dev->iobase + C6XDIGIO_STATUS_REG); + if ((status & 0x80) != context) + return 0; timeout++; - } + } while (timeout < C6XDIGIO_TIME_OUT); - WriteByteToHwPort(baseAddr, 0x74); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } + return -EBUSY; +} - WriteByteToHwPort(baseAddr, 0x70); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } +static int c6xdigio_write_data(struct comedi_device *dev, + unsigned int val, unsigned int status) +{ + outb_p(val, dev->iobase + C6XDIGIO_DATA_REG); + return c6xdigio_chk_status(dev, status); +} - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } +static int c6xdigio_get_encoder_bits(struct comedi_device *dev, + unsigned int *bits, + unsigned int cmd, + unsigned int status) +{ + unsigned int val; + + val = inb(dev->iobase + C6XDIGIO_STATUS_REG); + val >>= 3; + val &= 0x07; + + *bits = val; + return c6xdigio_write_data(dev, cmd, status); } -static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value) +static void c6xdigio_pwm_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) { - unsigned ppcmd; - union pwmcmdtype pwm; - int timeout = 0; - unsigned tmp; - - pwm.cmd = value; - if (pwm.cmd > 498) - pwm.cmd = 498; - if (pwm.cmd < 2) - pwm.cmd = 2; - - if (channel == 0) { - ppcmd = 0x28; - } else { /* if channel == 1 */ - ppcmd = 0x30; - } /* endif */ - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan); + unsigned int bits; + + if (val > 498) + val = 498; + if (val < 2) + val = 2; + + bits = (val >> 0) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 2) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 4) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 6) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 8) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + + c6xdigio_write_data(dev, 0x00, 0x80); +} - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } +static int c6xdigio_encoder_read(struct comedi_device *dev, + unsigned int chan) +{ + unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan); + unsigned int val = 0; + unsigned int bits; - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_write_data(dev, cmd, 0x00); - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 0); - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 3); - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 6); -} + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 9); -static int C6X_encInput(unsigned long baseAddr, unsigned channel) -{ - unsigned ppcmd; - union encvaluetype enc; - int timeout = 0; - int tmp; - - enc.value = 0; - if (channel == 0) - ppcmd = 0x48; - else - ppcmd = 0x50; - - WriteByteToHwPort(baseAddr, ppcmd); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 12); - enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 15); - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 18); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 21); + + c6xdigio_write_data(dev, 0x00, 0x80); - return enc.value ^ 0x800000; + return val; } -static void C6X_encResetAll(unsigned long baseAddr) +static int c6xdigio_pwm_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned timeout = 0; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = (s->state >> (16 * chan)) & 0xffff; + int i; - WriteByteToHwPort(baseAddr, 0x68); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x6C); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x68); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; + for (i = 0; i < insn->n; i++) { + val = data[i]; + c6xdigio_pwm_write(dev, chan, val); } + + /* + * There are only 2 PWM channels and they have a maxdata of 500. + * Instead of allocating private data to save the values in for + * readback this driver just packs the values for the two channels + * in the s->state. + */ + s->state &= (0xffff << (16 * chan)); + s->state |= (val << (16 * chan)); + + return insn->n; } -static int c6xdigio_pwmo_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int c6xdigio_pwm_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; int i; - int chan = CR_CHAN(insn->chanspec); - for (i = 0; i < insn->n; i++) { - C6X_pwmOutput(dev->iobase, chan, data[i]); - /* devpriv->ao_readback[chan] = data[i]; */ - } - return i; + val = (s->state >> (16 * chan)) & 0xffff; + + for (i = 0; i < insn->n; i++) + data[i] = val; + + return insn->n; } -static int c6xdigio_ei_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int c6xdigio_encoder_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - for (n = 0; n < insn->n; n++) - data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff); + for (i = 0; i < insn->n; i++) { + val = c6xdigio_encoder_read(dev, chan); + + /* munge two's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); + } - return n; + return insn->n; } -static void board_init(struct comedi_device *dev) +static void c6xdigio_init(struct comedi_device *dev) { - C6X_pwmInit(dev->iobase); - C6X_encResetAll(dev->iobase); + /* Initialize the PWM */ + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x74, 0x80); + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); + + /* Reset the encoders */ + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x6c, 0x80); + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); } static const struct pnp_device_id c6xdigio_pnp_tbl[] = { @@ -367,7 +251,7 @@ static int c6xdigio_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], C6XDIGIO_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x03); if (ret) return ret; @@ -380,27 +264,26 @@ static int c6xdigio_attach(struct comedi_device *dev, s = &dev->subdevices[0]; /* pwm output subdevice */ - s->type = COMEDI_SUBD_AO; /* Not sure what to put here */ - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_pwmo; */ - s->insn_write = c6xdigio_pwmo_insn_write; - s->maxdata = 500; - s->range_table = &range_bipolar10; /* A suitable lie */ + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 500; + s->range_table = &range_unknown; + s->insn_write = c6xdigio_pwm_insn_write; + s->insn_read = c6xdigio_pwm_insn_read; s = &dev->subdevices[1]; /* encoder (counter) subdevice */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_ei; */ - s->insn_read = c6xdigio_ei_insn_read; - s->maxdata = 0xffffff; - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = 2; + s->maxdata = 0xffffff; + s->range_table = &range_unknown; + s->insn_read = c6xdigio_encoder_insn_read; /* I will call this init anyway but more than likely the DSP board */ /* will not be connected when device driver is loaded. */ - board_init(dev); + c6xdigio_init(dev); return 0; } @@ -420,5 +303,5 @@ static struct comedi_driver c6xdigio_driver = { module_comedi_driver(c6xdigio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 64d5f291553..eb1b92d72e8 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -95,10 +95,17 @@ static const struct comedi_lrange das16cs_ai_range = { } }; -static irqreturn_t das16cs_interrupt(int irq, void *d) +static int das16cs_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - /* struct comedi_device *dev = d; */ - return IRQ_HANDLED; + unsigned int status; + + status = inw(dev->iobase + DAS16CS_MISC1); + if (status & 0x0080) + return 0; + return -EBUSY; } static int das16cs_ai_rinsn(struct comedi_device *dev, @@ -109,8 +116,8 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); + int ret; int i; - int to; outw(chan, dev->iobase + DAS16CS_DIO_MUX); @@ -138,132 +145,16 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outw(0, dev->iobase + DAS16CS_ADC_DATA); -#define TIMEOUT 1000 - for (to = 0; to < TIMEOUT; to++) { - if (inw(dev->iobase + DAS16CS_MISC1) & 0x0080) - break; - } - if (to == TIMEOUT) { - dev_dbg(dev->class_dev, "cb_das16_cs: ai timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0); + if (ret) + return ret; + data[i] = inw(dev->iobase + DAS16CS_ADC_DATA); } return i; } -static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - return -EINVAL; -} - -static int das16cs_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int tmp; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - -#define MAX_SPEED 10000 /* in nanoseconds */ -#define MIN_SPEED 1000000000 /* in nanoseconds */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); - } - if (cmd->convert_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* see above */ - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); - } - - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - if (cmd->stop_src == TRIG_COUNT) - err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); - else /* TRIG_NONE */ - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } - - if (err) - return 4; - - return 0; -} - static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -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); @@ -401,10 +293,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, dev->iobase = link->resource[0]->start; link->priv = dev; - ret = pcmcia_request_irq(link, das16cs_interrupt); - if (ret) - return ret; - dev->irq = link->irq; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -415,7 +303,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; @@ -424,8 +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 */ @@ -451,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 9819be092f8..7377da1aff7 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -376,6 +376,20 @@ static inline unsigned int cal_enable_bits(struct comedi_device *dev) return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); } +static int cb_pcidas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned int status; + + status = inw(devpriv->control_status + ADCMUX_CONT); + if (status & EOC) + return 0; + return -EBUSY; +} + static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -385,7 +399,8 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned int bits; - int n, i; + int ret; + int n; /* enable calibration input if appropriate */ if (insn->chanspec & CR_ALT_SOURCE) { @@ -415,13 +430,9 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, outw(0, devpriv->adc_fifo + ADCDATA); /* wait for conversion to end */ - /* return -ETIMEDOUT if there is a timeout */ - for (i = 0; i < 10000; i++) { - if (inw(devpriv->control_status + ADCMUX_CONT) & EOC) - break; - } - if (i == 10000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(devpriv->adc_fifo + ADCDATA); @@ -792,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) @@ -799,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 */ @@ -835,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 @@ -851,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) @@ -875,45 +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; + arg = cmd->scan_begin_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, &devpriv->divisor1, &devpriv->divisor2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; + &arg, cmd->flags); + 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; i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, &devpriv->divisor1, &devpriv->divisor2, - &cmd->convert_arg, cmd->flags); - if (tmp != cmd->convert_arg) - err++; + &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; @@ -921,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(I8254_OSC_BASE_10MHZ, - &devpriv->divisor1, &devpriv->divisor2, - ns, rounding_flags); + 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, @@ -972,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) @@ -1006,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) @@ -1016,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; @@ -1027,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) @@ -1034,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 */ @@ -1077,27 +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; + arg = cmd->scan_begin_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, &devpriv->ao_divisor1, &devpriv->ao_divisor2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; + &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; @@ -1137,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 */ @@ -1172,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) { @@ -1201,18 +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(I8254_OSC_BASE_10MHZ, - &devpriv->ao_divisor1, - &devpriv->ao_divisor2, - &cmd->scan_begin_arg, cmd->flags); + if (cmd->scan_begin_src == TRIG_TIMER) + cb_pcidas_ao_load_counters(dev); - /* 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); - } /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg; @@ -1269,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); @@ -1282,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; @@ -1300,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, @@ -1312,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) @@ -1322,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; @@ -1332,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); @@ -1355,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; } @@ -1364,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, @@ -1381,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; } @@ -1411,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; } @@ -1576,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; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 4fff1738e3f..035c3a17600 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1664,15 +1664,36 @@ static void i2c_write(struct comedi_device *dev, unsigned int address, i2c_stop(dev); } +static int cb_pcidas64_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->main_iobase + HW_STATUS_REG); + if (thisboard->layout == LAYOUT_4020) { + status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG); + if (status) + return 0; + } else { + if (pipe_full_bits(status)) + return 0; + } + return -EBUSY; +} + static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct pcidas64_board *thisboard = comedi_board(dev); struct pcidas64_private *devpriv = dev->private; - unsigned int bits = 0, n, i; + unsigned int bits = 0, n; unsigned int channel, range, aref; unsigned long flags; - static const int timeout = 100; + int ret; channel = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -1770,23 +1791,10 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->main_iobase + ADC_CONVERT_REG); /* wait for data */ - for (i = 0; i < timeout; i++) { - bits = readw(devpriv->main_iobase + HW_STATUS_REG); - if (thisboard->layout == LAYOUT_4020) { - if (readw(devpriv->main_iobase + - ADC_WRITE_PNTR_REG)) - break; - } else { - if (pipe_full_bits(bits)) - break; - } - udelay(1); - } - if (i == timeout) { - comedi_error(dev, " analog input read insn timed out"); - dev_info(dev->class_dev, "status 0x%x\n", bits); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0); + if (ret) + return ret; + if (thisboard->layout == LAYOUT_4020) data[n] = readl(devpriv->dio_counter_iobase + ADC_FIFO_REG) & 0xffff; @@ -1987,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 */ @@ -2032,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); @@ -2090,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; @@ -2695,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; @@ -2716,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; @@ -2865,7 +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); - 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) @@ -3176,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; } @@ -3196,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); @@ -3218,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; } @@ -3239,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 */ @@ -3277,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); @@ -3307,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; @@ -3816,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]; diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 8cca0518cfd..901dc5d1bb7 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -388,8 +388,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, for (i = 0; i < thisboard->ao_chans; i++) cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index 57295d189ff..50e522e6e69 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -31,7 +31,8 @@ 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. */ @@ -85,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 */ @@ -118,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 @@ -133,17 +148,10 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outw(0, dev->iobase + 0); -#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */ - /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */ - /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - busy = inb(devpriv->BADR3 + 2) & 0x80; - if (!busy) - break; - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(dev->iobase + 0); @@ -247,9 +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; } diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 43a86630a66..4a2b200de01 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -187,9 +187,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, if (ret) return ret; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - - return 1; + return 0; } static struct comedi_driver cb_pcimdda_driver = { diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 51a59e5b8ec..8450c99af8b 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -211,7 +211,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) return -EINVAL; } - snprintf(file, sizeof(file), "/dev/comedi%u", minor); + snprintf(file, sizeof(file), "/dev/comedi%d", minor); file[sizeof(file) - 1] = 0; d = comedi_open(file); @@ -254,6 +254,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) if (!devs) { dev_err(dev->class_dev, "Could not allocate memory. Out of memory?\n"); + kfree(bdev); return -ENOMEM; } devpriv->devs = devs; @@ -263,7 +264,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) char buf[20]; int left = MAX_BOARD_NAME - strlen(devpriv->name) - 1; - snprintf(buf, sizeof(buf), "%d:%d ", + snprintf(buf, sizeof(buf), "%u:%u ", bdev->minor, bdev->subdev); buf[sizeof(buf) - 1] = 0; strncat(devpriv->name, buf, left); diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c index 26d9dbcf8bd..c33c3e5680a 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ b/drivers/staging/comedi/drivers/comedi_fc.c @@ -1,34 +1,53 @@ /* - comedi/drivers/comedi_fc.c - - This is a place for code driver writers wish to share between - two or more drivers. fc is short - for frank-common. - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi_fc.c + * This is a place for code driver writers wish to share between + * two or more drivers. fc is short for frank-common. + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #include <linux/module.h> #include "../comedidev.h" #include "comedi_fc.h" -static void increment_scan_progress(struct comedi_subdevice *subd, - unsigned int num_bytes) +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) { - 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) { @@ -36,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 8558b07f8df..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, +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 9de81c7712f..a4274869235 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -181,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) @@ -229,7 +229,7 @@ static irqreturn_t parport_interrupt(int irq, void *d) 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); @@ -295,6 +295,7 @@ static int parport_attach(struct comedi_device *dev, 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; diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index d539eaf53b6..67a09aa6b72 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -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; @@ -418,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 323a7f39cd9..0a9c32e9db4 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -92,8 +92,6 @@ static int contec_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = contec_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c new file mode 100644 index 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 ce153fcb8b2..a8f6036ad82 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -333,14 +333,28 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) writeAcqScanListEntry(dev, word3); } +static int daqboard2000_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->daq + acqControl); + if (status & context) + return 0; + return -EBUSY; +} + static int daqboard2000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct daqboard2000_private *devpriv = dev->private; - unsigned int val; - int gain, chan, timeout; + int gain, chan; + int ret; int i; writew(DAQBOARD2000_AcqResetScanListFifo | @@ -367,25 +381,24 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, /* Enable reading from the scanlist FIFO */ writew(DAQBOARD2000_SeqStartScanList, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqConfigPipeFull) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqConfigPipeFull); + if (ret) + return ret; + writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqLogicScanning) - break; - /* udelay(2); */ - } - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqResultsFIFOHasValidData) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqLogicScanning); + if (ret) + return ret; + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqResultsFIFOHasValidData); + if (ret) + return ret; + data[i] = readw(devpriv->daq + acqResultsFIFO); writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); @@ -409,6 +422,21 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev, return i; } +static int daqboard2000_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int status; + + status = readw(devpriv->daq + dacControl); + if ((status & ((chan + 1) * 0x0010)) == 0) + return 0; + return -EBUSY; +} + static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -416,8 +444,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, { struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); - unsigned int val; - int timeout; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -431,12 +458,11 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, udelay(1000); #endif writew(data[i], devpriv->daq + dacSetting(chan)); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + dacControl); - if ((val & ((chan + 1) * 0x0010)) == 0) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; #if 0 /* @@ -737,9 +763,6 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, if (result) return result; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index e5c0ee9a09c..c5e352fb555 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -201,17 +201,29 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; -#define TIMEOUT 100000 +static int das08_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS08_STATUS); + if ((status & DAS08_EOC) == 0) + return 0; + return -EBUSY; +} static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das08_board_struct *thisboard = comedi_board(dev); struct das08_private_struct *devpriv = dev->private; - int i, n; + int n; int chan; int range; int lsb, msb; + int ret; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -244,14 +256,10 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); - for (i = 0; i < TIMEOUT; i++) { - if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC)) - break; - } - if (i == TIMEOUT) { - dev_err(dev->class_dev, "timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0); + if (ret) + return ret; + msb = inb(dev->iobase + DAS08_MSB); lsb = inb(dev->iobase + DAS08_LSB); if (thisboard->ai_encoding == das08_encode12) { @@ -529,9 +537,10 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s = &dev->subdevices[4]; /* 8255 */ if (thisboard->i8255_offset != 0) { - subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase + - thisboard-> - i8255_offset)); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + thisboard->i8255_offset); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index 46a314c5113..18cc170facd 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -40,7 +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_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/das16.c b/drivers/staging/comedi/drivers/das16.c index a8446ca0411..2feecf199f2 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -600,29 +600,56 @@ static void das16_timer_interrupt(unsigned long arg) 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; + trig_mask = TRIG_FOLLOW; if (devpriv->can_burst) - mask |= TRIG_TIMER | TRIG_EXT; - err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask); + 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; + trig_mask = TRIG_TIMER | TRIG_EXT; if (devpriv->can_burst) - mask |= TRIG_NOW; - err |= cfc_check_trigger_src(&cmd->convert_src, mask); + 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); @@ -673,44 +700,28 @@ 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 */ + arg = cmd->scan_begin_arg; i8253_cascade_ns_to_timer(devpriv->clockbase, &devpriv->divisor1, &devpriv->divisor2, - &cmd->scan_begin_arg, cmd->flags); - err += (tmp != cmd->scan_begin_arg); + &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 */ + arg = cmd->convert_arg; i8253_cascade_ns_to_timer(devpriv->clockbase, &devpriv->divisor1, &devpriv->divisor2, - &cmd->convert_arg, cmd->flags); - err += (tmp != cmd->convert_arg); + &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) { - dev_err(dev->class_dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - dev_err(dev->class_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; @@ -727,9 +738,10 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, &devpriv->divisor1, &devpriv->divisor2, &ns, rounding_flags); - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(timer_base, 0, 1, devpriv->divisor1, 2); - i8254_load(timer_base, 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; } @@ -750,8 +762,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) 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); if (devpriv->can_burst) outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG); @@ -856,18 +867,17 @@ static void das16_ai_munge(struct comedi_device *dev, } } -static int das16_ai_wait_for_conv(struct comedi_device *dev, - unsigned int timeout) +static int das16_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; - int i; - for (i = 0; i < timeout; i++) { - status = inb(dev->iobase + DAS16_STATUS_REG); - if (!(status & DAS16_STATUS_BUSY)) - return 0; - } - return -ETIME; + status = inb(dev->iobase + DAS16_STATUS_REG); + if ((status & DAS16_STATUS_BUSY) == 0) + return 0; + return -EBUSY; } static int das16_ai_insn_read(struct comedi_device *dev, @@ -897,7 +907,7 @@ static int das16_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ outb_p(0, dev->iobase + DAS16_TRIG_REG); - ret = das16_ai_wait_for_conv(dev, 1000); + ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index fee5facff8d..ec039fbff0f 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -150,11 +150,40 @@ static void munge_sample_array(unsigned 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 */ @@ -203,35 +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 */ + arg = cmd->convert_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, &devpriv->divisor1, &devpriv->divisor2, - &cmd->convert_arg, cmd->flags); - if (tmp != cmd->convert_arg) - err++; + &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; @@ -239,26 +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(I8254_OSC_BASE_10MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &ns, rounding_flags); - - /* 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, @@ -267,6 +271,7 @@ 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; /* disable interrupts and internal pacer */ @@ -278,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); @@ -292,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; @@ -308,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); @@ -331,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; @@ -356,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)); } @@ -407,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 */ @@ -440,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; } } @@ -449,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) diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 320d95a5f47..859519026c4 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -547,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; @@ -646,7 +646,6 @@ static void das1800_ai_handler(struct comedi_device *dev) struct comedi_cmd *cmd = &async->cmd; unsigned int status = inb(dev->iobase + DAS1800_STATUS); - async->events = 0; /* select adc for base address + 0 */ outb(ADC, dev->iobase + DAS1800_SELECT); /* dma buffer full */ @@ -665,9 +664,8 @@ static void das1800_ai_handler(struct comedi_device *dev) /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); comedi_error(dev, "DAS1800 FIFO overflow"); - das1800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } /* stop taking data if appropriate */ @@ -680,16 +678,12 @@ static void das1800_ai_handler(struct comedi_device *dev) das1800_flush_dma(dev, s); else das1800_handle_fifo_not_empty(dev, s); - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */ - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - - return; + cfc_handle_events(dev, s); } static int das1800_ai_poll(struct comedi_device *dev, @@ -737,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; @@ -746,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; @@ -763,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, @@ -771,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 */ @@ -831,66 +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 */ + 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++; + } + + arg = cmd->scan_begin_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, &devpriv->divisor1, &devpriv->divisor2, - &cmd->convert_arg, + &cmd->scan_begin_arg, cmd->flags); - if (tmp_arg != cmd->convert_arg) + if (arg != cmd->scan_begin_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) - 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(I8254_OSC_BASE_5MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->scan_begin_arg, - cmd->flags); - if (tmp_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; @@ -968,68 +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; + unsigned long timer_base = dev->iobase + DAS1800_COUNTER; - return 0; -} + /* 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); -/* 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 */ - 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(I8254_OSC_BASE_5MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &period, cmd->flags); - 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(I8254_OSC_BASE_5MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &period, cmd->flags); - 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' */ @@ -1142,7 +1097,6 @@ 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; @@ -1173,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 */ @@ -1476,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]; diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 43027ee500e..d18eea6c01a 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -1,309 +1,532 @@ /* - Some comments on the code.. - - - it shouldn't be necessary to use outb_p(). - - - ignoreirq creates a race condition. It needs to be fixed. - + * das6402.c + * Comedi driver for DAS6402 compatible boards + * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Rewrite of an experimental driver by: + * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* - comedi/drivers/das6402.c - An experimental driver for Computerboards' DAS6402 I/O card + * Driver: das6402 + * Description: Keithley Metrabyte DAS6402 (& compatibles) + * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12) + * (Keithley Metrabyte) DAS6402-16 (das6402-16) + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Fri, 14 Mar 2014 10:18:43 -0700 + * Status: unknown + * + * Configuration Options: + * [0] - I/O base address + * [1] - IRQ (optional, needed for async command support) + */ - Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> +#include <linux/module.h> +#include <linux/interrupt.h> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +#include "../comedidev.h" +#include "8253.h" - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - */ /* -Driver: das6402 -Description: Keithley Metrabyte DAS6402 (& compatibles) -Author: Oystein Svendsen <svendsen@pvv.org> -Status: bitrotten -Devices: [Keithley Metrabyte] DAS6402 (das6402) + * Register I/O map + */ +#define DAS6402_AI_DATA_REG 0x00 +#define DAS6402_AI_MUX_REG 0x02 +#define DAS6402_AI_MUX_LO(x) (((x) & 0x3f) << 0) +#define DAS6402_AI_MUX_HI(x) (((x) & 0x3f) << 8) +#define DAS6402_DI_DO_REG 0x03 +#define DAS6402_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define DAS6402_STATUS_REG 0x08 +#define DAS6402_STATUS_FFNE (1 << 0) +#define DAS6402_STATUS_FHALF (1 << 1) +#define DAS6402_STATUS_FFULL (1 << 2) +#define DAS6402_STATUS_XINT (1 << 3) +#define DAS6402_STATUS_INT (1 << 4) +#define DAS6402_STATUS_XTRIG (1 << 5) +#define DAS6402_STATUS_INDGT (1 << 6) +#define DAS6402_STATUS_10MHZ (1 << 7) +#define DAS6402_STATUS_W_CLRINT (1 << 0) +#define DAS6402_STATUS_W_CLRXTR (1 << 1) +#define DAS6402_STATUS_W_CLRXIN (1 << 2) +#define DAS6402_STATUS_W_EXTEND (1 << 4) +#define DAS6402_STATUS_W_ARMED (1 << 5) +#define DAS6402_STATUS_W_POSTMODE (1 << 6) +#define DAS6402_STATUS_W_10MHZ (1 << 7) +#define DAS6402_CTRL_REG 0x09 +#define DAS6402_CTRL_SOFT_TRIG (0 << 0) +#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0) +#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0) +#define DAS6402_CTRL_PACER_TRIG (3 << 0) +#define DAS6402_CTRL_BURSTEN (1 << 2) +#define DAS6402_CTRL_XINTE (1 << 3) +#define DAS6402_CTRL_IRQ(x) ((x) << 4) +#define DAS6402_CTRL_INTE (1 << 7) +#define DAS6402_TRIG_REG 0x0a +#define DAS6402_TRIG_TGEN (1 << 0) +#define DAS6402_TRIG_TGSEL (1 << 1) +#define DAS6402_TRIG_TGPOL (1 << 2) +#define DAS6402_TRIG_PRETRIG (1 << 3) +#define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4)) +#define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4)) +#define DAS6402_MODE_REG 0x0b +#define DAS6402_MODE_RANGE(x) ((x) << 0) +#define DAS6402_MODE_POLLED (0 << 2) +#define DAS6402_MODE_FIFONEPTY (1 << 2) +#define DAS6402_MODE_FIFOHFULL (2 << 2) +#define DAS6402_MODE_EOB (3 << 2) +#define DAS6402_MODE_ENHANCED (1 << 4) +#define DAS6402_MODE_SE (1 << 5) +#define DAS6402_MODE_UNI (1 << 6) +#define DAS6402_MODE_DMA1 (0 << 7) +#define DAS6402_MODE_DMA3 (1 << 7) +#define DAS6402_TIMER_BASE 0x0c + +static const struct comedi_lrange das6402_ai_ranges = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } +}; -This driver has suffered bitrot. -*/ +/* + * Analog output ranges are programmable on the DAS6402/12. + * For the DAS6402/16 the range bits have no function, the + * DAC ranges are selected by switches on the board. + */ +static const struct comedi_lrange das6402_ao_ranges = { + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } +}; -#include <linux/module.h> -#include <linux/interrupt.h> -#include "../comedidev.h" +struct das6402_boardinfo { + const char *name; + unsigned int maxdata; +}; -#define DAS6402_SIZE 16 - -#define N_WORDS (3000*64) - -#define STOP 0 -#define START 1 - -#define SCANL 0x3f00 -#define BYTE unsigned char -#define WORD unsigned short - -/*----- register 8 ----*/ -#define CLRINT 0x01 -#define CLRXTR 0x02 -#define CLRXIN 0x04 -#define EXTEND 0x10 -#define ARMED 0x20 /* enable conting of post sample conv */ -#define POSTMODE 0x40 -#define MHZ 0x80 /* 10 MHz clock */ -/*---------------------*/ - -/*----- register 9 ----*/ -#define IRQ (0x04 << 4) /* these two are */ -#define IRQV 10 /* dependent on each other */ - -#define CONVSRC 0x03 /* trig src is Intarnal pacer */ -#define BURSTEN 0x04 /* enable burst */ -#define XINTE 0x08 /* use external int. trig */ -#define INTE 0x80 /* enable analog interrupts */ -/*---------------------*/ - -/*----- register 10 ---*/ -#define TGEN 0x01 /* Use pin DI1 for externl trigging? */ -#define TGSEL 0x02 /* Use edge triggering */ -#define TGPOL 0x04 /* active edge is falling */ -#define PRETRIG 0x08 /* pretrig */ -/*---------------------*/ - -/*----- register 11 ---*/ -#define EOB 0x0c -#define FIFOHFULL 0x08 -#define GAIN 0x01 -#define FIFONEPTY 0x04 -#define MODE 0x10 -#define SEM 0x20 -#define BIP 0x40 -/*---------------------*/ - -#define M0 0x00 -#define M2 0x04 - -#define C0 0x00 -#define C1 0x40 -#define C2 0x80 -#define RWLH 0x30 +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; - } + if (load) { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY); - das6402_ai_fifo_dregs(dev, s); + i8254_write(timer_iobase, 0, 0, devpriv->count); + i8254_write(timer_iobase, 0, 1, devpriv->divider1); + i8254_write(timer_iobase, 0, 2, devpriv->divider2); - if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) { - outw_p(SCANL, dev->iobase + 2); /* clears the fifo */ - outb(0x07, dev->iobase + 8); /* clears all flip-flops */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + } else { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY); } +} - outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */ +static irqreturn_t das6402_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + + das6402_clear_all_interrupts(dev); - comedi_event(dev, s); return IRQ_HANDLED; } -#if 0 -static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) +static int das6402_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { - int i; + return -EINVAL; +} - for (i = 0; i < n; i++) - data[i] = inw(dev->iobase); +static int das6402_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + return -EINVAL; } -#endif static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + return 0; +} + +static void das6402_ai_soft_trig(struct comedi_device *dev) +{ + outw(0, dev->iobase + DAS6402_AI_DATA_REG); +} + +static int das6402_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS6402_STATUS_REG); + if (status & DAS6402_STATUS_FFNE) + return 0; + return -EBUSY; +} + +static int das6402_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned int val; + int ret; + int i; + + val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED; + if (aref == AREF_DIFF) { + if (chan > s->n_chan / 2) + return -EINVAL; + } else { + val |= DAS6402_MODE_SE; + } + if (comedi_range_is_unipolar(s, range)) + val |= DAS6402_MODE_UNI; + + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + das6402_set_mode(dev, val); + + /* load the mux for single channel conversion */ + outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan), + dev->iobase + DAS6402_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + das6402_ai_clear_eoc(dev); + das6402_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0); + if (ret) + break; + + val = inw(dev->iobase + DAS6402_AI_DATA_REG); + + if (s->maxdata == 0x0fff) + val >>= 4; + + data[i] = val; + } + + das6402_ai_clear_eoc(dev); + + return insn->n; +} + +static int das6402_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + /* set the range for this channel */ + val = devpriv->ao_range; + val &= ~DAS6402_AO_RANGE_MASK(chan); + val |= DAS6402_AO_RANGE(chan, range); + if (val != devpriv->ao_range) { + devpriv->ao_range = val; + outb(val, dev->iobase + DAS6402_TRIG_REG); + } /* - * This function should reset the board from whatever condition it - * is in (i.e., acquiring data), to a non-active state. + * The DAS6402/16 has a jumper to select either individual + * update (UPDATE) or simultaneous updating (XFER) of both + * DAC's. In UPDATE mode, when the MSB is written, that DAC + * is updated. In XFER mode, after both DAC's are loaded, + * a read cycle of any DAC register will update both DAC's + * simultaneously. + * + * If you have XFER mode enabled a (*insn_read) will need + * to be performed in order to update the DAC's with the + * last value written. */ + for (i = 0; i < insn->n; i++) { + val = data[i]; + + devpriv->ao_readback[chan] = val; + + if (s->maxdata == 0x0fff) { + /* + * DAS6402/12 has the two 8-bit DAC registers, left + * justified (the 4 LSB bits are don't care). Data + * can be written as one word. + */ + val <<= 4; + outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan)); + } else { + /* + * DAS6402/16 uses both 8-bit DAC registers and needs + * to be written LSB then MSB. + */ + outb(val & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + } + } - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Stopping acquisition\n"); - devpriv->das6402_ignoreirq = 1; - outb_p(0x02, dev->iobase + 10); /* disable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(0, dev->iobase + 9); /* disables interrupts */ - - outw_p(SCANL, dev->iobase + 2); - - return 0; + return insn->n; } -#ifdef unused -static int das6402_ai_mode2(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig *it) +static int das6402_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Starting acquisition\n"); - outb_p(0x03, dev->iobase + 10); /* enable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); + /* + * If XFER mode is enabled, reading any DAC register + * will update both DAC's simultaneously. + */ + inw(dev->iobase + DAS6402_AO_LSB_REG(chan)); - devpriv->ai_bytes_to_read = it->n * sizeof(short); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - /* um... ignoreirq is a nasty race condition */ - devpriv->das6402_ignoreirq = 0; + return insn->n; +} - outw_p(SCANL, dev->iobase + 2); +static int das6402_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + DAS6402_DI_DO_REG); - return 0; + return insn->n; } -#endif -static int board_init(struct comedi_device *dev) +static int das6402_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct das6402_private *devpriv = dev->private; - BYTE b; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS6402_DI_DO_REG); - devpriv->das6402_ignoreirq = 1; + data[1] = s->state; - outb(0x07, dev->iobase + 8); + return insn->n; +} - /* register 11 */ - outb_p(MODE, dev->iobase + 11); - b = BIP | SEM | MODE | GAIN | FIFOHFULL; - outb_p(b, dev->iobase + 11); +static void das6402_reset(struct comedi_device *dev) +{ + struct das6402_private *devpriv = dev->private; - /* register 8 */ - outb_p(EXTEND, dev->iobase + 8); - b = EXTEND | MHZ; - outb_p(b, dev->iobase + 8); - b = MHZ | CLRINT | CLRXTR | CLRXIN; - outb_p(b, dev->iobase + 8); + /* enable "Enhanced" mode */ + outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG); - /* register 9 */ - b = IRQ | CONVSRC | BURSTEN | INTE; - outb_p(b, dev->iobase + 9); + /* enable 10MHz pacer clock */ + das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ); - /* register 10 */ - b = TGSEL | TGEN; - outb_p(b, dev->iobase + 10); + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); - b = 0x07; - outb_p(b, dev->iobase + 8); + /* default ADC to single-ended unipolar 10V inputs */ + das6402_set_mode(dev, DAS6402_MODE_RANGE(0) | + DAS6402_MODE_POLLED | + DAS6402_MODE_SE | + DAS6402_MODE_UNI); - das6402_setcounter(dev); + /* default mux for single channel conversion (channel 0) */ + outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0), + dev->iobase + DAS6402_AI_MUX_REG); - outw_p(SCANL, dev->iobase + 2); /* reset card fifo */ + /* set both DAC's for unipolar 5V output range */ + devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2); + outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG); - devpriv->das6402_ignoreirq = 0; + /* set both DAC's to 0V */ + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + inw(dev->iobase + DAS6402_AO_LSB_REG(0)); - return 0; + das6402_enable_counter(dev, false); + + /* set all digital outputs low */ + outb(0, dev->iobase + DAS6402_DI_DO_REG); + + das6402_clear_all_interrupts(dev); } static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct das6402_boardinfo *board = comedi_board(dev); struct das6402_private *devpriv; - unsigned int irq; - int ret; struct comedi_subdevice *s; - - ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE); - if (ret) - return ret; - - irq = it->options[0]; - dev_dbg(dev->class_dev, "( irq = %u )\n", irq); - ret = request_irq(irq, intr_handler, 0, "das6402", dev); - if (ret < 0) - return ret; - - dev->irq = irq; + int ret; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - /* ai subdevice */ + das6402_reset(dev); + + /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ + if ((1 << it->options[1]) & 0x8cec) { + ret = request_irq(it->options[1], das6402_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = it->options[1]; + + switch (dev->irq) { + case 10: + devpriv->irq = 4; + break; + case 11: + devpriv->irq = 1; + break; + case 15: + devpriv->irq = 6; + break; + default: + devpriv->irq = dev->irq; + break; + } + } + } + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* Analog Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - /* s->trig[2]=das6402_ai_mode2; */ - s->cancel = das6402_ai_cancel; - s->maxdata = (1 << 12) - 1; - s->len_chanlist = 16; /* ? */ - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 64; + s->maxdata = board->maxdata; + s->range_table = &das6402_ai_ranges; + s->insn_read = das6402_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = das6402_ai_cmdtest; + s->do_cmd = das6402_ai_cmd; + s->cancel = das6402_ai_cancel; + } - board_init(dev); + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = board->maxdata; + s->range_table = &das6402_ao_ranges; + s->insn_write = das6402_ao_insn_write; + s->insn_read = das6402_ao_insn_read; + + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_di_insn_bits; + + /* Digital Input subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_do_insn_bits; return 0; } @@ -313,9 +536,12 @@ static struct comedi_driver das6402_driver = { .module = THIS_MODULE, .attach = das6402_attach, .detach = comedi_legacy_detach, + .board_name = &das6402_boards[0].name, + .num_names = ARRAY_SIZE(das6402_boards), + .offset = sizeof(struct das6402_boardinfo), }; module_comedi_driver(das6402_driver) -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 5af0a5764a8..6f7f8d531dd 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -224,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, @@ -275,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) @@ -307,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 */ @@ -352,41 +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 */ + arg = cmd->convert_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_1MHZ, &devpriv->divisor1, &devpriv->divisor2, - &cmd->convert_arg, cmd->flags); - if (tmp != cmd->convert_arg) - err++; + &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; @@ -400,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; @@ -420,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; } @@ -477,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; @@ -491,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; /* @@ -522,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--; @@ -532,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, @@ -551,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, @@ -599,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; @@ -686,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]; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 78a19629ff5..ad7a5d53b97 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -164,16 +164,29 @@ struct dmm32at_private { }; +static int dmm32at_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + context); + if ((status & DMM32AT_STATUS) == 0) + return 0; + return -EBUSY; +} + static int dmm32at_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + int n; unsigned int d; - unsigned char status; unsigned short msb, lsb; unsigned char chan; int range; + int ret; /* get the channel and range number */ @@ -190,26 +203,20 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev, outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ outb(0xff, dev->iobase + DMM32AT_CONV); + /* wait for conversion to end */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AISTAT); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, + DMM32AT_AISTAT); + if (ret) + return ret; /* read data */ lsb = inb(dev->iobase + DMM32AT_AILSB); @@ -236,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 */ @@ -318,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; @@ -403,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; @@ -439,14 +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) - 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 */ @@ -457,12 +468,6 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outb(0xff, dev->iobase + DMM32AT_CONV); } -/* 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; } @@ -503,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 */ @@ -525,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) @@ -533,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. */ @@ -549,13 +568,9 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, outb(hi, dev->iobase + DMM32AT_DACMSB); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_DACSTAT); - if ((status & DMM32AT_DACBUSY) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0); + if (ret) + return ret; /* dummy read to update trigger the output */ status = inb(dev->iobase + DMM32AT_DACMSB); diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index d4d4e4b497d..4263014426f 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -545,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; diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 4271903facd..ba7c2ba618e 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -224,23 +224,32 @@ static const struct comedi_lrange *dac_range_types[] = { &range_unipolar5 }; -#define DT2811_TIMEOUT 5 +static int dt2811_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2811_ADCSR); + if ((status & DT2811_ADBUSY) == 0) + return 0; + return -EBUSY; +} static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); - int timeout = DT2811_TIMEOUT; + int ret; int i; for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + DT2811_ADGCR); - while (timeout - && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) - timeout--; - if (!timeout) - return -ETIME; + ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0); + if (ret) + return ret; data[i] = inb(dev->iobase + DT2811_ADDATLO); data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index abad6e49c1c..904c9f0e4af 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -66,26 +66,35 @@ struct dt2814_private { #define DT2814_TIMEOUT 10 #define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */ +static int dt2814_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2814_CSR); + if (status & DT2814_FINISH) + return 0; + return -EBUSY; +} + static int dt2814_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, hi, lo; + int n, hi, lo; int chan; - int status = 0; + int ret; for (n = 0; n < insn->n; n++) { chan = CR_CHAN(insn->chanspec); outb(chan, dev->iobase + DT2814_CSR); - for (i = 0; i < DT2814_TIMEOUT; i++) { - status = inb(dev->iobase + DT2814_CSR); - udelay(10); - if (status & DT2814_FINISH) - break; - } - if (i >= DT2814_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, dt2814_ai_eoc, 0); + if (ret) + return ret; hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); @@ -119,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 */ @@ -161,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; diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index ee24717821e..b9ac4ed8bab 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -67,15 +67,17 @@ struct dt2815_private { unsigned int ao_readback[8]; }; -static int dt2815_wait_for_status(struct comedi_device *dev, int status) +static int dt2815_ao_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < 100; i++) { - if (inb(dev->iobase + DT2815_STATUS) == status) - break; - } - return status; + status = inb(dev->iobase + DT2815_STATUS); + if (status == context) + return 0; + return -EBUSY; } static int dt2815_ao_insn_read(struct comedi_device *dev, @@ -98,30 +100,23 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct dt2815_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); - unsigned int status; unsigned int lo, hi; + int ret; for (i = 0; i < insn->n; i++) { lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01; hi = (data[i] & 0xff0) >> 4; - status = dt2815_wait_for_status(dev, 0x00); - if (status != 0) { - dev_dbg(dev->class_dev, - "failed to write low byte on %d reason %x\n", - chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x00); + if (ret) + return ret; outb(lo, dev->iobase + DT2815_DATA); - status = dt2815_wait_for_status(dev, 0x10); - if (status != 0x10) { - dev_dbg(dev->class_dev, - "failed to write high byte on %d reason %x\n", - chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x10); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; } return i; diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 895f73a1902..c2a66dcf99f 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -63,7 +63,6 @@ Notes: #include "comedi_fc.h" -#define DT2821_TIMEOUT 100 /* 500 us */ #define DT2821_SIZE 0x10 /* @@ -248,27 +247,6 @@ struct dt282x_private { * Some useless abstractions */ #define chan_to_DAC(a) ((a)&1) -#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY) -#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE) - -/* - * danger! macro abuse... a is the expression to wait on, and b is - * the statement(s) to execute if it doesn't happen. - */ -#define wait_for(a, b) \ - do { \ - int _i; \ - for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \ - if (a) { \ - _i = 0; \ - break; \ - } \ - udelay(5); \ - } \ - if (_i) { \ - b \ - } \ - } while (0) static int prep_ai_dma(struct comedi_device *dev, int chan, int size); static int prep_ao_dma(struct comedi_device *dev, int chan, int size); @@ -328,7 +306,6 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); if (size == 0) { dev_err(dev->class_dev, "AO underrun\n"); - dt282x_ao_cancel(dev, s); s->async->events |= COMEDI_CB_OVERFLOW; return; } @@ -363,7 +340,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) dt282x_munge(dev, ptr, size); ret = cfc_write_array_to_buffer(s, ptr, size); if (ret != size) { - dt282x_ai_cancel(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; return; } devpriv->nread -= size / 2; @@ -373,7 +350,6 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) devpriv->nread = 0; } if (!devpriv->nread) { - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; return; } @@ -471,15 +447,13 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) if (adcsr & DT2821_ADERR) { if (devpriv->nread != 0) { comedi_error(dev, "A/D error"); - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_ERROR; } handled = 1; } if (dacsr & DT2821_DAERR) { comedi_error(dev, "D/A error"); - dt282x_ao_cancel(dev, s_ao); - s->async->events |= COMEDI_CB_ERROR; + s_ao->async->events |= COMEDI_CB_ERROR; handled = 1; } #if 0 @@ -492,7 +466,7 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) 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; @@ -508,7 +482,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) handled = 1; } #endif - comedi_event(dev, s); + cfc_handle_events(dev, s); + cfc_handle_events(dev, s_ao); return IRQ_RETVAL(handled); } @@ -530,6 +505,29 @@ static void dt282x_load_changain(struct comedi_device *dev, int n, outw(n - 1, dev->iobase + DT2821_CHANCSR); } +static int dt282x_ai_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + DT2821_ADCSR); + switch (context) { + case DT2821_MUXBUSY: + if ((status & DT2821_MUXBUSY) == 0) + return 0; + break; + case DT2821_ADDONE: + if (status & DT2821_ADDONE) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Performs a single A/D conversion. * - Put channel/gain into channel-gain list @@ -542,6 +540,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, { const struct dt282x_board *board = comedi_board(dev); struct dt282x_private *devpriv = dev->private; + int ret; int i; /* XXX should we really be enabling the ad clock here? */ @@ -551,13 +550,18 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, dt282x_load_changain(dev, 1, &insn->chanspec); outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; for (i = 0; i < insn->n; i++) { outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR); - wait_for(ad_done(), comedi_error(dev, "timeout\n"); - return -ETIME;); + + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, + DT2821_ADDONE); + if (ret) + return ret; data[i] = inw(dev->iobase + @@ -574,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 */ @@ -629,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; @@ -646,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, @@ -691,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, @@ -818,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 */ @@ -845,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 */ @@ -858,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; @@ -871,12 +876,14 @@ 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, diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index f52a4476cb7..4ab4de00592 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -322,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; @@ -369,12 +369,10 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; debug_n_ints++; - if (debug_n_ints >= 10) { - dt3k_ai_cancel(dev, s); + if (debug_n_ints >= 10) s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -418,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 */ @@ -468,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); } } @@ -767,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; } diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index f224825830b..e5593f8c740 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -57,18 +57,27 @@ struct dyna_pci10xx_private { unsigned long BADR3; }; -/******************************************************************************/ -/************************** READ WRITE FUNCTIONS ******************************/ -/******************************************************************************/ +static int dyna_pci10xx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw_p(dev->iobase); + if (status & (1 << 15)) + return 0; + return -EBUSY; +} -/* analog input callback */ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; - int n, counter; + int n; u16 d = 0; + int ret = 0; unsigned int chan, range; /* get the channel number and range */ @@ -82,18 +91,13 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, smp_mb(); outw_p(0x0000 + range + chan, dev->iobase + 2); udelay(10); + + ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0); + if (ret) + break; + /* read data */ - for (counter = 0; counter < READ_TIMEOUT; counter++) { - d = inw_p(dev->iobase); - - /* check if read is successful if the EOC bit is set */ - if (d & (1 << 15)) - goto conv_finish; - } - data[n] = 0; - dev_dbg(dev->class_dev, "timeout reading analog input\n"); - continue; -conv_finish: + d = inw_p(dev->iobase); /* mask the first 4 bits - EOC bits */ d &= 0x0FFF; data[n] = d; @@ -101,7 +105,7 @@ conv_finish: mutex_unlock(&devpriv->mutex); /* return the number of samples read/written */ - return n; + return ret ? ret : n; } /* analog output callback */ @@ -232,8 +236,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, s->state = 0; s->insn_bits = dyna_pci10xx_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index a99ddf00ddc..4e410f3b0e2 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -1,27 +1,49 @@ /* - comedi/drivers/fl512.c - Anders Gnistrup <ex18@kalman.iau.dtu.dk> -*/ + * fl512.c + * Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: fl512 -Description: unknown -Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> -Devices: [unknown] FL512 (fl512) -Status: unknown - -Digital I/O is not supported. - -Configuration options: - [0] - I/O port base address -*/ + * Driver: fl512 + * Description: unknown + * Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * Devices: [unknown] FL512 (fl512) + * Status: unknown + * + * Digital I/O is not supported. + * + * Configuration options: + * [0] - I/O port base address + */ #include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#define FL512_SIZE 16 /* the size of the used memory */ +/* + * Register I/O map + */ +#define FL512_AI_LSB_REG 0x02 +#define FL512_AI_MSB_REG 0x03 +#define FL512_AI_MUX_REG 0x02 +#define FL512_AI_START_CONV_REG 0x03 +#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2)) + struct fl512_private { unsigned short ao_readback[2]; }; @@ -38,72 +60,69 @@ static const struct comedi_lrange range_fl512 = { } }; -/* - * fl512_ai_insn : this is the analog input function - */ -static int fl512_ai_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - unsigned int lo_byte, hi_byte; - char chan = CR_CHAN(insn->chanspec); - unsigned long iobase = dev->iobase; - - for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */ - /* XXX probably can move next step out of for() loop -- will - * make AI a little bit faster. */ - outb(chan, iobase + 2); /* select chan */ - outb(0, iobase + 3); /* start conversion */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + FL512_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + outb(0, dev->iobase + FL512_AI_START_CONV_REG); + /* XXX should test "done" flag instead of delay */ - udelay(30); /* sleep 30 usec */ - lo_byte = inb(iobase + 2); /* low 8 byte */ - hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */ - data[n] = lo_byte + (hi_byte << 8); + udelay(30); + + val = inb(dev->iobase + FL512_AI_LSB_REG); + val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8); + val &= s->maxdata; + + data[i] = val; } - return n; + + return insn->n; } -/* - * fl512_ao_insn : used to write to a DA port n times - */ -static int fl512_ao_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); /* get chan to write */ - unsigned long iobase = dev->iobase; /* get base address */ - - for (n = 0; n < insn->n; n++) { /* write n data set */ - /* write low byte */ - outb(data[n] & 0x0ff, iobase + 4 + 2 * chan); - /* write high byte */ - outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan); - inb(iobase + 4 + 2 * chan); /* trig */ - - devpriv->ao_readback[chan] = data[n]; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* write LSB, MSB then trigger conversion */ + outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan)); + outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan)); + inb(dev->iobase + FL512_AO_TRIG_REG(chan)); } - return n; + devpriv->ao_readback[chan] = val; + + return insn->n; } -/* - * fl512_ao_insn_readback : used to read previous values written to - * DA port - */ -static int fl512_ao_insn_readback(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int fl512_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - return n; + return insn->n; } static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -112,7 +131,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], FL512_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; @@ -124,42 +143,26 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - /* - * this if the definitions of the supdevices, 2 have been defined - */ - /* Analog indput */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* define subdevice as Analog In */ - s->type = COMEDI_SUBD_AI; - /* you can read it from userspace */ - s->subdev_flags = SDF_READABLE | SDF_GROUND; - /* Number of Analog input channels */ - s->n_chan = 16; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when read AD */ - s->insn_read = fl512_ai_insn; - - /* Analog output */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_read = fl512_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* define subdevice as Analog OUT */ - s->type = COMEDI_SUBD_AO; - /* you can write it from userspace */ - s->subdev_flags = SDF_WRITABLE; - /* Number of Analog output channels */ - s->n_chan = 2; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when write DA */ - s->insn_write = fl512_ao_insn; - /* function to call when reading DA */ - s->insn_read = fl512_ao_insn_readback; - - return 1; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_write = fl512_ao_insn_write; + s->insn_read = fl512_ao_insn_read; + + return 0; } static struct comedi_driver fl512_driver = { diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index de60a2871d7..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,6 @@ * support could be added to this driver. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> @@ -52,149 +50,105 @@ #include "plx9080.h" #include "comedi_fc.h" -static void abort_dma(struct comedi_device *dev, unsigned int channel); -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t handle_interrupt(int irq, void *d); -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data); - -#define TIMER_BASE 50 /* 20MHz master clock */ -#define DMA_BUFFER_SIZE 0x10000 -#define NUM_DMA_BUFFERS 4 -#define NUM_DMA_DESCRIPTORS 256 - -enum hpdi_registers { - FIRMWARE_REV_REG = 0x0, - BOARD_CONTROL_REG = 0x4, - BOARD_STATUS_REG = 0x8, - TX_PROG_ALMOST_REG = 0xc, - RX_PROG_ALMOST_REG = 0x10, - FEATURES_REG = 0x14, - FIFO_REG = 0x18, - TX_STATUS_COUNT_REG = 0x1c, - TX_LINE_VALID_COUNT_REG = 0x20, - TX_LINE_INVALID_COUNT_REG = 0x24, - RX_STATUS_COUNT_REG = 0x28, - RX_LINE_COUNT_REG = 0x2c, - INTERRUPT_CONTROL_REG = 0x30, - INTERRUPT_STATUS_REG = 0x34, - TX_CLOCK_DIVIDER_REG = 0x38, - TX_FIFO_SIZE_REG = 0x40, - RX_FIFO_SIZE_REG = 0x44, - TX_FIFO_WORDS_REG = 0x48, - RX_FIFO_WORDS_REG = 0x4c, - INTERRUPT_EDGE_LEVEL_REG = 0x50, - INTERRUPT_POLARITY_REG = 0x54, -}; - -/* bit definitions */ - -enum firmware_revision_bits { - FEATURES_REG_PRESENT_BIT = 0x8000, -}; - -enum board_control_bits { - BOARD_RESET_BIT = 0x1, /* wait 10usec before accessing fifos */ - TX_FIFO_RESET_BIT = 0x2, - RX_FIFO_RESET_BIT = 0x4, - TX_ENABLE_BIT = 0x10, - RX_ENABLE_BIT = 0x20, - DEMAND_DMA_DIRECTION_TX_BIT = 0x40, - /* for ch 0, ch 1 can only transmit (when present) */ - LINE_VALID_ON_STATUS_VALID_BIT = 0x80, - START_TX_BIT = 0x10, - CABLE_THROTTLE_ENABLE_BIT = 0x20, - TEST_MODE_ENABLE_BIT = 0x80000000, -}; - -enum board_status_bits { - COMMAND_LINE_STATUS_MASK = 0x7f, - TX_IN_PROGRESS_BIT = 0x80, - TX_NOT_EMPTY_BIT = 0x100, - TX_NOT_ALMOST_EMPTY_BIT = 0x200, - TX_NOT_ALMOST_FULL_BIT = 0x400, - TX_NOT_FULL_BIT = 0x800, - RX_NOT_EMPTY_BIT = 0x1000, - RX_NOT_ALMOST_EMPTY_BIT = 0x2000, - RX_NOT_ALMOST_FULL_BIT = 0x4000, - RX_NOT_FULL_BIT = 0x8000, - BOARD_JUMPER0_INSTALLED_BIT = 0x10000, - BOARD_JUMPER1_INSTALLED_BIT = 0x20000, - TX_OVERRUN_BIT = 0x200000, - RX_UNDERRUN_BIT = 0x400000, - RX_OVERRUN_BIT = 0x800000, -}; - -static uint32_t almost_full_bits(unsigned int num_words) -{ - /* XXX need to add or subtract one? */ - return (num_words << 16) & 0xff0000; -} - -static uint32_t almost_empty_bits(unsigned int num_words) -{ - return num_words & 0xffff; -} - -enum features_bits { - FIFO_SIZE_PRESENT_BIT = 0x1, - FIFO_WORDS_PRESENT_BIT = 0x2, - LEVEL_EDGE_INTERRUPTS_PRESENT_BIT = 0x4, - GPIO_SUPPORTED_BIT = 0x8, - PLX_DMA_CH1_SUPPORTED_BIT = 0x10, - OVERRUN_UNDERRUN_SUPPORTED_BIT = 0x20, -}; - -enum interrupt_sources { - FRAME_VALID_START_INTR = 0, - FRAME_VALID_END_INTR = 1, - TX_FIFO_EMPTY_INTR = 8, - TX_FIFO_ALMOST_EMPTY_INTR = 9, - TX_FIFO_ALMOST_FULL_INTR = 10, - TX_FIFO_FULL_INTR = 11, - RX_EMPTY_INTR = 12, - RX_ALMOST_EMPTY_INTR = 13, - RX_ALMOST_FULL_INTR = 14, - RX_FULL_INTR = 15, -}; - -static uint32_t intr_bit(int interrupt_source) -{ - return 0x1 << interrupt_source; -} - -static unsigned int fifo_size(uint32_t fifo_size_bits) -{ - return fifo_size_bits & 0xfffff; -} +/* + * PCI BAR2 Register map (devpriv->mmio) + */ +#define FIRMWARE_REV_REG 0x00 +#define FEATURES_REG_PRESENT_BIT (1 << 15) +#define BOARD_CONTROL_REG 0x04 +#define BOARD_RESET_BIT (1 << 0) +#define TX_FIFO_RESET_BIT (1 << 1) +#define RX_FIFO_RESET_BIT (1 << 2) +#define TX_ENABLE_BIT (1 << 4) +#define RX_ENABLE_BIT (1 << 5) +#define DEMAND_DMA_DIRECTION_TX_BIT (1 << 6) /* ch 0 only */ +#define LINE_VALID_ON_STATUS_VALID_BIT (1 << 7) +#define START_TX_BIT (1 << 8) +#define CABLE_THROTTLE_ENABLE_BIT (1 << 9) +#define TEST_MODE_ENABLE_BIT (1 << 31) +#define BOARD_STATUS_REG 0x08 +#define COMMAND_LINE_STATUS_MASK (0x7f << 0) +#define TX_IN_PROGRESS_BIT (1 << 7) +#define TX_NOT_EMPTY_BIT (1 << 8) +#define TX_NOT_ALMOST_EMPTY_BIT (1 << 9) +#define TX_NOT_ALMOST_FULL_BIT (1 << 10) +#define TX_NOT_FULL_BIT (1 << 11) +#define RX_NOT_EMPTY_BIT (1 << 12) +#define RX_NOT_ALMOST_EMPTY_BIT (1 << 13) +#define RX_NOT_ALMOST_FULL_BIT (1 << 14) +#define RX_NOT_FULL_BIT (1 << 15) +#define BOARD_JUMPER0_INSTALLED_BIT (1 << 16) +#define BOARD_JUMPER1_INSTALLED_BIT (1 << 17) +#define TX_OVERRUN_BIT (1 << 21) +#define RX_UNDERRUN_BIT (1 << 22) +#define RX_OVERRUN_BIT (1 << 23) +#define TX_PROG_ALMOST_REG 0x0c +#define RX_PROG_ALMOST_REG 0x10 +#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0) +#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16) +#define FEATURES_REG 0x14 +#define FIFO_SIZE_PRESENT_BIT (1 << 0) +#define FIFO_WORDS_PRESENT_BIT (1 << 1) +#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT (1 << 2) +#define GPIO_SUPPORTED_BIT (1 << 3) +#define PLX_DMA_CH1_SUPPORTED_BIT (1 << 4) +#define OVERRUN_UNDERRUN_SUPPORTED_BIT (1 << 5) +#define FIFO_REG 0x18 +#define TX_STATUS_COUNT_REG 0x1c +#define TX_LINE_VALID_COUNT_REG 0x20, +#define TX_LINE_INVALID_COUNT_REG 0x24 +#define RX_STATUS_COUNT_REG 0x28 +#define RX_LINE_COUNT_REG 0x2c +#define INTERRUPT_CONTROL_REG 0x30 +#define FRAME_VALID_START_INTR (1 << 0) +#define FRAME_VALID_END_INTR (1 << 1) +#define TX_FIFO_EMPTY_INTR (1 << 8) +#define TX_FIFO_ALMOST_EMPTY_INTR (1 << 9) +#define TX_FIFO_ALMOST_FULL_INTR (1 << 10) +#define TX_FIFO_FULL_INTR (1 << 11) +#define RX_EMPTY_INTR (1 << 12) +#define RX_ALMOST_EMPTY_INTR (1 << 13) +#define RX_ALMOST_FULL_INTR (1 << 14) +#define RX_FULL_INTR (1 << 15) +#define INTERRUPT_STATUS_REG 0x34 +#define TX_CLOCK_DIVIDER_REG 0x38 +#define TX_FIFO_SIZE_REG 0x40 +#define RX_FIFO_SIZE_REG 0x44 +#define FIFO_SIZE_MASK (0xfffff << 0) +#define TX_FIFO_WORDS_REG 0x48 +#define RX_FIFO_WORDS_REG 0x4c +#define INTERRUPT_EDGE_LEVEL_REG 0x50 +#define INTERRUPT_POLARITY_REG 0x54 + +#define TIMER_BASE 50 /* 20MHz master clock */ +#define DMA_BUFFER_SIZE 0x10000 +#define NUM_DMA_BUFFERS 4 +#define NUM_DMA_DESCRIPTORS 256 struct hpdi_board { - const char *name; /* board name */ - int device_id; /* pci device id */ - int subdevice_id; /* pci subdevice id */ + const char *name; + int device_id; + int subdevice_id; }; static const struct hpdi_board hpdi_boards[] = { { - .name = "pci-hpdi32", - .device_id = PCI_DEVICE_ID_PLX_9080, - .subdevice_id = 0x2400, + .name = "pci-hpdi32", + .device_id = PCI_DEVICE_ID_PLX_9080, + .subdevice_id = 0x2400, }, #if 0 { - .name = "pxi-hpdi32", - .device_id = 0x9656, - .subdevice_id = 0x2705, + .name = "pxi-hpdi32", + .device_id = 0x9656, + .subdevice_id = 0x2705, }, #endif }; struct hpdi_private { - /* base addresses (ioremapped) */ - void __iomem *plx9080_iobase; - void __iomem *hpdi_iobase; + void __iomem *plx9080_mmio; + void __iomem *mmio; uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ /* physical addresses of dma buffers */ dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; @@ -207,26 +161,346 @@ struct hpdi_private { /* pointer to start of buffers indexed by descriptor */ uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* index of the dma descriptor that is currently being used */ - volatile unsigned int dma_desc_index; + unsigned int dma_desc_index; unsigned int tx_fifo_size; unsigned int rx_fifo_size; - volatile unsigned long dio_count; - /* software copies of values written to hpdi registers */ - volatile uint32_t bits[24]; + unsigned long dio_count; /* number of bytes at which to generate COMEDI_CB_BLOCK events */ - volatile unsigned int block_size; + unsigned int block_size; }; -static int dio_config_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) +{ + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int idx; + unsigned int start; + unsigned int desc; + unsigned int size; + unsigned int next; + + if (channel) + next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG); + else + next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + + idx = devpriv->dma_desc_index; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + /* loop until we have read all the full buffers */ + for (desc = 0; (next < start || next >= start + devpriv->block_size) && + desc < devpriv->num_dma_descriptors; desc++) { + /* transfer data from dma buffer to comedi buffer */ + size = devpriv->block_size / sizeof(uint32_t); + if (cmd->stop_src == TRIG_COUNT) { + if (size > devpriv->dio_count) + size = devpriv->dio_count; + devpriv->dio_count -= size; + } + cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx], + size * sizeof(uint32_t)); + idx++; + idx %= devpriv->num_dma_descriptors; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + + devpriv->dma_desc_index = idx; + } + /* XXX check for buffer overrun somehow */ +} + +static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + uint32_t hpdi_intr_status, hpdi_board_status; + uint32_t plx_status; + uint32_t plx_bits; + uint8_t dma0_status, dma1_status; + unsigned long flags; + + if (!dev->attached) + return IRQ_NONE; + + plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG); + if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) + return IRQ_NONE; + + hpdi_intr_status = readl(devpriv->mmio + INTERRUPT_STATUS_REG); + hpdi_board_status = readl(devpriv->mmio + BOARD_STATUS_REG); + + if (hpdi_intr_status) + writel(hpdi_intr_status, devpriv->mmio + INTERRUPT_STATUS_REG); + + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ + writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + + if (dma0_status & PLX_DMA_EN_BIT) + gsc_hpdi_drain_dma(dev, 0); + } + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ + writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + } + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* clear possible plx9080 interrupt sources */ + if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ + plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + } + + if (hpdi_board_status & RX_OVERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo overrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } + + if (hpdi_board_status & RX_UNDERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo underrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } + + if (devpriv->dio_count == 0) + async->events |= COMEDI_CB_EOA; + + cfc_handle_events(dev, s); + + return IRQ_HANDLED; +} + +static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel) +{ + struct hpdi_private *devpriv = dev->private; + unsigned long flags; + + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); + + plx9080_abort_dma(devpriv->plx9080_mmio, channel); + + spin_unlock_irqrestore(&dev->spinlock, flags); +} + +static int gsc_hpdi_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct hpdi_private *devpriv = dev->private; + + writel(0, devpriv->mmio + BOARD_CONTROL_REG); + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); + + gsc_hpdi_abort_dma(dev, 0); + + return 0; +} + +static int gsc_hpdi_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct hpdi_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned long flags; + uint32_t bits; + + if (s->io_bits) + return -EINVAL; + + writel(RX_FIFO_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + + gsc_hpdi_abort_dma(dev, 0); + + devpriv->dma_desc_index = 0; + + /* + * These register are supposedly unused during chained dma, + * but I have found that left over values from last operation + * occasionally cause problems with transfer of first dma + * block. Initializing them to zero seems to fix the problem. + */ + writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG); + + /* give location of first dma descriptor */ + bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | + PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; + writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG); + + /* enable dma transfer */ + spin_lock_irqsave(&dev->spinlock, flags); + writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + + if (cmd->stop_src == TRIG_COUNT) + devpriv->dio_count = cmd->stop_arg; + else + devpriv->dio_count = 1; + + /* clear over/under run status flags */ + writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, + devpriv->mmio + BOARD_STATUS_REG); + + /* enable interrupts */ + writel(RX_FULL_INTR, devpriv->mmio + INTERRUPT_CONTROL_REG); + + writel(RX_ENABLE_BIT, devpriv->mmio + BOARD_CONTROL_REG); + + return 0; +} + +static int gsc_hpdi_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) { + dev_dbg(dev->class_dev, + "chanlist must be ch 0 to 31 in order\n"); + return -EINVAL; + } + } + + return 0; +} + +static int gsc_hpdi_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + + if (s->io_bits) + return -EINVAL; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + 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); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + if (err) + return 4; + + /* Step 5: 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; + +} + +/* setup dma descriptors so a link completes every 'len' bytes */ +static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, + unsigned int len) +{ + struct hpdi_private *devpriv = dev->private; + dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; + uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | + PLX_XFER_LOCAL_TO_PCI; + unsigned int offset = 0; + unsigned int idx = 0; + unsigned int i; + + if (len > DMA_BUFFER_SIZE) + len = DMA_BUFFER_SIZE; + len -= len % sizeof(uint32_t); + if (len == 0) + return -EINVAL; + + for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) { + devpriv->dma_desc[i].pci_start_addr = + cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset); + devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); + devpriv->dma_desc[i].transfer_size = cpu_to_le32(len); + devpriv->dma_desc[i].next = cpu_to_le32((phys_addr + + (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); + + devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + + (offset / sizeof(uint32_t)); + + offset += len; + if (len + offset > DMA_BUFFER_SIZE) { + offset = 0; + idx++; + } + } + devpriv->num_dma_descriptors = i; + /* fix last descriptor to point back to first */ + devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits); + + devpriv->block_size = len; + + return len; +} + +static int gsc_hpdi_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { int ret; switch (data[0]) { case INSN_CONFIG_BLOCK_SIZE: - return dio_config_block_size(dev, data); + ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]); + if (ret) + return ret; + + data[1] = ret; + break; default: ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff); if (ret) @@ -237,31 +511,53 @@ static int dio_config_insn(struct comedi_device *dev, return insn->n; } -static void disable_plx_interrupts(struct comedi_device *dev) +static int gsc_hpdi_init(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; + uint32_t plx_intcsr_bits; + + /* wait 10usec after reset before accessing fifos */ + writel(BOARD_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + udelay(10); + + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + RX_PROG_ALMOST_REG); + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + TX_PROG_ALMOST_REG); + + devpriv->tx_fifo_size = readl(devpriv->mmio + TX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + devpriv->rx_fifo_size = readl(devpriv->mmio + RX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); + + /* enable interrupts */ + plx_intcsr_bits = + ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | + ICS_DMA0_E; + writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG); - writel(0, devpriv->plx9080_iobase + PLX_INTRCS_REG); + return 0; } -/* initialize plx9080 chip */ -static void init_plx9080(struct comedi_device *dev) +static void gsc_hpdi_init_plx9080(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; uint32_t bits; - void __iomem *plx_iobase = devpriv->plx9080_iobase; + void __iomem *plx_iobase = devpriv->plx9080_mmio; #ifdef __BIG_ENDIAN bits = BIGEND_DMA0 | BIGEND_DMA1; #else bits = 0; #endif - writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG); + writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG); - disable_plx_interrupts(dev); + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); - abort_dma(dev, 0); - abort_dma(dev, 1); + gsc_hpdi_abort_dma(dev, 0); + gsc_hpdi_abort_dma(dev, 1); /* configure dma0 mode */ bits = 0; @@ -285,117 +581,7 @@ static void init_plx9080(struct comedi_device *dev) writel(bits, plx_iobase + PLX_DMA0_MODE_REG); } -/* Allocate and initialize the subdevice structures. - */ -static int setup_subdevices(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int ret; - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; - - s = &dev->subdevices[0]; - /* analog input subdevice */ - dev->read_subdev = s; -/* dev->write_subdev = s; */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | SDF_CMD_READ; - s->n_chan = 32; - s->len_chanlist = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = dio_config_insn; - s->do_cmd = hpdi_cmd; - s->do_cmdtest = hpdi_cmd_test; - s->cancel = hpdi_cancel; - - return 0; -} - -static int init_hpdi(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; - uint32_t plx_intcsr_bits; - - writel(BOARD_RESET_BIT, devpriv->hpdi_iobase + BOARD_CONTROL_REG); - udelay(10); - - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + RX_PROG_ALMOST_REG); - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + TX_PROG_ALMOST_REG); - - devpriv->tx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - TX_FIFO_SIZE_REG)); - devpriv->rx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - RX_FIFO_SIZE_REG)); - - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - /* enable interrupts */ - plx_intcsr_bits = - ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | - ICS_DMA0_E; - writel(plx_intcsr_bits, devpriv->plx9080_iobase + PLX_INTRCS_REG); - - return 0; -} - -/* setup dma descriptors so a link completes every 'transfer_size' bytes */ -static int setup_dma_descriptors(struct comedi_device *dev, - unsigned int transfer_size) -{ - struct hpdi_private *devpriv = dev->private; - unsigned int buffer_index, buffer_offset; - uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI; - unsigned int i; - - if (transfer_size > DMA_BUFFER_SIZE) - transfer_size = DMA_BUFFER_SIZE; - transfer_size -= transfer_size % sizeof(uint32_t); - if (transfer_size == 0) - return -1; - - buffer_offset = 0; - buffer_index = 0; - for (i = 0; i < NUM_DMA_DESCRIPTORS && - buffer_index < NUM_DMA_BUFFERS; i++) { - devpriv->dma_desc[i].pci_start_addr = - cpu_to_le32(devpriv->dio_buffer_phys_addr[buffer_index] + - buffer_offset); - devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); - devpriv->dma_desc[i].transfer_size = - cpu_to_le32(transfer_size); - devpriv->dma_desc[i].next = - cpu_to_le32((devpriv->dma_desc_phys_addr + (i + - 1) * - sizeof(devpriv->dma_desc[0])) | next_bits); - - devpriv->desc_dio_buffer[i] = - devpriv->dio_buffer[buffer_index] + - (buffer_offset / sizeof(uint32_t)); - - buffer_offset += transfer_size; - if (transfer_size + buffer_offset > DMA_BUFFER_SIZE) { - buffer_offset = 0; - buffer_index++; - } - } - devpriv->num_dma_descriptors = i; - /* fix last descriptor to point back to first */ - devpriv->dma_desc[i - 1].next = - cpu_to_le32(devpriv->dma_desc_phys_addr | next_bits); - - devpriv->block_size = transfer_size; - - return transfer_size; -} - -static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev) +static const struct hpdi_board *gsc_hpdi_find_board(struct pci_dev *pcidev) { unsigned int i; @@ -406,16 +592,17 @@ static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev) return NULL; } -static int hpdi_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int gsc_hpdi_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct hpdi_board *thisboard; struct hpdi_private *devpriv; + struct comedi_subdevice *s; int i; int retval; - thisboard = hpdi_find_board(pcidev); + thisboard = gsc_hpdi_find_board(pcidev); if (!thisboard) { dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n", pci_name(pcidev)); @@ -433,17 +620,17 @@ static int hpdi_auto_attach(struct comedi_device *dev, return retval; pci_set_master(pcidev); - devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0); - devpriv->hpdi_iobase = pci_ioremap_bar(pcidev, 2); - if (!devpriv->plx9080_iobase || !devpriv->hpdi_iobase) { + devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0); + devpriv->mmio = pci_ioremap_bar(pcidev, 2); + if (!devpriv->plx9080_mmio || !devpriv->mmio) { dev_warn(dev->class_dev, "failed to remap io memory\n"); return -ENOMEM; } - init_plx9080(dev); + gsc_hpdi_init_plx9080(dev); /* get irq */ - if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, + if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED, dev->board_name, dev)) { dev_warn(dev->class_dev, "unable to allocate irq %u\n", pcidev->irq); @@ -470,18 +657,33 @@ static int hpdi_auto_attach(struct comedi_device *dev, return -EIO; } - retval = setup_dma_descriptors(dev, 0x1000); + retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000); if (retval < 0) return retval; - retval = setup_subdevices(dev); - if (retval < 0) + retval = comedi_alloc_subdevices(dev, 1); + if (retval) return retval; - return init_hpdi(dev); + /* Digital I/O subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | + SDF_CMD_READ; + s->n_chan = 32; + s->len_chanlist = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = gsc_hpdi_dio_insn_config; + s->do_cmd = gsc_hpdi_cmd; + s->do_cmdtest = gsc_hpdi_cmd_test; + s->cancel = gsc_hpdi_cancel; + + return gsc_hpdi_init(dev); } -static void hpdi_detach(struct comedi_device *dev) +static void gsc_hpdi_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct hpdi_private *devpriv = dev->private; @@ -490,12 +692,12 @@ static void hpdi_detach(struct comedi_device *dev) if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { - if (devpriv->plx9080_iobase) { - disable_plx_interrupts(dev); - iounmap(devpriv->plx9080_iobase); + if (devpriv->plx9080_mmio) { + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + iounmap(devpriv->plx9080_mmio); } - if (devpriv->hpdi_iobase) - iounmap(devpriv->hpdi_iobase); + if (devpriv->mmio) + iounmap(devpriv->mmio); /* free pci dma buffers */ for (i = 0; i < NUM_DMA_BUFFERS; i++) { if (devpriv->dio_buffer[i]) @@ -516,318 +718,11 @@ static void hpdi_detach(struct comedi_device *dev) comedi_pci_disable(dev); } -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data) -{ - unsigned int requested_block_size; - int retval; - - requested_block_size = data[1]; - - retval = setup_dma_descriptors(dev, requested_block_size); - if (retval < 0) - return retval; - - data[1] = retval; - - return 2; -} - -static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int i; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - if (!cmd->chanlist_len) { - cmd->chanlist_len = 32; - err |= -EINVAL; - } - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - switch (cmd->stop_src) { - case TRIG_COUNT: - err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); - break; - case TRIG_NONE: - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (err) - return 4; - - if (!cmd->chanlist) - return 0; - - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - /* XXX could support 8 or 16 channels */ - comedi_error(dev, - "chanlist must be ch 0 to 31 in order"); - err++; - break; - } - } - - if (err) - return 5; - - return 0; -} - -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - if (s->io_bits) - return -EINVAL; - else - return di_cmd_test(dev, s, cmd); -} - -static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits, - unsigned int offset) -{ - struct hpdi_private *devpriv = dev->private; - - writel(bits | devpriv->bits[offset / sizeof(uint32_t)], - devpriv->hpdi_iobase + offset); -} - -static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct hpdi_private *devpriv = dev->private; - uint32_t bits; - unsigned long flags; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - - hpdi_writel(dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG); - - abort_dma(dev, 0); - - devpriv->dma_desc_index = 0; - - /* These register are supposedly unused during chained dma, - * but I have found that left over values from last operation - * occasionally cause problems with transfer of first dma - * block. Initializing them to zero seems to fix the problem. */ - writel(0, devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); - /* give location of first dma descriptor */ - bits = - devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; - writel(bits, devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - /* enable dma transfer */ - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - if (cmd->stop_src == TRIG_COUNT) - devpriv->dio_count = cmd->stop_arg; - else - devpriv->dio_count = 1; - - /* clear over/under run status flags */ - writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, - devpriv->hpdi_iobase + BOARD_STATUS_REG); - /* enable interrupts */ - writel(intr_bit(RX_FULL_INTR), - devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - hpdi_writel(dev, RX_ENABLE_BIT, BOARD_CONTROL_REG); - - return 0; -} - -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s->io_bits) - return -EINVAL; - else - return di_cmd(dev, s); -} - -static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - struct comedi_async *async = dev->read_subdev->async; - uint32_t next_transfer_addr; - int j; - int num_samples = 0; - void __iomem *pci_addr_reg; - - if (channel) - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; - else - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - - /* loop until we have read all the full buffers */ - j = 0; - for (next_transfer_addr = readl(pci_addr_reg); - (next_transfer_addr < - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) - || next_transfer_addr >= - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) + devpriv->block_size) - && j < devpriv->num_dma_descriptors; j++) { - /* transfer data from dma buffer to comedi buffer */ - num_samples = devpriv->block_size / sizeof(uint32_t); - if (async->cmd.stop_src == TRIG_COUNT) { - if (num_samples > devpriv->dio_count) - num_samples = devpriv->dio_count; - devpriv->dio_count -= num_samples; - } - cfc_write_array_to_buffer(dev->read_subdev, - devpriv->desc_dio_buffer[devpriv-> - dma_desc_index], - num_samples * sizeof(uint32_t)); - devpriv->dma_desc_index++; - devpriv->dma_desc_index %= devpriv->num_dma_descriptors; - } - /* XXX check for buffer overrun somehow */ -} - -static irqreturn_t handle_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct hpdi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - uint32_t hpdi_intr_status, hpdi_board_status; - uint32_t plx_status; - uint32_t plx_bits; - uint8_t dma0_status, dma1_status; - unsigned long flags; - - if (!dev->attached) - return IRQ_NONE; - - plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG); - if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) - return IRQ_NONE; - - hpdi_intr_status = readl(devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - hpdi_board_status = readl(devpriv->hpdi_iobase + BOARD_STATUS_REG); - - async->events = 0; - - if (hpdi_intr_status) { - writel(hpdi_intr_status, - devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - } - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ - writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - - if (dma0_status & PLX_DMA_EN_BIT) - drain_dma_buffers(dev, 0); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* clear possible plx9080 interrupt sources */ - if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - } - - if (hpdi_board_status & RX_OVERRUN_BIT) { - comedi_error(dev, "rx fifo overrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - } - - if (hpdi_board_status & RX_UNDERRUN_BIT) { - comedi_error(dev, "rx fifo underrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - } - - if (devpriv->dio_count == 0) - async->events |= COMEDI_CB_EOA; - - cfc_handle_events(dev, s); - - return IRQ_HANDLED; -} - -static void abort_dma(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - unsigned long flags; - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - - plx9080_abort_dma(devpriv->plx9080_iobase, channel); - - spin_unlock_irqrestore(&dev->spinlock, flags); -} - -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct hpdi_private *devpriv = dev->private; - - hpdi_writel(dev, 0, BOARD_CONTROL_REG); - - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - abort_dma(dev, 0); - - return 0; -} - static struct comedi_driver gsc_hpdi_driver = { .driver_name = "gsc_hpdi", .module = THIS_MODULE, - .auto_attach = hpdi_auto_attach, - .detach = hpdi_detach, + .auto_attach = gsc_hpdi_auto_attach, + .detach = gsc_hpdi_detach, }; static int gsc_hpdi_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 80539b2bea1..0b8b2162b76 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -171,12 +171,27 @@ static void setup_channel_list(struct comedi_device *dev, } } +static int icp_multi_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_ADC_CSR); + if ((status & ADC_BSY) == 0) + return 0; + return -EBUSY; +} + static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, timeout; + int ret = 0; + int n; /* Disable A/D conversion ready interrupt */ devpriv->IntEnable &= ~ADC_READY; @@ -199,33 +214,10 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, udelay(1); /* Wait for conversion to complete, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_ADC_CSR) & ADC_BSY)) - goto conv_finish; - - udelay(1); - } - - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "A/D insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); + ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0); + if (ret) + break; - /* Clear data received */ - data[n] = 0; - - return -ETIME; - -conv_finish: data[n] = (readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff; } @@ -238,7 +230,21 @@ conv_finish: devpriv->IntStatus |= ADC_READY; writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); - return n; + return ret ? ret : n; +} + +static int icp_multi_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_DAC_CSR); + if ((status & DAC_BSY) == 0) + return 0; + return -EBUSY; } static int icp_multi_insn_write_ao(struct comedi_device *dev, @@ -246,7 +252,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, chan, range, timeout; + int n, chan, range; + int ret; /* Disable D/A conversion ready interrupt */ devpriv->IntEnable &= ~DAC_READY; @@ -274,33 +281,24 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* Wait for analogue output data register to be * ready for new data, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_DAC_CSR) & DAC_BSY)) - goto dac_ready; - - udelay(1); + ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0); + if (ret) { + /* Disable interrupt */ + devpriv->IntEnable &= ~DAC_READY; + writew(devpriv->IntEnable, + devpriv->io_addr + ICP_MULTI_INT_EN); + + /* Clear interrupt status */ + devpriv->IntStatus |= DAC_READY; + writew(devpriv->IntStatus, + devpriv->io_addr + ICP_MULTI_INT_STAT); + + /* Clear data received */ + devpriv->ao_data[chan] = 0; + + return ret; } - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "D/A insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); - - /* Clear data received */ - devpriv->ao_data[chan] = 0; - - return -ETIME; - -dac_ready: /* Write data to analogue output data register */ writew(data[n], devpriv->io_addr + ICP_MULTI_AO); @@ -565,9 +563,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, devpriv->valid = 1; - dev_info(dev->class_dev, "%s attached, irq %sabled\n", - dev->board_name, dev->irq ? "en" : "dis"); - return 0; } diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 8577778441f..2516ce83483 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -190,20 +190,18 @@ static int ii20k_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int ii20k_ai_wait_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - int timeout) +static int ii20k_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { void __iomem *iobase = ii20k_module_iobase(dev, s); unsigned char status; - do { - status = readb(iobase + II20K_AI_STATUS_REG); - if ((status & II20K_AI_STATUS_INT) == 0) - return 0; - } while (timeout--); - - return -ETIME; + status = readb(iobase + II20K_AI_STATUS_REG); + if ((status & II20K_AI_STATUS_INT) == 0) + return 0; + return -EBUSY; } static void ii20k_ai_setup(struct comedi_device *dev, @@ -263,7 +261,7 @@ static int ii20k_ai_insn_read(struct comedi_device *dev, /* generate a software start convert signal */ readb(iobase + II20K_AI_PACER_RESET_REG); - ret = ii20k_ai_wait_eoc(dev, s, 100); + ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0); if (ret) return ret; @@ -463,6 +461,7 @@ static int ii20k_attach(struct comedi_device *dev, 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; diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 6100c12c164..a8db9d86aad 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -51,23 +51,55 @@ #include "jr3_pci.h" #define PCI_VENDOR_ID_JR3 0x1762 -#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111 -#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111 -#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112 -#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 -#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 -struct jr3_pci_dev_private { - struct jr3_t __iomem *iobase; - int n_channels; - struct timer_list timer; +enum jr3_pci_boardid { + BOARD_JR3_1, + BOARD_JR3_2, + BOARD_JR3_3, + BOARD_JR3_4, }; -struct poll_delay_t { +struct jr3_pci_board { + const char *name; + int n_subdevs; +}; + +static const struct jr3_pci_board jr3_pci_boards[] = { + [BOARD_JR3_1] = { + .name = "jr3_pci_1", + .n_subdevs = 1, + }, + [BOARD_JR3_2] = { + .name = "jr3_pci_2", + .n_subdevs = 2, + }, + [BOARD_JR3_3] = { + .name = "jr3_pci_3", + .n_subdevs = 3, + }, + [BOARD_JR3_4] = { + .name = "jr3_pci_4", + .n_subdevs = 4, + }, +}; + +struct jr3_pci_transform { + struct { + u16 link_type; + s16 link_amount; + } link[8]; +}; + +struct jr3_pci_poll_delay { int min; int max; }; +struct jr3_pci_dev_private { + struct jr3_t __iomem *iobase; + struct timer_list timer; +}; + struct jr3_pci_subdev_private { struct jr3_channel __iomem *channel; unsigned long next_time_min; @@ -79,7 +111,6 @@ struct jr3_pci_subdev_private { state_jr3_init_use_offset_complete, state_jr3_done } state; - int channel_no; int serial_no; int model_no; struct { @@ -92,9 +123,9 @@ struct jr3_pci_subdev_private { int retries; }; -static struct poll_delay_t poll_delay_min_max(int min, int max) +static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max) { - struct poll_delay_t result; + struct jr3_pci_poll_delay result; result.min = min; result.max = max; @@ -106,15 +137,8 @@ static int is_complete(struct jr3_channel __iomem *channel) return get_s16(&channel->command_word0) == 0; } -struct transform_t { - struct { - u16 link_type; - s16 link_amount; - } link[8]; -}; - static void set_transforms(struct jr3_channel __iomem *channel, - struct transform_t transf, short num) + struct jr3_pci_transform transf, short num) { int i; @@ -194,110 +218,99 @@ static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem return result; } +static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int val = 0; + + if (spriv->state != state_jr3_done) + return 0; + + if (chan < 56) { + unsigned int axis = chan % 8; + unsigned filter = chan / 8; + + switch (axis) { + case 0: + val = get_s16(&spriv->channel->filter[filter].fx); + break; + case 1: + val = get_s16(&spriv->channel->filter[filter].fy); + break; + case 2: + val = get_s16(&spriv->channel->filter[filter].fz); + break; + case 3: + val = get_s16(&spriv->channel->filter[filter].mx); + break; + case 4: + val = get_s16(&spriv->channel->filter[filter].my); + break; + case 5: + val = get_s16(&spriv->channel->filter[filter].mz); + break; + case 6: + val = get_s16(&spriv->channel->filter[filter].v1); + break; + case 7: + val = get_s16(&spriv->channel->filter[filter].v2); + break; + } + val += 0x4000; + } else if (chan == 56) { + val = get_u16(&spriv->channel->model_no); + } else if (chan == 57) { + val = get_u16(&spriv->channel->serial_no); + } + + return val; +} + static int jr3_pci_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int result; - struct jr3_pci_subdev_private *p; - int channel; - - p = s->private; - channel = CR_CHAN(insn->chanspec); - if (p == NULL || channel > 57) { - result = -EINVAL; - } else { - int i; - - result = insn->n; - if (p->state != state_jr3_done || - (get_u16(&p->channel->errors) & (watch_dog | watch_dog2 | - sensor_change))) { - /* No sensor or sensor changed */ - if (p->state == state_jr3_done) { - /* Restart polling */ - p->state = state_jr3_poll; - } - result = -EAGAIN; - } - for (i = 0; i < insn->n; i++) { - if (channel < 56) { - int axis, filter; - - axis = channel % 8; - filter = channel / 8; - if (p->state != state_jr3_done) { - data[i] = 0; - } else { - int F = 0; - switch (axis) { - case 0: - F = get_s16(&p->channel-> - filter[filter].fx); - break; - case 1: - F = get_s16(&p->channel-> - filter[filter].fy); - break; - case 2: - F = get_s16(&p->channel-> - filter[filter].fz); - break; - case 3: - F = get_s16(&p->channel-> - filter[filter].mx); - break; - case 4: - F = get_s16(&p->channel-> - filter[filter].my); - break; - case 5: - F = get_s16(&p->channel-> - filter[filter].mz); - break; - case 6: - F = get_s16(&p->channel-> - filter[filter].v1); - break; - case 7: - F = get_s16(&p->channel-> - filter[filter].v2); - break; - } - data[i] = F + 0x4000; - } - } else if (channel == 56) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->model_no); - } else if (channel == 57) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->serial_no); - } + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + u16 errors; + int i; + + if (!spriv) + return -EINVAL; + + errors = get_u16(&spriv->channel->errors); + if (spriv->state != state_jr3_done || + (errors & (watch_dog | watch_dog2 | sensor_change))) { + /* No sensor or sensor changed */ + if (spriv->state == state_jr3_done) { + /* Restart polling */ + spriv->state = state_jr3_poll; } + return -EAGAIN; } - return result; + + for (i = 0; i < insn->n; i++) + data[i] = jr3_pci_ai_read_chan(dev, s, chan); + + return insn->n; } static int jr3_pci_open(struct comedi_device *dev) { + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; int i; - struct jr3_pci_dev_private *devpriv = dev->private; dev_dbg(dev->class_dev, "jr3_pci_open\n"); - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p; - - p = dev->subdevices[i].private; - if (p) { - dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", p, - p->serial_no, p->channel_no); - } + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + if (spriv) + dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", + spriv, spriv->serial_no, s->index); } return 0; } @@ -326,271 +339,262 @@ static int read_idm_word(const u8 *data, size_t size, int *pos, return result; } -static int jr3_download_firmware(struct comedi_device *dev, - const u8 *data, size_t size, - unsigned long context) +static int jr3_check_firmware(struct comedi_device *dev, + const u8 *data, size_t size) { + int more = 1; + int pos = 0; + /* * IDM file format is: * { count, address, data <count> } * * ffff */ - int result, more, pos, OK; - - result = 0; - more = 1; - pos = 0; - OK = 0; while (more) { - unsigned int count, addr; + unsigned int count = 0; + unsigned int addr = 0; more = more && read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) { - OK = 1; - break; - } + if (more && count == 0xffff) + return 0; + more = more && read_idm_word(data, size, &pos, &addr); while (more && count > 0) { - unsigned int dummy; + unsigned int dummy = 0; + more = more && read_idm_word(data, size, &pos, &dummy); count--; } } - if (!OK) { - result = -ENODATA; - } else { - int i; - struct jr3_pci_dev_private *p = dev->private; + return -ENODATA; +} + +static void jr3_write_firmware(struct comedi_device *dev, + int subdev, const u8 *data, size_t size) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_t __iomem *iobase = devpriv->iobase; + u32 __iomem *lo; + u32 __iomem *hi; + int more = 1; + int pos = 0; + + while (more) { + unsigned int count = 0; + unsigned int addr = 0; + + more = more && read_idm_word(data, size, &pos, &count); + if (more && count == 0xffff) + return; + + more = more && read_idm_word(data, size, &pos, &addr); + + dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n", + subdev, count, addr); + + while (more && count > 0) { + if (addr & 0x4000) { + /* 16 bit data, never seen in real life!! */ + unsigned int data1 = 0; - for (i = 0; i < p->n_channels; i++) { - struct jr3_pci_subdev_private *sp; + more = more && + read_idm_word(data, size, &pos, &data1); + count--; + /* jr3[addr + 0x20000 * pnum] = data1; */ + } else { + /* Download 24 bit program */ + unsigned int data1 = 0; + unsigned int data2 = 0; + + lo = &iobase->channel[subdev].program_lo[addr]; + hi = &iobase->channel[subdev].program_hi[addr]; - sp = dev->subdevices[i].private; - more = 1; - pos = 0; - while (more) { - unsigned int count, addr; more = more && - read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) - break; + read_idm_word(data, size, &pos, &data1); more = more && - read_idm_word(data, size, &pos, &addr); - dev_dbg(dev->class_dev, - "Loading#%d %4.4x bytes at %4.4x\n", - i, count, addr); - while (more && count > 0) { - if (addr & 0x4000) { - /* 16 bit data, never seen - * in real life!! */ - unsigned int data1; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - count--; - /* jr3[addr + 0x20000 * pnum] = - data1; */ - } else { - /* Download 24 bit program */ - unsigned int data1, data2; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - more = more && - read_idm_word(data, size, - &pos, - &data2); - count -= 2; - if (more) { - set_u16(&p-> - iobase->channel - [i].program_low - [addr], data1); - udelay(1); - set_u16(&p-> - iobase->channel - [i].program_high - [addr], data2); - udelay(1); - } - } - addr++; + read_idm_word(data, size, &pos, &data2); + count -= 2; + if (more) { + set_u16(lo, data1); + udelay(1); + set_u16(hi, data2); + udelay(1); } } + addr++; } } - return result; } -static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s) +static int jr3_download_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { - struct poll_delay_t result = poll_delay_min_max(1000, 2000); - struct jr3_pci_subdev_private *p = s->private; - int i; + int subdev; + int ret; - if (p) { - struct jr3_channel __iomem *channel = p->channel; - int errors = get_u16(&channel->errors); - - if (errors != p->errors) - p->errors = errors; - - if (errors & (watch_dog | watch_dog2 | sensor_change)) - /* Sensor communication lost, force poll mode */ - p->state = state_jr3_poll; - - switch (p->state) { - case state_jr3_poll: { - u16 model_no = get_u16(&channel->model_no); - u16 serial_no = get_u16(&channel->serial_no); - if ((errors & (watch_dog | watch_dog2)) || - model_no == 0 || serial_no == 0) { - /* - * Still no sensor, keep on polling. - * Since it takes up to 10 seconds - * for offsets to stabilize, polling - * each second should suffice. - */ - result = poll_delay_min_max(1000, 2000); - } else { - p->retries = 0; - p->state = - state_jr3_init_wait_for_offset; - result = poll_delay_min_max(1000, 2000); - } - } - break; - case state_jr3_init_wait_for_offset: - p->retries++; - if (p->retries < 10) { - /* Wait for offeset to stabilize - * (< 10 s according to manual) */ - result = poll_delay_min_max(1000, 2000); - } else { - struct transform_t transf; + /* verify IDM file format */ + ret = jr3_check_firmware(dev, data, size); + if (ret) + return ret; - p->model_no = get_u16(&channel->model_no); - p->serial_no = get_u16(&channel->serial_no); + /* write firmware to each subdevice */ + for (subdev = 0; subdev < dev->n_subdevices; subdev++) + jr3_write_firmware(dev, subdev, data, size); - /* Transformation all zeros */ - for (i = 0; i < ARRAY_SIZE(transf.link); i++) { - transf.link[i].link_type = - (enum link_types)0; - transf.link[i].link_amount = 0; - } + return 0; +} - set_transforms(channel, transf, 0); - use_transform(channel, 0); - p->state = state_jr3_init_transform_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_transform_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - /* Set full scale */ - struct six_axis_t min_full_scale; - struct six_axis_t max_full_scale; - - min_full_scale = get_min_full_scales(channel); - max_full_scale = get_max_full_scales(channel); - set_full_scales(channel, max_full_scale); - - p->state = - state_jr3_init_set_full_scale_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_set_full_scale_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - struct force_array __iomem *full_scale; - - /* Use ranges in kN or we will - * overflow around 2000N! */ - full_scale = &channel->full_scale; - p->range[0].range.min = - -get_s16(&full_scale->fx) * 1000; - p->range[0].range.max = - get_s16(&full_scale->fx) * 1000; - p->range[1].range.min = - -get_s16(&full_scale->fy) * 1000; - p->range[1].range.max = - get_s16(&full_scale->fy) * 1000; - p->range[2].range.min = - -get_s16(&full_scale->fz) * 1000; - p->range[2].range.max = - get_s16(&full_scale->fz) * 1000; - p->range[3].range.min = - -get_s16(&full_scale->mx) * 100; - p->range[3].range.max = - get_s16(&full_scale->mx) * 100; - p->range[4].range.min = - -get_s16(&full_scale->my) * 100; - p->range[4].range.max = - get_s16(&full_scale->my) * 100; - p->range[5].range.min = - -get_s16(&full_scale->mz) * 100; - p->range[5].range.max = - get_s16(&full_scale->mz) * 100; /* ?? */ - p->range[6].range.min = - -get_s16(&full_scale->v1) * 100;/* ?? */ - p->range[6].range.max = - get_s16(&full_scale->v1) * 100; /* ?? */ - p->range[7].range.min = - -get_s16(&full_scale->v2) * 100;/* ?? */ - p->range[7].range.max = - get_s16(&full_scale->v2) * 100; /* ?? */ - p->range[8].range.min = 0; - p->range[8].range.max = 65535; - - use_offset(channel, 0); - p->state = state_jr3_init_use_offset_complete; - /* Allow 40 ms for completion */ - result = poll_delay_min_max(40, 100); - } - break; - case state_jr3_init_use_offset_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - set_s16(&channel->offsets.fx, 0); - set_s16(&channel->offsets.fy, 0); - set_s16(&channel->offsets.fz, 0); - set_s16(&channel->offsets.mx, 0); - set_s16(&channel->offsets.my, 0); - set_s16(&channel->offsets.mz, 0); +static struct jr3_pci_poll_delay jr3_pci_poll_subdevice(struct comedi_subdevice *s) +{ + struct jr3_pci_subdev_private *spriv = s->private; + struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000); + struct jr3_channel __iomem *channel; + u16 model_no; + u16 serial_no; + int errors; + int i; - set_offset(channel); + if (!spriv) + return result; - p->state = state_jr3_done; + channel = spriv->channel; + errors = get_u16(&channel->errors); + + if (errors != spriv->errors) + spriv->errors = errors; + + /* Sensor communication lost? force poll mode */ + if (errors & (watch_dog | watch_dog2 | sensor_change)) + spriv->state = state_jr3_poll; + + switch (spriv->state) { + case state_jr3_poll: + model_no = get_u16(&channel->model_no); + serial_no = get_u16(&channel->serial_no); + + if ((errors & (watch_dog | watch_dog2)) || + model_no == 0 || serial_no == 0) { + /* + * Still no sensor, keep on polling. + * Since it takes up to 10 seconds for offsets to + * stabilize, polling each second should suffice. + */ + } else { + spriv->retries = 0; + spriv->state = state_jr3_init_wait_for_offset; + } + break; + case state_jr3_init_wait_for_offset: + spriv->retries++; + if (spriv->retries < 10) { + /* + * Wait for offeset to stabilize + * (< 10 s according to manual) + */ + } else { + struct jr3_pci_transform transf; + + spriv->model_no = get_u16(&channel->model_no); + spriv->serial_no = get_u16(&channel->serial_no); + + /* Transformation all zeros */ + for (i = 0; i < ARRAY_SIZE(transf.link); i++) { + transf.link[i].link_type = (enum link_types)0; + transf.link[i].link_amount = 0; } - break; - case state_jr3_done: - poll_delay_min_max(10000, 20000); - break; - default: - poll_delay_min_max(1000, 2000); - break; + + set_transforms(channel, transf, 0); + use_transform(channel, 0); + spriv->state = state_jr3_init_transform_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_transform_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + /* Set full scale */ + struct six_axis_t min_full_scale; + struct six_axis_t max_full_scale; + + min_full_scale = get_min_full_scales(channel); + max_full_scale = get_max_full_scales(channel); + set_full_scales(channel, max_full_scale); + + spriv->state = state_jr3_init_set_full_scale_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_set_full_scale_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + struct force_array __iomem *fs = &channel->full_scale; + + /* Use ranges in kN or we will overflow around 2000N! */ + spriv->range[0].range.min = -get_s16(&fs->fx) * 1000; + spriv->range[0].range.max = get_s16(&fs->fx) * 1000; + spriv->range[1].range.min = -get_s16(&fs->fy) * 1000; + spriv->range[1].range.max = get_s16(&fs->fy) * 1000; + spriv->range[2].range.min = -get_s16(&fs->fz) * 1000; + spriv->range[2].range.max = get_s16(&fs->fz) * 1000; + spriv->range[3].range.min = -get_s16(&fs->mx) * 100; + spriv->range[3].range.max = get_s16(&fs->mx) * 100; + spriv->range[4].range.min = -get_s16(&fs->my) * 100; + spriv->range[4].range.max = get_s16(&fs->my) * 100; + spriv->range[5].range.min = -get_s16(&fs->mz) * 100; + /* the next five are questionable */ + spriv->range[5].range.max = get_s16(&fs->mz) * 100; + spriv->range[6].range.min = -get_s16(&fs->v1) * 100; + spriv->range[6].range.max = get_s16(&fs->v1) * 100; + spriv->range[7].range.min = -get_s16(&fs->v2) * 100; + spriv->range[7].range.max = get_s16(&fs->v2) * 100; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65535; + + use_offset(channel, 0); + spriv->state = state_jr3_init_use_offset_complete; + /* Allow 40 ms for completion */ + result = poll_delay_min_max(40, 100); + } + break; + case state_jr3_init_use_offset_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + set_s16(&channel->offsets.fx, 0); + set_s16(&channel->offsets.fy, 0); + set_s16(&channel->offsets.fz, 0); + set_s16(&channel->offsets.mx, 0); + set_s16(&channel->offsets.my, 0); + set_s16(&channel->offsets.mz, 0); + + set_offset(channel); + + spriv->state = state_jr3_done; } + break; + case state_jr3_done: + result = poll_delay_min_max(10000, 20000); + break; + default: + break; } + return result; } static void jr3_pci_poll_dev(unsigned long data) { - unsigned long flags; struct comedi_device *dev = (struct comedi_device *)data; struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + unsigned long flags; unsigned long now; int delay; int i; @@ -598,18 +602,22 @@ static void jr3_pci_poll_dev(unsigned long data) spin_lock_irqsave(&dev->spinlock, flags); delay = 1000; now = jiffies; - /* Poll all channels that are ready to be polled */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *subdevpriv = - dev->subdevices[i].private; - if (now > subdevpriv->next_time_min) { - struct poll_delay_t sub_delay; - - sub_delay = jr3_pci_poll_subdevice(&dev->subdevices[i]); - subdevpriv->next_time_min = - jiffies + msecs_to_jiffies(sub_delay.min); - subdevpriv->next_time_max = - jiffies + msecs_to_jiffies(sub_delay.max); + + /* Poll all channels that are ready to be polled */ + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + + if (now > spriv->next_time_min) { + struct jr3_pci_poll_delay sub_delay; + + sub_delay = jr3_pci_poll_subdevice(s); + + spriv->next_time_min = jiffies + + msecs_to_jiffies(sub_delay.min); + spriv->next_time_max = jiffies + + msecs_to_jiffies(sub_delay.max); + if (sub_delay.max && sub_delay.max < delay) /* * Wake up as late as possible -> @@ -624,13 +632,58 @@ static void jr3_pci_poll_dev(unsigned long data) add_timer(&devpriv->timer); } +static struct jr3_pci_subdev_private * +jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + int j; + int k; + + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) + return NULL; + + spriv->channel = &devpriv->iobase->channel[s->index].data; + + for (j = 0; j < 8; j++) { + spriv->range[j].length = 1; + spriv->range[j].range.min = -1000000; + spriv->range[j].range.max = 1000000; + + for (k = 0; k < 7; k++) { + spriv->range_table_list[j + k * 8] = + (struct comedi_lrange *)&spriv->range[j]; + spriv->maxdata_list[j + k * 8] = 0x7fff; + } + } + spriv->range[8].length = 1; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65536; + + spriv->range_table_list[56] = (struct comedi_lrange *)&spriv->range[8]; + spriv->range_table_list[57] = (struct comedi_lrange *)&spriv->range[8]; + spriv->maxdata_list[56] = 0xffff; + spriv->maxdata_list[57] = 0xffff; + + dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", + spriv->channel, devpriv->iobase, + ((char __iomem *)spriv->channel - + (char __iomem *)devpriv->iobase)); + + return spriv; +} + static int jr3_pci_auto_attach(struct comedi_device *dev, - unsigned long context_unused) + unsigned long context) { - int result; struct pci_dev *pcidev = comedi_to_pci_dev(dev); - int i; + static const struct jr3_pci_board *board = NULL; struct jr3_pci_dev_private *devpriv; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + int ret; + int i; if (sizeof(struct jr3_channel) != 0xc00) { dev_err(dev->class_dev, @@ -639,106 +692,56 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, return -EINVAL; } + if (context < ARRAY_SIZE(jr3_pci_boards)) + board = &jr3_pci_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; init_timer(&devpriv->timer); - switch (pcidev->device) { - case PCI_DEVICE_ID_JR3_1_CHANNEL: - case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW: - devpriv->n_channels = 1; - break; - case PCI_DEVICE_ID_JR3_2_CHANNEL: - devpriv->n_channels = 2; - break; - case PCI_DEVICE_ID_JR3_3_CHANNEL: - devpriv->n_channels = 3; - break; - case PCI_DEVICE_ID_JR3_4_CHANNEL: - devpriv->n_channels = 4; - break; - default: - dev_err(dev->class_dev, "jr3_pci: pci %s not supported\n", - pci_name(pcidev)); - return -EINVAL; - break; - } - result = comedi_pci_enable(dev); - if (result) - return result; + ret = comedi_pci_enable(dev); + if (ret) + return ret; devpriv->iobase = pci_ioremap_bar(pcidev, 0); if (!devpriv->iobase) return -ENOMEM; - result = comedi_alloc_subdevices(dev, devpriv->n_channels); - if (result) - return result; + ret = comedi_alloc_subdevices(dev, board->n_subdevs); + if (ret) + return ret; dev->open = jr3_pci_open; - for (i = 0; i < devpriv->n_channels; i++) { - dev->subdevices[i].type = COMEDI_SUBD_AI; - dev->subdevices[i].subdev_flags = SDF_READABLE | SDF_GROUND; - dev->subdevices[i].n_chan = 8 * 7 + 2; - dev->subdevices[i].insn_read = jr3_pci_ai_insn_read; - dev->subdevices[i].private = - kzalloc(sizeof(struct jr3_pci_subdev_private), - GFP_KERNEL); - if (dev->subdevices[i].private) { - struct jr3_pci_subdev_private *p; - int j; - - p = dev->subdevices[i].private; - p->channel = &devpriv->iobase->channel[i].data; - dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", - p->channel, devpriv->iobase, - ((char __iomem *)p->channel - - (char __iomem *)devpriv->iobase)); - p->channel_no = i; - for (j = 0; j < 8; j++) { - int k; - - p->range[j].length = 1; - p->range[j].range.min = -1000000; - p->range[j].range.max = 1000000; - for (k = 0; k < 7; k++) { - p->range_table_list[j + k * 8] = - (struct comedi_lrange *)&p-> - range[j]; - p->maxdata_list[j + k * 8] = 0x7fff; - } - } - p->range[8].length = 1; - p->range[8].range.min = 0; - p->range[8].range.max = 65536; - - p->range_table_list[56] = - (struct comedi_lrange *)&p->range[8]; - p->range_table_list[57] = - (struct comedi_lrange *)&p->range[8]; - p->maxdata_list[56] = 0xffff; - p->maxdata_list[57] = 0xffff; - /* Channel specific range and maxdata */ - dev->subdevices[i].range_table = NULL; - dev->subdevices[i].range_table_list = - p->range_table_list; - dev->subdevices[i].maxdata = 0; - dev->subdevices[i].maxdata_list = p->maxdata_list; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8 * 7 + 2; + s->insn_read = jr3_pci_ai_insn_read; + + spriv = jr3_pci_alloc_spriv(dev, s); + if (spriv) { + /* Channel specific range and maxdata */ + s->range_table_list = spriv->range_table_list; + s->maxdata_list = spriv->maxdata_list; } } /* Reset DSP card */ writel(0, &devpriv->iobase->channel[0].reset); - result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, - "comedi/jr3pci.idm", - jr3_download_firmware, 0); - dev_dbg(dev->class_dev, "Firmare load %d\n", result); - - if (result < 0) - return result; + ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + "comedi/jr3pci.idm", + jr3_download_firmware, 0); + dev_dbg(dev->class_dev, "Firmare load %d\n", ret); + if (ret < 0) + return ret; /* * TODO: use firmware to load preferred offset tables. Suggested * format: @@ -761,11 +764,12 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, } /* Start card timer */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p = dev->subdevices[i].private; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; - p->next_time_min = jiffies + msecs_to_jiffies(500); - p->next_time_max = jiffies + msecs_to_jiffies(2000); + spriv->next_time_min = jiffies + msecs_to_jiffies(500); + spriv->next_time_max = jiffies + msecs_to_jiffies(2000); } devpriv->timer.data = (unsigned long)dev; @@ -773,21 +777,16 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, devpriv->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&devpriv->timer); - return result; + return 0; } static void jr3_pci_detach(struct comedi_device *dev) { - int i; struct jr3_pci_dev_private *devpriv = dev->private; if (devpriv) { del_timer_sync(&devpriv->timer); - if (dev->subdevices) { - for (i = 0; i < devpriv->n_channels; i++) - kfree(dev->subdevices[i].private); - } if (devpriv->iobase) iounmap(devpriv->iobase); } @@ -808,11 +807,11 @@ static int jr3_pci_pci_probe(struct pci_dev *dev, } static const struct pci_device_id jr3_pci_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) }, + { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, + { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, + { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, { 0 } }; MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index 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 6b9846fd8c4..ec43c38958d 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -1,92 +1,113 @@ /* - comedi/drivers/ke_counter.c - Comedi driver for Kolter-Electronic PCI Counter 1 Card - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ke_counter -Description: Driver for Kolter Electronic Counter Card -Devices: [Kolter Electronic] PCI Counter Card (ke_counter) -Author: Michael Hillmann -Updated: Mon, 14 Apr 2008 15:42:42 +0100 -Status: tested - -Configuration Options: not applicable, uses PCI auto config + * ke_counter.c + * Comedi driver for Kolter-Electronic PCI Counter 1 Card + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -This driver is a simple driver to read the counter values from -Kolter Electronic PCI Counter Card. -*/ +/* + * Driver: ke_counter + * Description: Driver for Kolter Electronic Counter Card + * Devices: (Kolter Electronic) PCI Counter Card [ke_counter] + * Author: Michael Hillmann + * Updated: Mon, 14 Apr 2008 15:42:42 +0100 + * Status: tested + * + * Configuration Options: not applicable, uses PCI auto config + */ #include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" -#define CNT_CARD_DEVICE_ID 0x0014 +/* + * PCI BAR 0 Register I/O map + */ +#define KE_RESET_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LSB_REG(x) (0x04 + ((x) * 0x20)) +#define KE_MID_REG(x) (0x08 + ((x) * 0x20)) +#define KE_MSB_REG(x) (0x0c + ((x) * 0x20)) +#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20)) +#define KE_OSC_SEL_REG 0xf8 +#define KE_OSC_SEL_EXT (1 << 0) +#define KE_OSC_SEL_4MHZ (2 << 0) +#define KE_OSC_SEL_20MHZ (3 << 0) +#define KE_DO_REG 0xfc + +static int ke_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; -/*-- counter write ----------------------------------------------------------*/ + for (i = 0; i < insn->n; i++) { + val = data[0]; -/* This should be used only for resetting the counters; maybe it is better - to make a special command 'reset'. */ -static int cnt_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - - outb((unsigned char)((data[0] >> 24) & 0xff), - dev->iobase + chan * 0x20 + 0x10); - outb((unsigned char)((data[0] >> 16) & 0xff), - dev->iobase + chan * 0x20 + 0x0c); - outb((unsigned char)((data[0] >> 8) & 0xff), - dev->iobase + chan * 0x20 + 0x08); - outb((unsigned char)((data[0] >> 0) & 0xff), - dev->iobase + chan * 0x20 + 0x04); - - /* return the number of samples written */ - return 1; -} + /* Order matters */ + outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan)); + outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan)); + outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan)); + } -/*-- counter read -----------------------------------------------------------*/ + return insn->n; +} -static int cnt_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int ke_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char a0, a1, a2, a3, a4; - int chan = CR_CHAN(insn->chanspec); - int result; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - a0 = inb(dev->iobase + chan * 0x20); - a1 = inb(dev->iobase + chan * 0x20 + 0x04); - a2 = inb(dev->iobase + chan * 0x20 + 0x08); - a3 = inb(dev->iobase + chan * 0x20 + 0x0c); - a4 = inb(dev->iobase + chan * 0x20 + 0x10); + for (i = 0; i < insn->n; i++) { + /* Order matters */ + inb(dev->iobase + KE_LATCH_REG(chan)); - result = (a1 + (a2 * 256) + (a3 * 65536)); - if (a4 > 0) - result = result - s->maxdata; + val = inb(dev->iobase + KE_LSB_REG(chan)); + val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8); + val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16); + val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24); - *data = (unsigned int)result; + data[i] = val; + } - /* return the number of samples read */ - return 1; + return insn->n; } -static int cnt_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int ke_counter_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + KE_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int ke_counter_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct comedi_subdevice *s; @@ -97,30 +118,32 @@ static int cnt_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 0); - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; - - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; - s->n_chan = 3; - s->maxdata = 0x00ffffff; - s->insn_read = cnt_rinsn; - s->insn_write = cnt_winsn; - - /* select 20MHz clock */ - outb(3, dev->iobase + 248); - - /* reset all counters */ - outb(0, dev->iobase); - outb(0, dev->iobase + 0x20); - outb(0, dev->iobase + 0x40); - - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0x01ffffff; + s->range_table = &range_unknown; + s->insn_read = ke_counter_insn_read; + s->insn_write = ke_counter_insn_write; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ke_counter_do_insn_bits; + + outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG); + + outb(0, dev->iobase + KE_RESET_REG(0)); + outb(0, dev->iobase + KE_RESET_REG(1)); + outb(0, dev->iobase + KE_RESET_REG(2)); return 0; } @@ -128,7 +151,7 @@ static int cnt_auto_attach(struct comedi_device *dev, static struct comedi_driver ke_counter_driver = { .driver_name = "ke_counter", .module = THIS_MODULE, - .auto_attach = cnt_auto_attach, + .auto_attach = ke_counter_auto_attach, .detach = comedi_pci_disable, }; @@ -140,7 +163,7 @@ static int ke_counter_pci_probe(struct pci_dev *dev, } static const struct pci_device_id ke_counter_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) }, { 0 } }; MODULE_DEVICE_TABLE(pci, ke_counter_pci_table); @@ -154,5 +177,5 @@ static struct pci_driver ke_counter_pci_driver = { module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index e739bcd66a0..25ce2f78db8 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -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, + if (aref == SDF_DIFF) { + if (chan >= max_diff_chan) { + dev_dbg(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, - "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; } @@ -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; @@ -1112,9 +1072,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (!dev->attached) return IRQ_NONE; - /* Reset all events */ - s->async->events = 0; - if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { /* Read status register to find out what happened */ @@ -1167,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 @@ -1212,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; @@ -1395,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]) { @@ -1402,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; diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 7f668789640..0ff126b1fdf 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -248,6 +248,20 @@ static int me_dio_insn_bits(struct comedi_device *dev, return insn->n; } +static int me_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct me_private_data *dev_private = dev->private; + unsigned int status; + + status = readw(dev_private->me_regbase + ME_STATUS); + if ((status & 0x0004) == 0) + return 0; + return -EBUSY; +} + static int me_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -258,7 +272,7 @@ static int me_ai_insn_read(struct comedi_device *dev, unsigned int rang = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned short val; - int i; + int ret; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -290,19 +304,14 @@ static int me_ai_insn_read(struct comedi_device *dev, readw(dev_private->me_regbase + ME_ADC_START); /* wait for ADC fifo not empty flag */ - for (i = 100000; i > 0; i--) - if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004)) - break; + ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); + if (ret) + return ret; /* get value from ADC fifo */ - if (i) { - val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); - val = (val ^ 0x800) & 0x0fff; - data[0] = val; - } else { - dev_err(dev->class_dev, "Cannot get single value\n"); - return -EIO; - } + val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); + val = (val ^ 0x800) & 0x0fff; + data[0] = val; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -542,9 +551,6 @@ static int me_auto_attach(struct comedi_device *dev, s->insn_bits = me_dio_insn_bits; s->insn_config = me_dio_insn_config; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c index 81b78e053f4..a4f7d6f138d 100644 --- a/drivers/staging/comedi/drivers/mf6x4.c +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -133,21 +133,18 @@ static int mf6x4_do_insn_bits(struct comedi_device *dev, return insn->n; } -static int mf6x4_ai_wait_for_eoc(struct comedi_device *dev, - unsigned int timeout) +static int mf6x4_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { struct mf6x4_private *devpriv = dev->private; - unsigned int eolc; + unsigned int status; - while (timeout--) { - eolc = ioread32(devpriv->gpioc_R) & MF6X4_GPIOC_EOLC; - if (eolc) - return 0; - - udelay(1); - } - - return -ETIME; + status = ioread32(devpriv->gpioc_R); + if (status & MF6X4_GPIOC_EOLC) + return 0; + return -EBUSY; } static int mf6x4_ai_insn_read(struct comedi_device *dev, @@ -168,7 +165,7 @@ static int mf6x4_ai_insn_read(struct comedi_device *dev, /* Trigger ADC conversion by reading ADSTART */ ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R); - ret = mf6x4_ai_wait_for_eoc(dev, 100); + ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index 9c9a0ee432c..19c029acbc9 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -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; @@ -333,7 +334,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring, 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; } @@ -525,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; @@ -550,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; } @@ -593,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; diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index bcf2f972376..e6e58e989b7 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -29,9 +29,9 @@ #define MAX_MITE_DMA_CHANNELS 8 struct mite_dma_descriptor { - u32 count; - u32 addr; - u32 next; + __le32 count; + __le32 addr; + __le32 next; u32 dar; }; @@ -106,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); @@ -120,7 +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); + 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 fe4621ea65c..f770400a0e8 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -142,8 +142,18 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { } }; -/* Timeout 200ms */ -#define TIMEOUT 200 +static int mpc624_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + MPC624_ADC); + if ((status & MPC624_ADBUSY) == 0) + return 0; + return -EBUSY; +} static int mpc624_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -152,7 +162,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, struct mpc624_private *devpriv = dev->private; int n, i; unsigned long int data_in, data_out; - unsigned char ucPort; + int ret; /* * WARNING: @@ -170,15 +180,9 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, udelay(1); /* Wait for the conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - ucPort = inb(dev->iobase + MPC624_ADC); - if (ucPort & MPC624_ADBUSY) - udelay(1000); - else - break; - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0); + if (ret) + return ret; /* Start reading data */ data_in = 0; @@ -341,7 +345,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->insn_read = mpc624_ai_rinsn; - return 1; + return 0; } static struct comedi_driver mpc624_driver = { diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 3ca755eca28..b74b9e9bfd4 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -81,34 +81,44 @@ struct multiq3_private { unsigned int ao_readback[2]; }; +static int multiq3_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + MULTIQ3_STATUS); + if (status & context) + return 0; + return -EBUSY; +} + static int multiq3_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, n; + int n; int chan; unsigned int hi, lo; + int ret; chan = CR_CHAN(insn->chanspec); outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3), dev->iobase + MULTIQ3_CONTROL); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC); + if (ret) + return ret; for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + MULTIQ3_AD_CS); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + - MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC_I) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC_I); + if (ret) + return ret; hi = inb(dev->iobase + MULTIQ3_AD_CS); lo = inb(dev->iobase + MULTIQ3_AD_CS); diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 860fc81fb11..c8b1fa793a3 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -215,7 +215,7 @@ static irqreturn_t ni6527_interrupt(int irq, void *d) return IRQ_NONE; if (status & NI6527_STATUS_EDGE) { - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); } @@ -253,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) @@ -421,6 +421,7 @@ static int ni6527_auto_attach(struct comedi_device *dev, 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; diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 6e42001f686..9a139d6b8ef 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -439,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; @@ -473,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) @@ -491,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); @@ -671,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; diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index df42e390617..634cde83a02 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -40,6 +40,7 @@ #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" #include "ni_tio.h" @@ -789,13 +790,7 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, struct ni_gpct *counter = s->private; ni_tio_handle_interrupt(counter, s); - if (s->async->events) { - if (s->async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_660x_cancel(dev, s); - } - comedi_event(dev, s); - } + cfc_handle_events(dev, s); } static irqreturn_t ni_660x_interrupt(int irq, void *d) @@ -828,9 +823,9 @@ static int ni_660x_input_poll(struct comedi_device *dev, /* lock to avoid race with comedi_poll */ spin_lock_irqsave(&devpriv->interrupt_lock, flags); - mite_sync_input_dma(counter->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, @@ -841,7 +836,7 @@ static int ni_660x_buf_change(struct comedi_device *dev, struct ni_gpct *counter = s->private; int ret; - ret = mite_buf_change(mite_ring(devpriv, counter), s->async); + ret = mite_buf_change(mite_ring(devpriv, counter), s); if (ret < 0) return ret; @@ -1187,7 +1182,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev, global_interrupt_config_bits |= Cascade_Int_Enable_Bit; ni_660x_write_register(dev, 0, global_interrupt_config_bits, NI660X_GLOBAL_INT_CFG); - dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name); + return 0; } diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 8550fdc4ccd..1002ceacfdc 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -246,9 +246,6 @@ static int ni_670x_auto_attach(struct comedi_device *dev, /* Config of ao registers */ writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET); - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index f83eb9ebe27..5bd19494dbf 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -184,7 +184,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) } /* initialize async here to make sure s is not NULL */ async = s->async; - async->events = 0; cmd = &async->cmd; status = inw(dev->iobase + STATUS_REG); @@ -196,15 +195,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d) if (status & OVFL_BIT) { comedi_error(dev, "fifo overflow"); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); } if ((status & DMA_TC_BIT) == 0) { comedi_error(dev, "caught non-dma interrupt? Aborting."); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -249,7 +247,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) cfc_write_to_buffer(s, dpnt); if (cmd->stop_src == TRIG_COUNT) { if (--devpriv->count == 0) { /* end of acquisition */ - a2150_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -265,7 +262,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); /* clear interrupt */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); @@ -290,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 */ @@ -342,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; @@ -390,6 +402,7 @@ 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; @@ -457,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; @@ -488,13 +502,25 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int a2150_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STATUS_REG); + if (status & FNE_BIT) + return 0; + return -EBUSY; +} + static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct a2150_private *devpriv = dev->private; - unsigned int i, n; - static const int timeout = 100000; - static const int filter_delay = 36; + unsigned int n; + int ret; /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); @@ -524,30 +550,20 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, * there is a 35.6 sample delay for data to get through the * antialias filter */ - for (n = 0; n < filter_delay; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + for (n = 0; n < 36; n++) { + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + inw(dev->iobase + FIFO_DATA_REG); } /* read data */ for (n = 0; n < insn->n; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + data[n] = inw(dev->iobase + FIFO_DATA_REG); data[n] ^= 0x8000; } @@ -680,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]; diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 10e3e9475ee..c93b47bcca5 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -310,6 +310,7 @@ static int atao_calib_insn_read(struct comedi_device *dev, static void atao_reset(struct comedi_device *dev) { struct atao_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + ATAO_82C53_BASE; /* This is the reset sequence described in the manual */ @@ -317,10 +318,9 @@ static void atao_reset(struct comedi_device *dev) outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); /* Put outputs of counter 1 and counter 2 in a high state */ - i8254_load(dev->iobase + ATAO_82C53_BASE, 0, - 0, 0x0003, I8254_MODE4 | I8254_BINARY); - i8254_set_mode(dev->iobase + ATAO_82C53_BASE, 0, - 1, I8254_MODE4 | I8254_BINARY); + 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); diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index e8cd5ddb85c..6ad27f50c6e 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -96,7 +96,6 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) #define CLOCK_100_HZ 0x8F25 /* Other miscellaneous defines */ #define ATMIO16D_SIZE 32 /* bus address range */ -#define ATMIO16D_TIMEOUT 10 struct atmio16_board_t { @@ -222,7 +221,7 @@ static irqreturn_t atmio16d_interrupt(int irq, void *d) struct comedi_device *dev = d; 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; @@ -448,16 +447,32 @@ static int atmio16d_ai_cancel(struct comedi_device *dev, return 0; } -/* Mode 0 is used to get a single conversion on demand */ +static int atmio16d_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STAT_REG); + if (status & STAT_AD_CONVAVAIL) + return 0; + if (status & STAT_AD_OVERFLOW) { + outw(0, dev->iobase + AD_CLEAR_REG); + return -EOVERFLOW; + } + return -EBUSY; +} + static int atmio16d_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct atmio16d_private *devpriv = dev->private; - int i, t; + int i; int chan; int gain; - int status; + int ret; chan = CR_CHAN(insn->chanspec); gain = CR_RANGE(insn->chanspec); @@ -473,26 +488,17 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { /* start the conversion */ outw(0, dev->iobase + START_CONVERT_REG); + /* wait for it to finish */ - for (t = 0; t < ATMIO16D_TIMEOUT; t++) { - /* check conversion status */ - status = inw(dev->iobase + STAT_REG); - if (status & STAT_AD_CONVAVAIL) { - /* read the data now */ - data[i] = inw(dev->iobase + AD_FIFO_REG); - /* change to two's complement if need be */ - if (devpriv->adc_coding == adc_2comp) - data[i] ^= 0x800; - break; - } - if (status & STAT_AD_OVERFLOW) { - outw(0, dev->iobase + AD_CLEAR_REG); - return -ETIME; - } - } - /* end waiting, now check if it timed out */ - if (t == ATMIO16D_TIMEOUT) - return -ETIME; + ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0); + if (ret) + return ret; + + /* read the data now */ + data[i] = inw(dev->iobase + AD_FIFO_REG); + /* change to two's complement if need be */ + if (devpriv->adc_coding == adc_2comp) + data[i] ^= 0x800; } return i; @@ -723,10 +729,13 @@ static int atmio16d_attach(struct comedi_device *dev, /* 8255 subdevice */ s = &dev->subdevices[3]; - if (board->has_8255) - subdev_8255_init(dev, s, NULL, dev->iobase); - else + if (board->has_8255) { + ret = subdev_8255_init(dev, s, NULL, dev->iobase); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* don't yet know how to deal with counter/timers */ #if 0 diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index e4cdca34915..728bf7f14f7 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -109,19 +109,38 @@ static int daq700_dio_insn_config(struct comedi_device *dev, return insn->n; } +static int daq700_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + STA_R2); + if ((status & 0x03)) + return -EOVERFLOW; + status = inb(dev->iobase + STA_R1); + if ((status & 0x02)) + return -ENODATA; + if ((status & 0x11) == 0x01) + return 0; + return -EBUSY; +} + static int daq700_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, chan; + int n, chan; int d; - unsigned int status; - enum { TIMEOUT = 100 }; + int ret; chan = CR_CHAN(insn->chanspec); /* write channel to multiplexer */ /* 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 */ @@ -229,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 335ea34fa57..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. diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 0512445df08..3e3f940fa57 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -73,7 +73,6 @@ #include "ni_labpc_isadma.h" #define LABPC_SIZE 0x20 /* size of ISA io region */ -#define LABPC_ADC_TIMEOUT 1000 enum scan_mode { MODE_SINGLE_CHAN, @@ -172,32 +171,39 @@ static const struct labpc_boardinfo labpc_boards[] = { }; #endif -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; + + 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) @@ -308,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, @@ -352,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); @@ -363,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; @@ -549,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; } } @@ -664,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; @@ -714,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; @@ -735,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); @@ -750,17 +749,12 @@ 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); } /* figure out what method we will use to transfer data */ @@ -805,38 +799,25 @@ 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); @@ -893,8 +874,9 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int labpc_drain_fifo(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - unsigned 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; @@ -903,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--; @@ -950,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); @@ -968,7 +949,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overrun"); return IRQ_HANDLED; } @@ -988,7 +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; } @@ -996,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; } diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c index 2149596830a..d9f25fdbb72 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c @@ -87,6 +87,7 @@ 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; @@ -108,12 +109,12 @@ void labpc_drain_dma(struct comedi_device *dev) */ 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) + 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 (async->cmd.stop_src != TRIG_COUNT) { + if (cmd->stop_src != TRIG_COUNT) { leftover = devpriv->dma_transfer_size / sample_size; } else if (devpriv->count > num_points) { leftover = devpriv->count - num_points; @@ -125,7 +126,7 @@ void labpc_drain_dma(struct comedi_device *dev) for (i = 0; i < num_points; i++) cfc_write_to_buffer(s, devpriv->dma_buffer[i]); - if (async->cmd.stop_src == TRIG_COUNT) + if (cmd->stop_src == TRIG_COUNT) devpriv->count -= num_points; /* set address and count for next transfer */ diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 457b88481db..7ffdcc07ef9 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -256,7 +256,6 @@ static int ni_rtsi_insn_config(struct comedi_device *dev, static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_read_eeprom(struct comedi_device *dev, int addr); -static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s); #ifndef PCIDMA static void ni_handle_fifo_half_full(struct comedi_device *dev); static int ni_ao_fifo_half_empty(struct comedi_device *dev, @@ -272,15 +271,12 @@ static void shutdown_ai_command(struct comedi_device *dev); static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s); - static int ni_8255_callback(int dir, int port, int data, unsigned long arg); #ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s); #endif -static int ni_gpct_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index); @@ -687,12 +683,22 @@ static void ni_clear_ai_fifo(struct comedi_device *dev) { const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; + static const int timeout = 10000; + int i; if (board->reg_type == ni_reg_6143) { /* Flush the 6143 data FIFO */ ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */ ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */ - while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */ + /* Wait for complete */ + for (i = 0; i < timeout; i++) { + if (!(ni_readl(AIFIFO_Status_6143) & 0x10)) + break; + udelay(1); + } + if (i == timeout) { + comedi_error(dev, "FIFO flush timeout."); + } } else { devpriv->stc_writew(dev, 1, ADC_FIFO_Clear); if (board->reg_type == ni_reg_625x) { @@ -858,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); } @@ -871,7 +877,7 @@ static void mite_handle_b_linkc(struct mite_struct *mite, spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ao_mite_chan) - mite_sync_output_dma(devpriv->ao_mite_chan, s->async); + mite_sync_output_dma(devpriv->ao_mite_chan, s); spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } @@ -937,32 +943,6 @@ static void shutdown_ai_command(struct comedi_device *dev) s->async->events |= COMEDI_CB_EOA; } -static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | - COMEDI_CB_EOA)) { - switch (s->index) { - case NI_AI_SUBDEV: - ni_ai_reset(dev, s); - break; - case NI_AO_SUBDEV: - ni_ao_reset(dev, s); - break; - case NI_GPCT0_SUBDEV: - case NI_GPCT1_SUBDEV: - ni_gpct_cancel(dev, s); - break; - case NI_DIO_SUBDEV: - ni_cdio_cancel(dev, s); - break; - default: - break; - } - } - comedi_event(dev, s); -} - static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index) { @@ -974,8 +954,7 @@ static void handle_gpct_interrupt(struct comedi_device *dev, ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index], s); - if (s->async->events) - ni_event(dev, s); + cfc_handle_events(dev, s); #endif } @@ -1033,7 +1012,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (comedi_is_subdevice_running(s)) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - ni_event(dev, s); + cfc_handle_events(dev, s); } return; } @@ -1048,8 +1027,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (status & (AI_Overrun_St | AI_Overflow_St)) s->async->events |= COMEDI_CB_OVERFLOW; - ni_event(dev, s); - + cfc_handle_events(dev, s); return; } if (status & AI_SC_TC_St) { @@ -1076,7 +1054,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if ((status & AI_STOP_St)) ni_handle_eos(dev, s); - ni_event(dev, s); + cfc_handle_events(dev, s); } static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) @@ -1151,7 +1129,7 @@ static void handle_b_interrupt(struct comedi_device *dev, } #endif - ni_event(dev, s); + cfc_handle_events(dev, s); } #ifndef PCIDMA @@ -1171,7 +1149,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev, 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; @@ -1181,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++; @@ -1222,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; @@ -1252,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; @@ -1490,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); unsigned short *array = data; unsigned int *larray = data; + unsigned int i; for (i = 0; i < length; i++) { #ifdef PCIDMA @@ -1507,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; } } @@ -1527,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) { @@ -1567,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) { @@ -2102,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 */ @@ -2141,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) { @@ -2532,30 +2513,28 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } #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; } 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, @@ -2732,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; - unsigned int range; - unsigned int i; - unsigned int offset; + 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; - 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; } } @@ -2968,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 @@ -3239,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; } @@ -3250,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 */ @@ -3280,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) { @@ -3326,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; } @@ -3461,12 +3438,27 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev, 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 */ @@ -3506,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; @@ -3552,25 +3541,32 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) retval = ni_request_cdo_mite_channel(dev); 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); @@ -3645,7 +3641,7 @@ 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 @@ -3662,7 +3658,7 @@ static void handle_cdio_interrupt(struct comedi_device *dev) M_Offset_CDIO_Command); /* s->async->events |= COMEDI_CB_EOA; */ } - ni_event(dev, s); + cfc_handle_events(dev, s); } static int ni_serial_insn_config(struct comedi_device *dev, @@ -4282,10 +4278,14 @@ static int ni_E_init(struct comedi_device *dev) /* 8255 device */ s = &dev->subdevices[NI_8255_DIO_SUBDEV]; - if (board->has_8255) - subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev); - else + if (board->has_8255) { + ret = subdev_8255_init(dev, s, ni_8255_callback, + (unsigned long)dev); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* formerly general purpose counter/timer device, but no longer used */ s = &dev->subdevices[NI_UNUSED_SUBDEV]; @@ -4393,6 +4393,9 @@ static int ni_E_init(struct comedi_device *dev) &ni_gpct_read_register, counter_variant, NUM_GPCT); + if (!devpriv->counter_dev) + return -ENOMEM; + /* General purpose counters */ for (j = 0; j < NUM_GPCT; ++j) { s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; @@ -4483,7 +4486,6 @@ static int ni_E_init(struct comedi_device *dev) ni_writeb(0x0, M_Offset_AO_Calibration); } - printk("\n"); return 0; } @@ -4992,9 +4994,9 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } #endif +#ifdef PCIDMA static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { -#ifdef PCIDMA struct ni_gpct *counter = s->private; int retval; @@ -5002,10 +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 /* * diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 30c46a3c176..5fc74d6ff6a 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -263,9 +263,6 @@ enum FPGA_Control_Bits { #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -static int ni_pcidio_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - enum nidio_boardid { BOARD_PCIDIO_32HS, BOARD_PXI6533, @@ -353,17 +350,6 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } -static void ni_pcidio_event(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_pcidio_cancel(dev, s); - } - comedi_event(dev, s); -} - static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct nidio96_private *devpriv = dev->private; @@ -373,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); @@ -419,7 +405,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) 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 | @@ -461,8 +447,8 @@ static irqreturn_t nidio_interrupt(int irq, void *d) Group_1_FIFO); data1 = auxdata & 0xffff; data2 = (auxdata & 0xffff0000) >> 16; - comedi_buf_put(async, data1); - comedi_buf_put(async, data2); + comedi_buf_put(s, data1); + comedi_buf_put(s, data2); flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); } @@ -501,7 +487,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) } out: - ni_pcidio_event(dev, s); + cfc_handle_events(dev, s); #if 0 if (!tag) { writeb(0x03, @@ -550,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 */ @@ -609,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) @@ -773,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) { @@ -787,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); @@ -818,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; diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 0ed98045587..89300dc78e3 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1551,7 +1551,7 @@ static int pcimio_auto_attach(struct comedi_device *dev, dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change; dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change; - return ret; + return 0; } static int pcimio_ai_change(struct comedi_device *dev, @@ -1560,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; @@ -1573,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; @@ -1587,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; @@ -1601,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; @@ -1614,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; diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h index 68378dab4e7..1056bf001e5 100644 --- a/drivers/staging/comedi/drivers/ni_tio.h +++ b/drivers/staging/comedi/drivers/ni_tio.h @@ -115,10 +115,10 @@ struct ni_gpct { struct ni_gpct_device { struct comedi_device *dev; - void (*write_register) (struct ni_gpct *counter, unsigned bits, - enum ni_gpct_register reg); - unsigned (*read_register) (struct ni_gpct *counter, - enum ni_gpct_register reg); + void (*write_register)(struct ni_gpct *counter, unsigned bits, + enum ni_gpct_register reg); + unsigned (*read_register)(struct ni_gpct *counter, + enum ni_gpct_register reg); enum ni_gpct_variant variant; struct ni_gpct *counters; unsigned num_counters; diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 7d64f8892f0..2557ab48cb6 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -89,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); @@ -113,15 +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: @@ -162,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; @@ -176,9 +181,10 @@ 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; @@ -217,12 +223,12 @@ int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) "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); @@ -271,8 +277,16 @@ int ni_tio_cmdtest(struct comedi_device *dev, /* 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); @@ -450,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); diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index f0fc123ef56..c38d97a9a89 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -202,6 +202,7 @@ static irqreturn_t pcl711_interrupt(int irq, void *d) struct comedi_device *dev = d; struct pcl711_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int data; if (!dev->attached) { @@ -213,12 +214,11 @@ static irqreturn_t pcl711_interrupt(int irq, void *d) outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); - if (comedi_buf_put(s->async, data) == 0) { + 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 (s->async->cmd.stop_src == TRIG_COUNT && - !(--devpriv->ntrig)) { + if (cmd->stop_src == TRIG_COUNT && !(--devpriv->ntrig)) { pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); s->async->events |= COMEDI_CB_EOA; } @@ -253,18 +253,17 @@ static void pcl711_set_changain(struct comedi_device *dev, outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG); } -static int pcl711_ai_wait_for_eoc(struct comedi_device *dev, - unsigned int timeout) +static int pcl711_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned int msb; + unsigned int status; - while (timeout--) { - msb = inb(dev->iobase + PCL711_AI_MSB_REG); - if ((msb & PCL711_AI_MSB_DRDY) == 0) - return 0; - udelay(1); - } - return -ETIME; + status = inb(dev->iobase + PCL711_AI_MSB_REG); + if ((status & PCL711_AI_MSB_DRDY) == 0) + return 0; + return -EBUSY; } static int pcl711_ai_insn_read(struct comedi_device *dev, @@ -282,7 +281,7 @@ static int pcl711_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG); - ret = pcl711_ai_wait_for_eoc(dev, 100); + ret = comedi_timeout(dev, s, insn, pcl711_ai_eoc, 0); if (ret) return ret; @@ -296,8 +295,8 @@ 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 */ @@ -336,11 +335,8 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) { + if (cmd->stop_src == TRIG_NONE) err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } else { - /* ignore */ - } if (err) return 3; @@ -348,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; + arg = cmd->scan_begin_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, &devpriv->divisor1, &devpriv->divisor2, - &cmd->scan_begin_arg, - cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) @@ -364,6 +358,18 @@ 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; @@ -382,13 +388,8 @@ static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } if (cmd->scan_begin_src == TRIG_TIMER) { - i8254_load(dev->iobase + PCL711_TIMER_BASE, 0, - 1, devpriv->divisor1, I8254_MODE2 | I8254_BINARY); - i8254_load(dev->iobase + PCL711_TIMER_BASE, 0, - 2, devpriv->divisor2, I8254_MODE2 | I8254_BINARY); - + 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 { pcl711_ai_set_mode(dev, PCL711_MODE_EXT_IRQ); diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index cf9568ee46e..74f6489bd12 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -197,7 +197,7 @@ static int pcl726_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) @@ -240,7 +240,7 @@ static irqreturn_t pcl726_interrupt(int irq, void *d) if (devpriv->cmd_running) { pcl726_intr_cancel(dev, s); - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); comedi_event(dev, s); } @@ -430,6 +430,7 @@ static int pcl726_attach(struct comedi_device *dev, 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; diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index 2baaf1db6fb..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 * @@ -70,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 { @@ -158,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, }, }; diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 53613b385f3..4c1b9470647 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -131,34 +131,32 @@ #define boardACL8216 8 /* and ICP DAS A-826PG */ #define boardA821 9 /* PGH, PGL, PGL/NDA versions */ -#define PCLx1x_IORANGE 16 - -#define PCL812_CTR0 0 -#define PCL812_CTR1 1 -#define PCL812_CTR2 2 -#define PCL812_CTRCTL 3 -#define PCL812_AD_LO 4 -#define PCL812_DA1_LO 4 -#define PCL812_AD_HI 5 -#define PCL812_DA1_HI 5 -#define PCL812_DA2_LO 6 -#define PCL812_DI_LO 6 -#define PCL812_DA2_HI 7 -#define PCL812_DI_HI 7 -#define PCL812_CLRINT 8 -#define PCL812_GAIN 9 -#define PCL812_MUX 10 -#define PCL812_MODE 11 -#define PCL812_CNTENABLE 10 -#define PCL812_SOFTTRIG 12 -#define PCL812_DO_LO 13 -#define PCL812_DO_HI 14 - -#define PCL812_DRDY 0x10 /* =0 data ready */ - -#define ACL8216_STATUS 8 /* 5. bit signalize data ready */ - -#define ACL8216_DRDY 0x20 /* =0 data ready */ +/* + * Register I/O map + */ +#define PCL812_TIMER_BASE 0x00 +#define PCL812_AI_LSB_REG 0x04 +#define PCL812_AI_MSB_REG 0x05 +#define PCL812_AI_MSB_DRDY (1 << 4) +#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL812_DI_LSB_REG 0x06 +#define PCL812_DI_MSB_REG 0x07 +#define PCL812_STATUS_REG 0x08 +#define PCL812_STATUS_DRDY (1 << 5) +#define PCL812_RANGE_REG 0x09 +#define PCL812_MUX_REG 0x0a +#define PCL812_MUX_CHAN(x) ((x) << 0) +#define PCL812_MUX_CS0 (1 << 4) +#define PCL812_MUX_CS1 (1 << 5) +#define PCL812_CTRL_REG 0x0b +#define PCL812_CTRL_DISABLE_TRIG (0 << 0) +#define PCL812_CTRL_SOFT_TRIG (1 << 0) +#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0) +#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0) +#define PCL812_SOFTTRIG_REG 0x0c +#define PCL812_DO_LSB_REG 0x0d +#define PCL812_DO_MSB_REG 0x0e #define MAX_CHANLIST_LEN 256 /* length of scan list */ @@ -331,213 +329,388 @@ static const struct comedi_lrange range_a821pgh_ai = { }; struct pcl812_board { + const char *name; + int board_type; + int n_aichan; + int n_aochan; + unsigned int ai_ns_min; + const struct comedi_lrange *rangelist_ai; + unsigned int IRQbits; + unsigned int has_dma:1; + unsigned int has_16bit_ai:1; + unsigned int has_mpc508_mux:1; + unsigned int has_dio:1; +}; - const char *name; /* board name */ - int board_type; /* type of this board */ - int n_aichan; /* num of AI chans in S.E. */ - int n_aichan_diff; /* DIFF num of chans */ - int n_aochan; /* num of DA chans */ - int n_dichan; /* DI and DO chans */ - int n_dochan; - int ai_maxdata; /* AI resolution */ - unsigned int ai_ns_min; /* max sample speed of card v ns */ - unsigned int i8254_osc_base; /* clock base */ - const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ - unsigned int IRQbits; /* allowed IRQ */ - unsigned char DMAbits; /* allowed DMA chans */ - unsigned char io_range; /* iorange for this board */ - unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ +static const struct pcl812_board boardtypes[] = { + { + .name = "pcl812", + .board_type = boardPCL812, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_bipolar10, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl812pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112dg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "acl8112hg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a821pgl", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a821pglnda", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + }, { + .name = "a821pgh", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_a821pgh_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a822pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a822pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl813", + .board_type = boardPCL813, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "pcl813b", + .board_type = boardPCL813B, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "acl8113", + .board_type = boardACL8113, + .n_aichan = 32, + .rangelist_ai = &range_acl8113_1_ai, + }, { + .name = "iso813", + .board_type = boardISO813, + .n_aichan = 32, + .rangelist_ai = &range_iso813_1_ai, + }, { + .name = "acl8216", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a826pg", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_dio = 1, + }, }; struct pcl812_private { - - unsigned char valid; /* =1 device is OK */ unsigned char dma; /* >0 use dma ( usedDMA channel) */ - unsigned char use_diff; /* =1 diff inputs */ - unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */ - unsigned char use_ext_trg; /* 1=board uses external trigger */ unsigned char range_correction; /* =1 we must add 1 to range number */ - unsigned char old_chan_reg; /* lastly used chan/gain pair */ - unsigned char old_gain_reg; + unsigned int last_ai_chanspec; unsigned char mode_reg_int; /* there is stored INT number for some card */ - unsigned char ai_neverending; /* =1 we do unlimited AI */ - unsigned char ai_eos; /* 1=EOS wake up */ - unsigned char ai_dma; /* =1 we use DMA */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - unsigned int ai_scans; /* len of scanlist */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - unsigned int ai_is16b; /* =1 we have 16 bit card */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* PTR to DMA buf */ - unsigned int dmapages[2]; /* how many pages we have allocated */ unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ - unsigned int hwdmasize[2]; /* DMA buf size in bytes */ unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */ int next_dma_buf; /* which buffer is next to use */ unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ unsigned int ao_readback[2]; /* data for AO readback */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int use_diff:1; + unsigned int use_mpc508:1; + unsigned int use_ext_trg:1; + unsigned int ai_dma:1; + unsigned int ai_eos:1; }; -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait); -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -/* -============================================================================== -*/ -static int pcl812_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers) { struct pcl812_private *devpriv = dev->private; - int n; - int timeout, hi; - - /* select software trigger */ - outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - hi = inb(dev->iobase + PCL812_AD_HI); - if (!(hi & PCL812_DRDY)) - goto conv_finish; - udelay(1); - } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return -ETIME; + unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); -conv_finish: - data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO); + if (load_timers) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return n; } -/* -============================================================================== -*/ -static int acl8216_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - int n; - int timeout; - - /* select software trigger */ - outb(1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) - goto conv_finish; - udelay(1); + struct pcl812_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; + + /* we use EOS, so adapt DMA buffer to one scan */ + if (devpriv->ai_eos) { + devpriv->dmabytestomove[0] = 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; } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(0, dev->iobase + PCL812_MODE); - return -ETIME; - -conv_finish: - data[n] = - (inb(dev->iobase + - PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO); + if (cmd->stop_src == TRIG_NONE) { + devpriv->dma_runs_to_end = 1; + } else { + /* how many samples we must transfer? */ + bytes = cmd->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); - return i; + if (wait) + /* + * XXX this depends on selected range and can be very long for + * some high gain ranges! + */ + udelay(devpriv->max_812_ai_mode0_rangewait); } -/* -============================================================================== -*/ -static int pcl812_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_clear_eoc(struct comedi_device *dev) { - data[1] = inb(dev->iobase + PCL812_DI_LO); - data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8; + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL812_STATUS_REG); +} - return insn->n; +static void pcl812_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(255, dev->iobase + PCL812_SOFTTRIG_REG); } -static int pcl812_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static unsigned int pcl812_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) { - if (comedi_dio_update_state(s, data)) { - outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); - outb((s->state >> 8), dev->iobase + PCL812_DO_HI); - } + unsigned int val; - data[1] = s->state; + val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL812_AI_LSB_REG); - return insn->n; + return val & s->maxdata; +} + +static int pcl812_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + if (s->maxdata > 0x0fff) { + status = inb(dev->iobase + PCL812_STATUS_REG); + if ((status & PCL812_STATUS_DRDY) == 0) + return 0; + } else { + status = inb(dev->iobase + PCL812_AI_MSB_REG); + if ((status & PCL812_AI_MSB_DRDY) == 0) + return 0; + } + return -EBUSY; } -/* -============================================================================== -*/ static int pcl812_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -545,7 +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 */ @@ -585,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) @@ -599,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); - 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) @@ -615,69 +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); - } - - 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; - 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; @@ -685,197 +813,100 @@ 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->read_subdev; - unsigned int next_chan; + struct comedi_cmd *cmd = &s->async->cmd; - s->async->events = 0; + s->async->events |= COMEDI_CB_BLOCK; - timeout = 50; /* wait max 50us, it must finish under 33us */ - if (devpriv->ai_is16b) { - mask = 0xffff; - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } else { - mask = 0x0fff; - while (timeout--) { - if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { - err = 0; - break; - } - udelay(1); - } + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; } - if (err) { + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; + } + + return true; +} + +static void pcl812_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int next_chan; + + if (pcl812_ai_eoc(dev, s, NULL, 0)) { dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); - pcl812_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - comedi_buf_put(s->async, - ((inb(dev->iobase + PCL812_AD_HI) << 8) | - inb(dev->iobase + PCL812_AD_LO)) & mask); + comedi_buf_put(s, 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); + if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan]) + pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0); - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - - s->async->cur_chan = next_chan; - if (next_chan == 0) { /* one scan done */ - devpriv->ai_act_scan++; - if (!(devpriv->ai_neverending)) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - } - - comedi_event(dev, s); - return IRQ_HANDLED; + pcl812_ai_next_chan(dev, s); } -/* -============================================================================== -*/ static void transfer_from_dma_buf(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short *ptr, unsigned int bufptr, unsigned int len) { - struct pcl812_private *devpriv = dev->private; unsigned int i; - s->async->events = 0; for (i = len; i; i--) { - /* get one sample */ - comedi_buf_put(s->async, ptr[bufptr++]); - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - break; - } - } - } + 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->read_subdev; - unsigned long dma_flags; int len, bufptr; unsigned short *ptr; @@ -883,58 +914,36 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - devpriv->ai_poll_ptr; - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - disable_dma(devpriv->dma); - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->ai_eos) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv->next_dma_buf]); - } else { - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - devpriv->dma_runs_to_end--; - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + pcl812_ai_setup_next_dma(dev, s); bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); - - return IRQ_HANDLED; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812(int irq, void *d) +static irqreturn_t pcl812_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; struct pcl812_private *devpriv = dev->private; if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); + pcl812_ai_clear_eoc(dev); return IRQ_HANDLED; } + if (devpriv->ai_dma) - return interrupt_pcl812_ai_dma(irq, d); + pcl812_handle_dma(dev, s); else - return interrupt_pcl812_ai_int(irq, d); + pcl812_handle_eoc(dev, s); + + pcl812_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; @@ -979,204 +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 dma; - unsigned long pages; struct comedi_subdevice *s; int n_subdevices; - - ret = comedi_request_region(dev, it->options[0], board->io_range); - if (ret) - return ret; + int subdev; + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl812, 0, + ret = request_irq(it->options[1], pcl812_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (((1 << dma) & board->DMAbits) == 0) { - dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { dev_err(dev->class_dev, - "unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ - } - devpriv->dma = dma; - pages = 1; /* we want 8KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages); - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages); + devpriv->dma = it->options[2]; + + devpriv->dmapages = 1; /* we want 8KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } } -no_dma: - n_subdevices = 0; - if (board->n_aichan > 0) - n_subdevices++; + /* differential analog inputs? */ + switch (board->board_type) { + case boardA821: + if (it->options[2] == 1) + devpriv->use_diff = 1; + break; + case boardACL8112: + case boardACL8216: + if (it->options[4] == 1) + devpriv->use_diff = 1; + break; + } + + n_subdevices = 1; /* all boardtypes have analog inputs */ if (board->n_aochan > 0) n_subdevices++; - if (board->n_dichan > 0) - n_subdevices++; - if (board->n_dochan > 0) - n_subdevices++; + if (board->has_dio) + n_subdevices += 2; ret = comedi_alloc_subdevices(dev, n_subdevices); if (ret) @@ -1184,146 +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->range_table = board->rangelist_ai; - if (board->board_type == boardACL8216) - s->insn_read = acl8216_ai_insn_read; - else - s->insn_read = pcl812_ai_insn_read; - - devpriv->use_MPC = board->haveMPC508; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = MAX_CHANLIST_LEN; - s->do_cmdtest = pcl812_ai_cmdtest; - s->do_cmd = pcl812_ai_cmd; - s->poll = pcl812_ai_poll; - s->cancel = pcl812_ai_cancel; - } - switch (board->board_type) { - case boardPCL812PG: - if (it->options[4] == 1) - s->range_table = &range_pcl812pg2_ai; - break; - case boardPCL812: - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range812_bipolar1_25; - break; - case 4: - s->range_table = &range812_bipolar0_625; - break; - case 5: - s->range_table = &range812_bipolar0_3125; - break; - default: - s->range_table = &range_bipolar10; - break; - } - break; - break; - case boardPCL813B: - if (it->options[1] == 1) - s->range_table = &range_pcl813b2_ai; - break; - case boardISO813: - switch (it->options[1]) { - case 0: - s->range_table = &range_iso813_1_ai; - break; - case 1: - s->range_table = &range_iso813_1_2_ai; - break; - case 2: - s->range_table = &range_iso813_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_iso813_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_iso813_1_ai; - break; - } - break; - case boardACL8113: - switch (it->options[1]) { - case 0: - s->range_table = &range_acl8113_1_ai; - break; - case 1: - s->range_table = &range_acl8113_1_2_ai; - break; - case 2: - s->range_table = &range_acl8113_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_acl8113_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_acl8113_1_ai; - break; - } - break; - } - subdev++; + /* Analog Input subdevice */ + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (devpriv->use_diff) { + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan / 2; + } else { + s->subdev_flags |= SDF_GROUND; + s->n_chan = board->n_aichan; + } + s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff; + + pcl812_set_ai_range_table(dev, s, it); + + s->insn_read = pcl812_ai_insn_read; + + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = MAX_CHANLIST_LEN; + s->do_cmdtest = pcl812_ai_cmdtest; + s->do_cmd = pcl812_ai_cmd; + s->poll = pcl812_ai_poll; + s->cancel = pcl812_ai_cancel; } + devpriv->use_mpc508 = board->has_mpc508_mux; + + subdev++; + /* analog output */ if (board->n_aochan > 0) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->range_table = board->rangelist_ao; - s->insn_read = pcl812_ao_insn_read; - s->insn_write = pcl812_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &range_unipolar5; + s->insn_read = pcl812_ao_insn_read; + s->insn_write = pcl812_ao_insn_write; switch (board->board_type) { case boardA821: if (it->options[3] == 1) @@ -1342,33 +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->range_table = &range_digital; - s->insn_bits = pcl812_di_insn_bits; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_di_insn_bits; subdev++; - } - /* digital output */ - if (board->n_dochan > 0) { + /* Digital Output subdevice */ s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl812_do_insn_bits; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_do_insn_bits; subdev++; } switch (board->board_type) { case boardACL8216: - devpriv->ai_is16b = 1; case boardPCL812PG: case boardPCL812: case boardACL8112: @@ -1390,8 +1401,6 @@ no_dma: break; } - devpriv->valid = 1; - pcl812_reset(dev); return 0; @@ -1403,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, I8254_OSC_BASE_2MHZ, &range_bipolar10, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 33000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, NULL, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_a821pgh_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_acl8113_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_iso813_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, -}; - static struct comedi_driver pcl812_driver = { .driver_name = "pcl812", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index e9d47045993..d9ca7fe16c9 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -44,40 +44,38 @@ Configuration Options: #include "comedi_fc.h" #include "8253.h" -/* boards constants */ -/* IO space len */ -#define PCLx1x_RANGE 16 - -/* INTEL 8254 counters */ -#define PCL816_CTR0 4 -#define PCL816_CTR1 5 -#define PCL816_CTR2 6 -/* R: counter read-back register W: counter control */ -#define PCL816_CTRCTL 7 - -/* R: A/D high byte W: A/D range control */ -#define PCL816_RANGE 9 -/* W: clear INT request */ -#define PCL816_CLRINT 10 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL816_MUX 11 -/* R/W: operation control register */ -#define PCL816_CONTROL 12 - -/* R: return status byte W: set DMA/IRQ */ -#define PCL816_STATUS 13 -#define PCL816_STATUS_DRDY_MASK 0x80 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL816_AD_LO 8 -/* R: high byte of A/D W: A/D range control */ -#define PCL816_AD_HI 9 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 +/* + * Register I/O map + */ +#define PCL816_DO_DI_LSB_REG 0x00 +#define PCL816_DO_DI_MSB_REG 0x01 +#define PCL816_TIMER_BASE 0x04 +#define PCL816_AI_LSB_REG 0x08 +#define PCL816_AI_MSB_REG 0x09 +#define PCL816_RANGE_REG 0x09 +#define PCL816_CLRINT_REG 0x0a +#define PCL816_MUX_REG 0x0b +#define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL816_CTRL_REG 0x0c +#define PCL816_CTRL_DISABLE_TRIG (0 << 0) +#define PCL816_CTRL_SOFT_TRIG (1 << 0) +#define PCL816_CTRL_PACER_TRIG (1 << 1) +#define PCL816_CTRL_EXT_TRIG (1 << 2) +#define PCL816_CTRL_POE (1 << 3) +#define PCL816_CTRL_DMAEN (1 << 4) +#define PCL816_CTRL_INTEN (1 << 5) +#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6) +#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6) +#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6) +#define PCL816_STATUS_REG 0x0d +#define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL816_STATUS_INTSRC_MASK (3 << 4) +#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4) +#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4) +#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4) +#define PCL816_STATUS_INTSRC_DMA (3 << 4) +#define PCL816_STATUS_INTACT (1 << 6) +#define PCL816_STATUS_DRDY (1 << 7) #define MAGIC_DMA_WORD 0x5a5a @@ -95,314 +93,282 @@ static const struct comedi_lrange range_pcl816 = { }; struct pcl816_board { + const char *name; + int ai_maxdata; + int ao_maxdata; + int ai_chanlist; +}; - const char *name; /* board name */ - int n_ranges; /* len of range list */ - int n_aichan; /* num of A/D chans in diferencial mode */ - unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - int ai_chanlist; /* allowed len of channel list A/D */ - int ao_chanlist; /* allowed len of channel list D/A */ - int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ +static const struct pcl816_board boardtypes[] = { + { + .name = "pcl816", + .ai_maxdata = 0xffff, + .ao_maxdata = 0xffff, + .ai_chanlist = 1024, + }, { + .name = "pcl814b", + .ai_maxdata = 0x3fff, + .ao_maxdata = 0x3fff, + .ai_chanlist = 1024, + }, }; struct pcl816_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ - unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - - unsigned int ai_scans; /* len of scanlist */ - unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */ - int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */ - unsigned int ai_act_chanlist_len; /* how long is actual MUX list */ - unsigned int ai_act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_n_chan; /* how many channels per scan */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -/* -============================================================================== -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int chanlen); -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int seglen); -static int pcl816_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static int pcl816_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); - -/* -============================================================================== - ANALOG INPUT MODE0, 816 cards, slow version -*/ -static int pcl816_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; - - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL816_CONTROL); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Set the input channel */ - outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); - - for (n = 0; n < insn->n; n++) { - - outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */ - - timeout = 100; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) { - /* return read value */ - data[n] = - ((inb(dev->iobase + - PCL816_AD_HI) << 8) | - (inb(dev->iobase + PCL816_AD_LO))); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - break; - } - udelay(1); - } - /* Return timeout error */ - if (!timeout) { - comedi_error(dev, "A/D insn timeout\n"); - data[0] = 0; - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - return -EIO; - } + struct pcl816_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 0, I8254_MODE1 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x00ff); + udelay(1); + + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - return n; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) +static void pcl816_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl816_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned char low, hi; - int timeout = 50; /* wait max 50us */ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) - break; - udelay(1); + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + /* how many */ + bytes = 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); } - if (!timeout) { /* timeout, bail error */ - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + devpriv->dma_runs_to_end--; +} + +static void pcl816_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) +{ + outb(chan, dev->iobase + PCL816_MUX_REG); + outb(range, dev->iobase + PCL816_RANGE_REG); +} + +static void pcl816_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL816_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL816_MUX_REG); +} + +static void pcl816_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) +{ + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + unsigned int i; + + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + pcl816_ai_set_chan_range(dev, last_chan, range); } - /* get the sample */ - low = inb(dev->iobase + PCL816_AD_LO); - hi = inb(dev->iobase + PCL816_AD_HI); + udelay(1); - comedi_buf_put(s->async, (hi << 8) | low); + pcl816_ai_set_chan_scan(dev, first_chan, last_chan); +} - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ +static void pcl816_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL816_CLRINT_REG); +} - if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len) - devpriv->ai_act_chanlist_pos = 0; +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); +} + +static unsigned int pcl816_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL816_AI_LSB_REG); + + return val & s->maxdata; +} + +static int pcl816_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + PCL816_STATUS_REG); + if ((status & PCL816_STATUS_DRDY) == 0) + return 0; + return -EBUSY; +} + +static bool pcl816_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { + if (s->async->cur_chan >= cmd->chanlist_len) { s->async->cur_chan = 0; devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; } - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); - return IRQ_HANDLED; + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; + } + + return true; } -/* -============================================================================== - analog input dma mode 1 & 3, 816 cards -*/ static void transfer_from_dma_buf(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short *ptr, unsigned int bufptr, unsigned int len) { - struct pcl816_private *devpriv = dev->private; int i; - s->async->events = 0; - for (i = 0; i < len; i++) { + comedi_buf_put(s, ptr[bufptr++]); - comedi_buf_put(s->async, ptr[bufptr++]); - - if (++devpriv->ai_act_chanlist_pos >= - devpriv->ai_act_chanlist_len) { - devpriv->ai_act_chanlist_pos = 0; - } - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - } - - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_BLOCK; - break; - } + if (!pcl816_ai_next_chan(dev, s)) + return; } - - comedi_event(dev, s); } -static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) +static irqreturn_t pcl816_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct pcl816_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - int len, bufptr, this_dma_buf; - unsigned long dma_flags; + struct pcl816_private *devpriv = dev->private; unsigned short *ptr; + unsigned int bufptr; + unsigned int len; - disable_dma(devpriv->dma); - this_dma_buf = devpriv->next_dma_buf; - - /* switch dma bufs */ - if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; + } - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); -/* clear_dma_ff (devpriv->dma); */ - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); + if (devpriv->ai_cmd_canceled) { + devpriv->ai_cmd_canceled = 0; + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; } - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; - ptr = (unsigned short *)devpriv->dmabuf[this_dma_buf]; + pcl816_ai_setup_next_dma(dev, s); - len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr; + len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr; bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); - return IRQ_HANDLED; -} - -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl816(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl816_private *devpriv = dev->private; - - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; - } - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl816_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl816_ai_mode13_int(irq, d); - } + pcl816_ai_clear_eoc(dev); - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - if (!dev->irq || !devpriv->irq_blocked || !devpriv->int816_mode) { - if (devpriv->irq_was_now_closed) { - devpriv->irq_was_now_closed = 0; - /* comedi_error(dev,"last IRQ.."); */ - return IRQ_HANDLED; - } - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl816_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcl816_board *board = comedi_board(dev); + struct pcl816_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -432,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); @@ -450,14 +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); - 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) @@ -477,120 +440,40 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl; unsigned int seglen; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; -/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */ - if (devpriv->irq_blocked) + if (devpriv->ai_cmd_running) return -EBUSY; - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, cmd->flags); - - /* PCL816 crash if any divisor is set to 1 */ - if (divisor1 == 1) { - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl816_start_pacer(dev, false); seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); if (seglen < 1) return -EINVAL; - setup_channel_list(dev, s, cmd->chanlist, seglen); + pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen); udelay(1); - devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->irq_blocked = 1; + devpriv->ai_cmd_running = 1; devpriv->ai_poll_ptr = 0; - devpriv->irq_was_now_closed = 0; + devpriv->ai_cmd_canceled = 0; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; - } - - if (devpriv->dma) { - bytes = devpriv->hwdmasize[0]; - if (!devpriv->ai_neverending) { - /* how many */ - bytes = s->async->cmd.chanlist_len * - s->async->cmd.chanlist_len * - sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = bytes / - devpriv->hwdmasize[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } else - devpriv->dma_runs_to_end = -1; - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } - - start_pacer(dev, 1, divisor1, divisor2); - dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7); - - switch (cmd->convert_src) { - case TRIG_TIMER: - devpriv->int816_mode = INT_TYPE_AI1_DMA; - - /* Pacer+IRQ+DMA */ - outb(0x32, dev->iobase + PCL816_CONTROL); + pcl816_ai_setup_dma(dev, s); - /* write irq and DMA to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; + pcl816_start_pacer(dev, true); - default: - devpriv->int816_mode = INT_TYPE_AI3_DMA; - - /* Ext trig+IRQ+DMA */ - outb(0x34, dev->iobase + PCL816_CONTROL); + ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL816_CTRL_PACER_TRIG; + else /* TRIG_EXT */ + ctrl |= PCL816_CTRL_EXT_TRIG; - /* write irq to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; - } + outb(ctrl, dev->iobase + PCL816_CTRL_REG); + outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG); return 0; } @@ -601,9 +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++) { @@ -618,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 */ @@ -634,134 +514,34 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_poll_ptr = top1; /* new buffer position */ spin_unlock_irqrestore(&dev->spinlock, flags); + cfc_handle_events(dev, s); + return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl816_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; - if (devpriv->irq_blocked > 0) { - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, - dev->iobase + PCL816_CONTROL); /* Stop A/D */ - udelay(1); - outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ - - /* Stop pacer */ - outb(0xb0, dev->iobase + PCL816_CTRCTL); - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_HI); - - /* clear INT request */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Stop A/D */ - outb(0, dev->iobase + PCL816_CONTROL); - devpriv->irq_blocked = 0; - devpriv->irq_was_now_closed = devpriv->int816_mode; - devpriv->int816_mode = 0; - devpriv->last_int_sub = s; -/* s->busy = 0; */ - break; - } - } - return 0; -} - -/* -============================================================================== - chech for PCL816 -*/ -static int pcl816_check(unsigned long iobase) -{ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - outb(0x18, iobase + PCL816_CONTROL); - udelay(1); - if (inb(iobase + PCL816_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ -} - -/* -============================================================================== - reset whole PCL-816 cards -*/ -static void pcl816_reset(struct comedi_device *dev) -{ -/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */ -/* outb (0, dev->iobase + PCL818_DA_HI); */ -/* udelay (1); */ -/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */ -/* outb (0, dev->iobase + PCL818_DO_LO); */ -/* udelay (1); */ - outb(0, dev->iobase + PCL816_CONTROL); - outb(0, dev->iobase + PCL816_MUX); - outb(0, dev->iobase + PCL816_CLRINT); - outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0x30, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_RANGE); -} + if (!devpriv->ai_cmd_running) + return 0; -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void -start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, - unsigned int divisor2) -{ - outb(0x32, dev->iobase + PCL816_CTRCTL); - outb(0xff, dev->iobase + PCL816_CTR0); - outb(0x00, dev->iobase + PCL816_CTR0); - udelay(1); + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - /* set counter 2 as mode 3 */ - outb(0xb4, dev->iobase + PCL816_CTRCTL); - /* set counter 1 as mode 3 */ - outb(0x74, dev->iobase + PCL816_CTRCTL); - udelay(1); + /* Stop pacer */ + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 1, I8254_MODE0 | I8254_BINARY); - if (mode == 1) { - dev_dbg(dev->class_dev, "mode %d, divisor1 %d, divisor2 %d\n", - mode, divisor1, divisor2); - outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1); - } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 1; - /* clear pending interrupts (just in case) */ -/* outb(0, dev->iobase + PCL816_CLRINT); */ + return 0; } -/* -============================================================================== - Check if channel list from user is built correctly - If it's ok, then return non-zero length of repeated segment of channel list -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, @@ -818,180 +598,181 @@ check_channel_list(struct comedi_device *dev, return seglen; /* we can serve this with MUX logic */ } -/* -============================================================================== - Program scan/gain logic with channel list. -*/ -static void -setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int *chanlist, - unsigned int seglen) +static int pcl816_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pcl816_private *devpriv = dev->private; - unsigned int i; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; - devpriv->ai_act_chanlist_len = seglen; - devpriv->ai_act_chanlist_pos = 0; + outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG); - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); + pcl816_ai_set_chan_range(dev, chan, range); + pcl816_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl816_ai_clear_eoc(dev); + pcl816_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl816_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl816_ai_get_sample(dev, s); } + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - udelay(1); - /* select channel interval to scan */ - outb(devpriv->ai_act_chanlist[0] | - (devpriv->ai_act_chanlist[seglen - 1] << 4), - dev->iobase + PCL816_MUX); + return ret ? ret : insn->n; +} + +static int pcl816_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl816_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG); + } + + data[1] = s->state; + + return insn->n; +} + +static void pcl816_reset(struct comedi_device *dev) +{ + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_set_chan_range(dev, 0, 0); + pcl816_ai_clear_eoc(dev); + + /* Stop pacer */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL816_DO_DI_LSB_REG); + outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); } static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv; - int ret; - unsigned int dma; - unsigned long pages; - /* int i; */ struct comedi_subdevice *s; - - ret = comedi_request_region(dev, it->options[0], board->io_range); - if (ret) - return ret; - - if (pcl816_check(dev->iobase)) { - dev_err(dev->class_dev, "I can't detect board. FAIL!\n"); - return -EIO; - } + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl816, 0, + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl816_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->int816_mode = 0; /* mode of irq */ - - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - - if (((1 << dma) & board->DMAbits) == 0) { - dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { dev_err(dev->class_dev, - "unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ + "unable to request DMA channel %d\n", + it->options[2]); + return -EBUSY; } + devpriv->dma = it->options[2]; - devpriv->dma = dma; - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; - if (!devpriv->dmabuf[0]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; + for (i = 0; i < 2; i++) { + unsigned long dmabuf; - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - return -EBUSY; + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; } -no_dma: - -/* if (board->n_aochan > 0) - subdevs[1] = COMEDI_SUBD_AO; - if (board->n_dichan > 0) - subdevs[2] = COMEDI_SUBD_DI; - if (board->n_dochan > 0) - subdevs[3] = COMEDI_SUBD_DO; -*/ - - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (board->n_aichan > 0) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_CMD_READ | SDF_DIFF; - s->n_chan = board->n_aichan; - s->maxdata = board->ai_maxdata; - s->range_table = board->ai_range_type; - s->insn_read = pcl816_ai_insn_read; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = board->ai_chanlist; - s->do_cmdtest = pcl816_ai_cmdtest; - s->do_cmd = pcl816_ai_cmd; - s->poll = pcl816_ai_poll; - s->cancel = pcl816_ai_cancel; - } - } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_CMD_READ | SDF_DIFF; + s->n_chan = 16; + s->maxdata = board->ai_maxdata; + s->range_table = &range_pcl816; + s->insn_read = pcl816_ai_insn_read; + if (devpriv->dma) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = board->ai_chanlist; + s->do_cmdtest = pcl816_ai_cmdtest; + s->do_cmd = pcl816_ai_cmd; + s->poll = pcl816_ai_poll; + s->cancel = pcl816_ai_cancel; } + /* Analog OUtput subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_UNUSED; #if 0 -case COMEDI_SUBD_AO: + subdevs[1] = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; + s->n_chan = 1; s->maxdata = board->ao_maxdata; - s->len_chanlist = board->ao_chanlist; - s->range_table = board->ao_range_type; - break; - -case COMEDI_SUBD_DI: - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->len_chanlist = board->n_dichan; - s->range_table = &range_digital; - break; - -case COMEDI_SUBD_DO: - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->len_chanlist = board->n_dochan; - s->range_table = &range_digital; - break; + s->range_table = &range_pcl816; #endif + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_do_insn_bits; + pcl816_reset(dev); return 0; @@ -1007,34 +788,13 @@ static void pcl816_detach(struct comedi_device *dev) if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl816_board boardtypes[] = { - {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, /* IRQ mask */ - 0x0a, /* DMA mask */ - 0xffff, /* 16-bit card */ - 0xffff, /* D/A maxdata */ - 1024, - 1, /* ao chan list */ - I8254_OSC_BASE_10MHZ}, - {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, - 0x0a, - 0x3fff, /* 14 bit card */ - 0x3fff, - 1024, - 1, - I8254_OSC_BASE_10MHZ}, -}; - static struct comedi_driver pcl816_driver = { .driver_name = "pcl816", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index fa1758ad49d..7d00ae639d3 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -110,8 +110,6 @@ A word or two about DMA. Driver support DMA operations at two ways: #include "comedi_fc.h" #include "8253.h" -/* #define PCL818_MODE13_AO 1 */ - /* boards constants */ #define boardPCL818L 0 @@ -121,46 +119,38 @@ A word or two about DMA. Driver support DMA operations at two ways: #define boardPCL818 4 #define boardPCL718 5 -/* IO space len */ -#define PCLx1x_RANGE 16 -/* IO space len if we use FIFO */ -#define PCLx1xFIFO_RANGE 32 - -/* W: clear INT request */ -#define PCL818_CLRINT 8 -/* R: return status byte */ -#define PCL818_STATUS 8 -/* R: A/D high byte W: A/D range control */ -#define PCL818_RANGE 1 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL818_MUX 2 -/* R/W: operation control register */ -#define PCL818_CONTROL 9 -/* W: counter enable */ -#define PCL818_CNTENABLE 10 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL818_AD_LO 0 -/* R: high byte of A/D W: A/D range control */ -#define PCL818_AD_HI 1 -/* W: D/A low&high byte */ -#define PCL818_DA_LO 4 -#define PCL818_DA_HI 5 -/* R: low&high byte of DI */ -#define PCL818_DI_LO 3 -#define PCL818_DI_HI 11 -/* W: low&high byte of DO */ -#define PCL818_DO_LO 3 -#define PCL818_DO_HI 11 -/* W: PCL718 second D/A */ -#define PCL718_DA2_LO 6 -#define PCL718_DA2_HI 7 -/* counters */ -#define PCL818_CTR0 12 -#define PCL818_CTR1 13 -#define PCL818_CTR2 14 -/* W: counter control */ -#define PCL818_CTRCTL 15 +/* + * Register I/O map + */ +#define PCL818_AI_LSB_REG 0x00 +#define PCL818_AI_MSB_REG 0x01 +#define PCL818_RANGE_REG 0x01 +#define PCL818_MUX_REG 0x02 +#define PCL818_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL818_DO_DI_LSB_REG 0x03 +#define PCL818_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL818_STATUS_REG 0x08 +#define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL818_STATUS_INT (1 << 4) +#define PCL818_STATUS_MUX (1 << 5) +#define PCL818_STATUS_UNI (1 << 6) +#define PCL818_STATUS_EOC (1 << 7) +#define PCL818_CTRL_REG 0x09 +#define PCL818_CTRL_DISABLE_TRIG (0 << 0) +#define PCL818_CTRL_SOFT_TRIG (1 << 0) +#define PCL818_CTRL_EXT_TRIG (2 << 0) +#define PCL818_CTRL_PACER_TRIG (3 << 0) +#define PCL818_CTRL_DMAE (1 << 2) +#define PCL818_CTRL_IRQ(x) ((x) << 4) +#define PCL818_CTRL_INTE (1 << 7) +#define PCL818_CNTENABLE_REG 0x0a +#define PCL818_CNTENABLE_PACER_ENA (0 << 0) +#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0) +#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1) +#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1) +#define PCL818_DO_DI_MSB_REG 0x0b +#define PCL818_TIMER_BASE 0x0c /* W: fifo enable/disable */ #define PCL818_FI_ENABLE 6 @@ -172,19 +162,7 @@ A word or two about DMA. Driver support DMA operations at two ways: #define PCL818_FI_STATUS 25 /* R: one record from FIFO */ #define PCL818_FI_DATALO 23 -#define PCL818_FI_DATAHI 23 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI1_FIFO 3 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 -#define INT_TYPE_AI3_FIFO 6 -#ifdef PCL818_MODE13_AO -#define INT_TYPE_AO1_INT 7 -#define INT_TYPE_AO3_INT 8 -#endif +#define PCL818_FI_DATAHI 24 #define MAGIC_DMA_WORD 0x5a5a @@ -262,630 +240,439 @@ static const struct comedi_lrange range718_unipolar1 = { }; struct pcl818_board { + const char *name; + unsigned int ns_min; + int n_aochan; + const struct comedi_lrange *ai_range_type; + unsigned int has_dma:1; + unsigned int has_fifo:1; + unsigned int is_818:1; +}; - const char *name; /* driver name */ - int n_ranges; /* len of range list */ - int n_aichan_se; /* num of A/D chans in single ended mode */ - int n_aichan_diff; /* num of A/D chans in diferencial mode */ - unsigned int ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - unsigned char fifo; /* 1=board has FIFO */ - int is_818; +static const struct pcl818_board boardtypes[] = { + { + .name = "pcl818l", + .ns_min = 25000, + .n_aochan = 1, + .ai_range_type = &range_pcl818l_l_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818h", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818hd", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818hg", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818hg_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818", + .ns_min = 10000, + .n_aochan = 2, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl718", + .ns_min = 16000, + .n_aochan = 2, + .ai_range_type = &range_unipolar5, + .has_dma = 1, + }, { + .name = "pcm3718", + .ns_min = 10000, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, }; struct pcl818_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ - unsigned int io_range; + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */ unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */ int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */ - int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ int ai_act_chan; /* actual position in actual scan */ unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ unsigned int act_chanlist_len; /* how long is actual MUX list */ unsigned int act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; - unsigned char usefifo; /* 1=use fifo */ unsigned int ao_readback[2]; + unsigned int divisor1; + unsigned int divisor2; + unsigned int usefifo:1; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */ - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff -}; - -/* -============================================================================== -*/ -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen); -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); - -static int pcl818_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); - -/* -============================================================================== - ANALOG INPUT MODE0, 818 cards, slow version -*/ -static int pcl818_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; + struct pcl818_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL818_CONTROL); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); - /* select channel */ - outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX); + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + } +} - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE); +static void pcl818_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int flags; + unsigned int bytes; - for (n = 0; n < insn->n; n++) { + disable_dma(devpriv->dma); /* disable dma */ + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + bytes = cmd->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); + + pcl818_ai_set_chan_scan(dev, first_chan, last_chan); } -/* -============================================================================== - DIGITAL INPUT MODE0, 818 cards +static void pcl818_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL818_STATUS_REG); +} - only one sample per call is supported -*/ -static int pcl818_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_soft_trig(struct comedi_device *dev) { - data[1] = inb(dev->iobase + PCL818_DI_LO) | - (inb(dev->iobase + PCL818_DI_HI) << 8); + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL818_AI_LSB_REG); +} - return insn->n; +static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) +{ + unsigned int val; + + val = inb(dev->iobase + PCL818_FI_DATALO); + val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8); + + if (chan) + *chan = val & 0xf; + + return (val >> 4) & s->maxdata; } -static int pcl818_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static unsigned int pcl818_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) { - if (comedi_dio_update_state(s, data)) { - outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); - outb((s->state >> 8), dev->iobase + PCL818_DO_HI); - } + unsigned int val; - data[1] = s->state; + val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL818_AI_LSB_REG); - return insn->n; + if (chan) + *chan = val & 0xf; + + return (val >> 4) & s->maxdata; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) +static int pcl818_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned char low; - int timeout = 50; /* wait max 50us */ + unsigned int status; - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + status = inb(dev->iobase + PCL818_STATUS_REG); + if (status & PCL818_STATUS_INT) + return 0; + return -EBUSY; +} -conv_finish: - low = inb(dev->iobase + PCL818_AD_LO); - comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */ - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ +static bool pcl818_ai_dropout(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int expected_chan; - if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ + expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos]; + if (chan != expected_chan) { dev_dbg(dev->class_dev, - "A/D mode1/3 IRQ - channel dropout %x!=%x !\n", - (low & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); + "A/D mode1/3 %s - channel dropout %d!=%d !\n", + (devpriv->dma) ? "DMA" : + (devpriv->usefifo) ? "FIFO" : "IRQ", + chan, expected_chan); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return true; } + return false; +} + +static bool pcl818_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; + devpriv->act_chanlist_pos++; if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) devpriv->act_chanlist_pos = 0; s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { + if (s->async->cur_chan >= cmd->chanlist_len) { s->async->cur_chan = 0; devpriv->ai_act_scan--; + s->async->events |= COMEDI_CB_EOS; } - if (!devpriv->neverending_ai) { - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - comedi_event(dev, s); - return IRQ_HANDLED; + + return true; } -/* -============================================================================== - analog input dma mode 1 & 3, 818 cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) +static void pcl818_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int chan; + unsigned int val; + + if (pcl818_ai_eoc(dev, s, NULL, 0)) { + comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; + } + + val = pcl818_ai_get_sample(dev, s, &chan); + + if (pcl818_ai_dropout(dev, s, chan)) + return; + + comedi_buf_put(s, val); + + pcl818_ai_next_chan(dev, s); +} + +static void pcl818_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - int i, len, bufptr; - unsigned long flags; unsigned short *ptr; + unsigned int chan; + unsigned int val; + int i, len, bufptr; - disable_dma(devpriv->dma); - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */ - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end || devpriv->neverending_ai) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(flags); - enable_dma(devpriv->dma); - } + pcl818_ai_setup_next_dma(dev, s); - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; - len = devpriv->hwdmasize[0] >> 1; + len = devpriv->hwdmasize >> 1; bufptr = 0; for (i = 0; i < len; i++) { - if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - dev_dbg(dev->class_dev, - "A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n", - (ptr[bufptr] & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos], - devpriv->act_chanlist_pos); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } + val = ptr[bufptr++]; + chan = val & 0xf; + val = (val >> 4) & s->maxdata; - comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ + if (pcl818_ai_dropout(dev, s, chan)) + break; - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; + comedi_buf_put(s, val); - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } - - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } + if (!pcl818_ai_next_chan(dev, s)) + break; } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818HD/HG cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) +static void pcl818_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; + unsigned int status; + unsigned int chan; + unsigned int val; int i, len; - unsigned char lo; - outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ + status = inb(dev->iobase + PCL818_FI_STATUS); - lo = inb(dev->iobase + PCL818_FI_STATUS); - - if (lo & 4) { + if (status & 4) { comedi_error(dev, "A/D mode1/3 FIFO overflow!"); - pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - if (lo & 1) { + if (status & 1) { comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); - pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - if (lo & 2) + if (status & 2) len = 512; else len = 0; for (i = 0; i < len; i++) { - lo = inb(dev->iobase + PCL818_FI_DATALO); - if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - dev_dbg(dev->class_dev, - "A/D mode1/3 FIFO - channel dropout %d!=%d !\n", - (lo & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } + val = pcl818_ai_get_fifo_sample(dev, s, &chan); - comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ - - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; + if (pcl818_ai_dropout(dev, s, chan)) + break; - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } + comedi_buf_put(s, val); - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } + if (!pcl818_ai_next_chan(dev, s)) + break; } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; } -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl818(int irq, void *d) +static irqreturn_t pcl818_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl818_ai_clear_eoc(dev); return IRQ_HANDLED; } - if (devpriv->irq_blocked && devpriv->irq_was_now_closed) { - if ((devpriv->neverending_ai || (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) && - (devpriv->ai_mode == INT_TYPE_AI1_DMA || - devpriv->ai_mode == INT_TYPE_AI3_DMA)) { - /* The cleanup from ai_cancel() has been delayed - until now because the card doesn't seem to like - being reprogrammed while a DMA transfer is in - progress. - */ - devpriv->ai_act_scan = 0; - devpriv->neverending_ai = 0; - pcl818_ai_cancel(dev, dev->read_subdev); - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - + if (devpriv->ai_cmd_canceled) { + /* + * The cleanup from ai_cancel() has been delayed + * until now because the card doesn't seem to like + * being reprogrammed while a DMA transfer is in + * progress. + */ + devpriv->ai_act_scan = 0; + s->cancel(dev, s); return IRQ_HANDLED; } - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl818_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl818_ai_mode13_int(irq, d); - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: - return interrupt_pcl818_ai_mode13_fifo(irq, d); -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: - return interrupt_pcl818_ao_mode13_int(irq, d); -#endif - default: - break; - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - if (!devpriv->irq_blocked || !devpriv->ai_mode) { - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; -} - -/* -============================================================================== - ANALOG INPUT MODE 1 or 3 DMA , 818 cards -*/ -static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl818_private *devpriv = dev->private; - unsigned int flags; - unsigned int bytes; - - disable_dma(devpriv->dma); /* disable dma */ - bytes = devpriv->hwdmasize[0]; - if (!devpriv->neverending_ai) { - bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */ - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(flags); - enable_dma(devpriv->dma); - - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_DMA; - outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */ - } else { - devpriv->ai_mode = INT_TYPE_AI3_DMA; - outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */ - } -} - -/* -============================================================================== - ANALOG INPUT MODE 1 or 3, 818 cards -*/ -static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl818_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - int divisor1 = 0, divisor2 = 0; - unsigned int seglen; - - if (devpriv->irq_blocked) - return -EBUSY; - - start_pacer(dev, -1, 0, 0); /* stop pacer */ - - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); - - udelay(1); - - devpriv->ai_act_scan = devpriv->ai_scans; - devpriv->ai_act_chan = 0; - devpriv->irq_blocked = 1; - devpriv->irq_was_now_closed = 0; - devpriv->neverending_ai = 0; - devpriv->act_chanlist_pos = 0; - devpriv->dma_runs_to_end = 0; - - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; /* well, user want neverending */ - - if (mode == 1) { - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, - TRIG_ROUND_NEAREST); - if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */ - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ - - switch (devpriv->dma) { - case 1: /* DMA */ - case 3: - pcl818_ai_mode13dma_int(mode, dev, s); - break; - case 0: - if (!devpriv->usefifo) { - /* IRQ */ - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_INT; - /* Pacer+IRQ */ - outb(0x83 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_INT; - /* Ext trig+IRQ */ - outb(0x82 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } - } else { - /* FIFO */ - /* enable FIFO */ - outb(1, dev->iobase + PCL818_FI_ENABLE); - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_FIFO; - /* Pacer */ - outb(0x03, dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_FIFO; - outb(0x02, dev->iobase + PCL818_CONTROL); - } - } - } - - start_pacer(dev, mode, divisor1, divisor2); - - return 0; -} + if (devpriv->dma) + pcl818_handle_dma(dev, s); + else if (devpriv->usefifo) + pcl818_handle_fifo(dev, s); + else + pcl818_handle_eoc(dev, s); -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - outb(0xb4, dev->iobase + PCL818_CTRCTL); - outb(0x74, dev->iobase + PCL818_CTRCTL); - udelay(1); + pcl818_ai_clear_eoc(dev); - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1); - } + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== - Check if channel list from user is builded correctly - If it's ok, then program scan/gain logic -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) @@ -941,52 +728,20 @@ static int check_channel_list(struct comedi_device *dev, return seglen; } -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) -{ - struct pcl818_private *devpriv = dev->private; - int i; - - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */ - outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */ - } - - udelay(1); - - /* select channel interval to scan */ - outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen - - 1] << 4), - dev->iobase + PCL818_MUX); -} - -/* -============================================================================== - Check if board is switched to SE (1) or DIFF(0) mode -*/ static int check_single_ended(unsigned int port) { - if (inb(port + PCL818_STATUS) & 0x20) + if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX) return 1; return 0; } -/* -============================================================================== -*/ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcl818_board *board = comedi_board(dev); struct pcl818_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -1033,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; + arg = cmd->convert_arg; i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, cmd->flags); - if (cmd->convert_arg < board->ns_min) - cmd->convert_arg = board->ns_min; - if (tmp != cmd->convert_arg) - err++; + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -1057,152 +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); - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; + devpriv->ai_act_scan = cmd->stop_arg; + devpriv->ai_act_chan = 0; + devpriv->ai_cmd_running = 1; + devpriv->ai_cmd_canceled = 0; + devpriv->act_chanlist_pos = 0; + devpriv->dma_runs_to_end = 0; - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans = cmd->stop_arg; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL818_CTRL_PACER_TRIG; else - devpriv->ai_scans = 0; + ctrl |= PCL818_CTRL_EXT_TRIG; - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ - devpriv->ai_timer1 = cmd->convert_arg; - retval = pcl818_ai_cmd_mode(1, dev, s); - return retval; - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pcl818_ai_cmd_mode(3, dev, s); - } + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + + if (devpriv->dma) { + pcl818_ai_setup_dma(dev, s); + + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) | + PCL818_CTRL_DMAE; + } else if (devpriv->usefifo) { + /* enable FIFO */ + outb(1, dev->iobase + PCL818_FI_ENABLE); + } else { + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq); } + outb(ctrl, dev->iobase + PCL818_CTRL_REG); + + if (cmd->convert_src == TRIG_TIMER) + pcl818_start_pacer(dev, true); - return -1; + return 0; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (devpriv->irq_blocked > 0) { - devpriv->irq_was_now_closed = 1; - - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - if (devpriv->neverending_ai || - (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) { - /* wait for running dma transfer to end, do cleanup in interrupt */ - goto end; - } - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: -#endif - outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - udelay(1); - start_pacer(dev, -1, 0, 0); - outb(0, dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_HI); - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - if (devpriv->usefifo) { /* FIFO shutdown */ - outb(0, dev->iobase + PCL818_FI_INTCLR); - outb(0, dev->iobase + PCL818_FI_FLUSH); - outb(0, dev->iobase + PCL818_FI_ENABLE); + if (!devpriv->ai_cmd_running) + return 0; + + if (devpriv->dma) { + if (cmd->stop_src == TRIG_NONE || + (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) { + if (!devpriv->ai_cmd_canceled) { + /* + * Wait for running dma transfer to end, + * do cleanup in interrupt. + */ + devpriv->ai_cmd_canceled = 1; + return 0; } - devpriv->irq_blocked = 0; - devpriv->last_int_sub = s; - devpriv->neverending_ai = 0; - devpriv->ai_mode = 0; - devpriv->irq_was_now_closed = 0; - break; } + disable_dma(devpriv->dma); + } + + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_start_pacer(dev, false); + pcl818_ai_clear_eoc(dev); + + if (devpriv->usefifo) { /* FIFO shutdown */ + outb(0, dev->iobase + PCL818_FI_INTCLR); + outb(0, dev->iobase + PCL818_FI_FLUSH); + outb(0, dev->iobase + PCL818_FI_ENABLE); } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 0; -end: return 0; } -/* -============================================================================== - chech for PCL818 -*/ -static int pcl818_check(unsigned long iobase) +static int pcl818_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - outb(0x00, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL818_MUX); - udelay(1); - outb(0x18, iobase + PCL818_CONTROL); - udelay(1); - if (inb(iobase + PCL818_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; + + outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG); + + pcl818_ai_set_chan_range(dev, chan, range); + pcl818_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl818_ai_clear_eoc(dev); + pcl818_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl818_ai_get_sample(dev, s, NULL); + } + pcl818_ai_clear_eoc(dev); + + return ret ? ret : insn->n; +} + +static int pcl818_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) { + devpriv->ao_readback[chan] = data[i]; + outb((data[i] & 0x000f) << 4, + dev->iobase + PCL818_AO_LSB_REG(chan)); + outb((data[i] & 0x0ff0) >> 4, + dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + return insn->n; +} + +static int pcl818_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int pcl818_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl818_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG); + } + + data[1] = s->state; + + return insn->n; } -/* -============================================================================== - reset whole PCL-818 cards -*/ static void pcl818_reset(struct comedi_device *dev) { const struct pcl818_board *board = comedi_board(dev); - struct pcl818_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; + unsigned int chan; - if (devpriv->usefifo) { /* FIFO shutdown */ + /* flush and disable the FIFO */ + if (board->has_fifo) { outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); } - outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */ - outb(0, dev->iobase + PCL818_DA_HI); - udelay(1); - outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */ - outb(0, dev->iobase + PCL818_DO_LO); - udelay(1); - outb(0, dev->iobase + PCL818_CONTROL); - outb(0, dev->iobase + PCL818_CNTENABLE); - outb(0, dev->iobase + PCL818_MUX); - outb(0, dev->iobase + PCL818_CLRINT); - outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL818_CTRCTL); - outb(0x30, dev->iobase + PCL818_CTRCTL); + + /* disable analog input trigger */ + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_ai_clear_eoc(dev); + + pcl818_ai_set_chan_range(dev, 0, 0); + + /* stop pacer */ + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL818_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL818_DO_DI_MSB_REG); + outb(0, dev->iobase + PCL818_DO_DI_LSB_REG); +} + +static void pcl818_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl818_board *board = comedi_board(dev); + + /* default to the range table from the boardinfo */ + s->range_table = board->ai_range_type; + + /* now check the user config option based on the boardtype */ if (board->is_818) { - outb(0, dev->iobase + PCL818_RANGE); + if (it->options[4] == 1 || it->options[4] == 10) { + /* secondary range list jumper selectable */ + s->range_table = &range_pcl818l_h_ai; + } } else { - outb(0, dev->iobase + PCL718_DA2_LO); - outb(0, dev->iobase + PCL718_DA2_HI); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range718_bipolar1; + break; + case 4: + s->range_table = &range718_bipolar0_5; + break; + case 6: + s->range_table = &range_unipolar10; + break; + case 7: + s->range_table = &range_unipolar5; + break; + case 8: + s->range_table = &range718_unipolar2; + break; + case 9: + s->range_table = &range718_unipolar1; + break; + default: + s->range_table = &range_unknown; + break; + } } } @@ -1210,154 +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; - int dma; - unsigned long pages; struct comedi_subdevice *s; + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - devpriv->io_range = board->io_range; - if ((board->fifo) && (it->options[2] == -1)) { - /* we've board with FIFO and we want to use FIFO */ - devpriv->io_range = PCLx1xFIFO_RANGE; - devpriv->usefifo = 1; - } - ret = comedi_request_region(dev, it->options[0], devpriv->io_range); + ret = comedi_request_region(dev, it->options[0], + board->has_fifo ? 0x20 : 0x10); if (ret) return ret; - if (pcl818_check(dev->iobase)) { - comedi_error(dev, "I can't detect board. FAIL!\n"); - return -EIO; - } - - if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl818, 0, + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl818_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->ai_mode = 0; /* mode of irq */ - - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - if (((1 << dma) & board->DMAbits) == 0) { + /* should we use the FIFO? */ + if (dev->irq && board->has_fifo && it->options[2] == -1) + devpriv->usefifo = 1; + + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); + if (ret) { dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); - if (ret) - return -EBUSY; /* DMA isn't free */ - devpriv->dma = dma; - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) - /* maybe experiment with try_to_free_pages() will help .... */ - return -EBUSY; /* no buffer :-( */ - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; - } + } + devpriv->dma = it->options[2]; + + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; -no_dma: + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } + } ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (!board->n_aichan_se) { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (check_single_ended(dev->iobase)) { + s->n_chan = 16; + s->subdev_flags |= SDF_COMMON | SDF_GROUND; } else { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - if (check_single_ended(dev->iobase)) { - s->n_chan = board->n_aichan_se; - s->subdev_flags |= SDF_COMMON | SDF_GROUND; - } else { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - } - s->maxdata = board->ai_maxdata; - s->range_table = board->ai_range_type; - s->insn_read = pcl818_ai_insn_read; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = s->n_chan; - s->do_cmdtest = ai_cmdtest; - s->do_cmd = ai_cmd; - s->cancel = pcl818_ai_cancel; - } - if (board->is_818) { - if ((it->options[4] == 1) || (it->options[4] == 10)) - s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */ - } else { - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range718_bipolar1; - break; - case 4: - s->range_table = &range718_bipolar0_5; - break; - case 6: - s->range_table = &range_unipolar10; - break; - case 7: - s->range_table = &range_unipolar5; - break; - case 8: - s->range_table = &range718_unipolar2; - break; - case 9: - s->range_table = &range718_unipolar1; - break; - default: - s->range_table = &range_unknown; - break; - } - } + s->n_chan = 8; + s->subdev_flags |= SDF_DIFF; + } + s->maxdata = 0x0fff; + + pcl818_set_ai_range_table(dev, s, it); + + s->insn_read = pcl818_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = ai_cmdtest; + s->do_cmd = pcl818_ai_cmd; + s->cancel = pcl818_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (!board->n_aochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = board->ao_maxdata; - s->range_table = board->ao_range_type; - s->insn_read = pcl818_ao_insn_read; - s->insn_write = pcl818_ao_insn_write; + if (board->n_aochan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0x0fff; + s->range_table = &range_unipolar5; + s->insn_read = pcl818_ao_insn_read; + s->insn_write = pcl818_ao_insn_write; if (board->is_818) { if ((it->options[4] == 1) || (it->options[4] == 10)) s->range_table = &range_unipolar10; @@ -1369,31 +1184,27 @@ no_dma: if (it->options[5] == 2) s->range_table = &range_unknown; } - } - - s = &dev->subdevices[2]; - if (!board->n_dichan) { - s->type = COMEDI_SUBD_UNUSED; } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl818_di_insn_bits; + s->type = COMEDI_SUBD_UNUSED; } + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - if (!board->n_dochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl818_do_insn_bits; - } + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_do_insn_bits; /* select 1/10MHz oscilator */ if ((it->options[3] == 0) || (it->options[3] == 10)) @@ -1424,38 +1235,13 @@ static void pcl818_detach(struct comedi_device *dev) if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl818_board boardtypes[] = { - {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 0}, - /* pcm3718 */ - {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, -}; - static struct comedi_driver pcl818_driver = { .driver_name = "pcl818", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index f4a49bd649f..53e73737a90 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -225,8 +225,10 @@ static int pcm3724_attach(struct comedi_device *dev, for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; - subdev_8255_init(dev, s, subdev_8255_cb, - (unsigned long)(dev->iobase + SIZE_8255 * i)); + ret = subdev_8255_init(dev, s, subdev_8255_cb, + dev->iobase + SIZE_8255 * i); + if (ret) + return ret; s->insn_config = subdev_3724_insn_config; } return 0; diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index fe482fdd512..87c61d9b11d 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -61,18 +61,17 @@ static const struct pcmad_board_struct pcmad_boards[] = { }, }; -#define TIMEOUT 100 - -static int pcmad_ai_wait_for_eoc(struct comedi_device *dev, - int timeout) +static int pcmad_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < timeout; i++) { - if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMAD_STATUS); + if ((status & 0x3) == 0x3) + return 0; + return -EBUSY; } static int pcmad_ai_insn_read(struct comedi_device *dev, @@ -89,7 +88,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + PCMAD_CONVERT); - ret = pcmad_ai_wait_for_eoc(dev, TIMEOUT); + ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index c388f7f3222..fed7e77e030 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -192,7 +192,6 @@ struct pcmmio_private { unsigned int enabled_mask; unsigned int stop_count; unsigned int active:1; - unsigned int continuous:1; unsigned int ao_readback[8]; }; @@ -339,8 +338,8 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev, unsigned int triggered) { struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int oldevents = s->async->events; - unsigned int len = s->async->cmd.chanlist_len; unsigned int val = 0; unsigned long flags; int i; @@ -353,16 +352,16 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev, if (!(triggered & devpriv->enabled_mask)) goto done; - for (i = 0; i < len; i++) { - unsigned int chan = CR_CHAN(s->async->cmd.chanlist[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, val) && - comedi_buf_put(s->async, val >> 16)) { + 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!! */ @@ -371,15 +370,12 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev, } /* Check for end of acquisition. */ - if (!devpriv->continuous) { - /* stop_src == TRIG_COUNT */ - if (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); - } + 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); } } @@ -421,7 +417,7 @@ static int pcmmio_start_intr(struct comedi_device *dev, unsigned int pol_bits = 0; int i; - if (!devpriv->continuous && devpriv->stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; devpriv->active = 0; @@ -464,18 +460,16 @@ static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 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(&devpriv->spinlock, flags); @@ -504,28 +498,17 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->active = 1; /* Set up end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - devpriv->continuous = 0; + if (cmd->stop_src == TRIG_COUNT) devpriv->stop_count = cmd->stop_arg; - break; - default: - /* TRIG_NONE */ - devpriv->continuous = 1; + else /* TRIG_NONE */ devpriv->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 = pcmmio_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = pcmmio_start_intr(dev, s); - break; - } + spin_unlock_irqrestore(&devpriv->spinlock, flags); if (event) @@ -589,16 +572,17 @@ static int pcmmio_cmdtest(struct comedi_device *dev, return 0; } -static int pcmmio_ai_wait_for_eoc(unsigned long iobase, unsigned int timeout) +static int pcmmio_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - while (timeout--) { - status = inb(iobase + PCMMIO_AI_STATUS_REG); - if (status & PCMMIO_AI_STATUS_DATA_READY) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMMIO_AI_STATUS_REG); + if (status & PCMMIO_AI_STATUS_DATA_READY) + return 0; + return -EBUSY; } static int pcmmio_ai_insn_read(struct comedi_device *dev, @@ -643,7 +627,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev, cmd |= PCMMIO_AI_CMD_RANGE(range); outb(cmd, iobase + PCMMIO_AI_CMD_REG); - ret = pcmmio_ai_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); if (ret) return ret; @@ -652,7 +637,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(cmd, iobase + PCMMIO_AI_CMD_REG); - ret = pcmmio_ai_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); if (ret) return ret; @@ -684,16 +670,17 @@ static int pcmmio_ao_insn_read(struct comedi_device *dev, return insn->n; } -static int pcmmio_ao_wait_for_eoc(unsigned long iobase, unsigned int timeout) +static int pcmmio_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - while (timeout--) { - status = inb(iobase + PCMMIO_AO_STATUS_REG); - if (status & PCMMIO_AO_STATUS_DATA_READY) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMMIO_AO_STATUS_REG); + if (status & PCMMIO_AO_STATUS_DATA_READY) + return 0; + return -EBUSY; } static int pcmmio_ao_insn_write(struct comedi_device *dev, @@ -726,7 +713,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG); outb(0, iobase + PCMMIO_AO_MSB_REG); outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG); - ret = pcmmio_ao_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); if (ret) return ret; @@ -738,7 +726,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG); outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE, iobase + PCMMIO_AO_CMD_REG); - ret = pcmmio_ao_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index a8f390f7a87..62914bb342d 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -317,7 +317,7 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, struct pcmuio_private *devpriv = dev->private; int asic = pcmuio_subdevice_to_asic(s); struct pcmuio_asic *chip = &devpriv->asics[asic]; - unsigned int len = s->async->cmd.chanlist_len; + struct comedi_cmd *cmd = &s->async->cmd; unsigned oldevents = s->async->events; unsigned int val = 0; unsigned long flags; @@ -331,15 +331,15 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, if (!(triggered & chip->enabled_mask)) goto done; - for (i = 0; i < len; i++) { - unsigned int chan = CR_CHAN(s->async->cmd.chanlist[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, val) && - comedi_buf_put(s->async, val >> 16)) { + 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!! */ @@ -460,20 +460,18 @@ static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 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_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(&chip->spinlock, flags); @@ -518,15 +516,11 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* 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(&chip->spinlock, flags); if (event) diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 55e3c2e2bc5..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; }; /********************************************************************** diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c deleted file mode 100644 index 2ae4ee15704..00000000000 --- a/drivers/staging/comedi/drivers/poc.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - comedi/drivers/poc.c - Mini-drivers for POC (Piece of Crap) boards - Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: poc -Description: Generic driver for very simple devices -Author: ds -Devices: [Keithley Metrabyte] DAC-02 (dac02) -Updated: Sat, 16 Mar 2002 17:34:48 -0800 -Status: unknown - -This driver is indended to support very simple ISA-based devices, -including: - dac02 - Keithley DAC-02 analog output board - -Configuration options: - [0] - I/O port base -*/ - -#include <linux/module.h> -#include "../comedidev.h" - -struct boarddef_struct { - const char *name; - unsigned int iosize; - int (*setup) (struct comedi_device *); - int type; - int n_chan; - int n_bits; - int (*winsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - const struct comedi_lrange *range; -}; - -struct poc_private { - unsigned int ao_readback[32]; -}; - -static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int chan; - - chan = CR_CHAN(insn->chanspec); - data[0] = devpriv->ao_readback[chan]; - - return 1; -} - -/* DAC-02 registers */ -#define DAC02_LSB(a) (2 * a) -#define DAC02_MSB(a) (2 * a + 1) - -static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int temp; - int chan; - int output; - - chan = CR_CHAN(insn->chanspec); - devpriv->ao_readback[chan] = data[0]; - output = data[0]; -#ifdef wrong - /* convert to complementary binary if range is bipolar */ - if ((CR_RANGE(insn->chanspec) & 0x2) == 0) - output = ~output; -#endif - temp = (output << 4) & 0xf0; - outb(temp, dev->iobase + DAC02_LSB(chan)); - temp = (output >> 4) & 0xff; - outb(temp, dev->iobase + DAC02_MSB(chan)); - - return 1; -} - -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct boarddef_struct *board = comedi_board(dev); - struct poc_private *devpriv; - struct comedi_subdevice *s; - int ret; - - ret = comedi_request_region(dev, it->options[0], board->iosize); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - /* analog output subdevice */ - s = &dev->subdevices[0]; - s->type = board->type; - s->n_chan = board->n_chan; - s->maxdata = (1 << board->n_bits) - 1; - s->range_table = board->range; - s->insn_write = board->winsn; - s->insn_read = board->rinsn; - s->insn_bits = board->insnbits; - if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) - s->subdev_flags = SDF_WRITABLE; - - return 0; -} - -static const struct boarddef_struct boards[] = { - { - .name = "dac02", - .iosize = 8, - /* .setup = dac02_setup, */ - .type = COMEDI_SUBD_AO, - .n_chan = 2, - .n_bits = 12, - .winsn = dac02_ao_winsn, - .rinsn = readback_insn, - .range = &range_unknown, - }, -}; - -static struct comedi_driver poc_driver = { - .driver_name = "poc", - .module = THIS_MODULE, - .attach = poc_attach, - .detach = comedi_legacy_detach, - .board_name = &boards[0].name, - .num_names = ARRAY_SIZE(boards), - .offset = sizeof(boards[0]), -}; -module_comedi_driver(poc_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 96a46954b3c..b3bbec0a0d2 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -214,7 +214,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) s->async->events |= COMEDI_CB_EOA | COMEDI_CB_OVERFLOW; dev_warn(dev->class_dev, "data lost\n"); - daqp_ai_cancel(dev, s); break; } @@ -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) diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 0f026afde9b..d55c5893203 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -237,20 +237,6 @@ /* The board support a channel list up to the FIFO length (1K or 8K) */ #define RTD_MAX_CHANLIST 128 /* max channel list that we allow */ -/* tuning for ai/ao instruction done polling */ -#ifdef FAST_SPIN -#define WAIT_QUIETLY /* as nothing, spin on done bit */ -#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */ -#define RTD_DAC_TIMEOUT 66000 -#define RTD_DMA_TIMEOUT 33000 /* 1 msec */ -#else -/* by delaying, power and electrical noise are reduced somewhat */ -#define WAIT_QUIETLY udelay(1) -#define RTD_ADC_TIMEOUT 2000 /* in usec */ -#define RTD_DAC_TIMEOUT 2000 /* in usec */ -#define RTD_DMA_TIMEOUT 1000 /* in usec */ -#endif - /*====================================================================== Board specific stuff ======================================================================*/ @@ -562,21 +548,27 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) return fifo_size; } -/* - "instructions" read/write data in "one-shot" or "software-triggered" - mode (simplest case). - This doesn't use interrupts. +static int rtd_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & FS_ADC_NOT_EMPTY) + return 0; + return -EBUSY; +} - Note, we don't do any settling delays. Use a instruction list to - select, delay, then read. - */ static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct rtd_private *devpriv = dev->private; - int n, ii; - int stat; + int ret; + int n; /* clear any old fifo data */ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); @@ -593,14 +585,9 @@ static int rtd_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ writew(0, devpriv->las0 + LAS0_ADC); - for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) { - stat = readl(devpriv->las0 + LAS0_ADC); - if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */ - break; - WAIT_QUIETLY; - } - if (ii >= RTD_ADC_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0); + if (ret) + return ret; /* read data */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); @@ -642,7 +629,7 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, d = comedi_offset_munge(s, d); d &= s->maxdata; - if (!comedi_buf_put(s->async, d)) + if (!comedi_buf_put(s, d)) return -1; if (devpriv->ai_count > 0) /* < 0, means read forever */ @@ -671,7 +658,7 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) d = comedi_offset_munge(s, d); d &= s->maxdata; - if (!comedi_buf_put(s->async, d)) + if (!comedi_buf_put(s, d)) return -1; if (devpriv->ai_count > 0) /* < 0, means read forever */ @@ -792,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 */ @@ -891,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 { @@ -904,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); } } @@ -1116,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) @@ -1127,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 + @@ -1136,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 */ @@ -1157,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 */ @@ -1382,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; } diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index e1f3671ac05..bd447b2add7 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -83,8 +83,6 @@ #define RTI800_IOSIZE 0x10 -#define RTI800_AI_TIMEOUT 100 - static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, { BIP_RANGE(10), @@ -145,23 +143,21 @@ struct rti800_private { unsigned char muxgain_bits; }; -static int rti800_ai_wait_for_conversion(struct comedi_device *dev, - int timeout) +static int rti800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - int i; - for (i = 0; i < timeout; i++) { - status = inb(dev->iobase + RTI800_CSR); - if (status & RTI800_CSR_OVERRUN) { - outb(0, dev->iobase + RTI800_CLRFLAGS); - return -EIO; - } - if (status & RTI800_CSR_DONE) - return 0; - udelay(1); + status = inb(dev->iobase + RTI800_CSR); + if (status & RTI800_CSR_OVERRUN) { + outb(0, dev->iobase + RTI800_CLRFLAGS); + return -EOVERFLOW; } - return -ETIME; + if (status & RTI800_CSR_DONE) + return 0; + return -EBUSY; } static int rti800_ai_insn_read(struct comedi_device *dev, @@ -198,7 +194,8 @@ static int rti800_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(0, dev->iobase + RTI800_CONVERT); - ret = rti800_ai_wait_for_conversion(dev, RTI800_AI_TIMEOUT); + + ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index a3fa2a4baef..605a31d702e 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -1,45 +1,44 @@ /* - comedi/drivers/rti802.c - Hardware driver for Analog Devices RTI-802 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * rti802.c + * Comedi driver for Analog Devices RTI-802 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: rti802 -Description: Analog Devices RTI-802 -Author: Anders Blomdell <anders.blomdell@control.lth.se> -Devices: [Analog Devices] RTI-802 (rti802) -Status: works - -Configuration Options: - [0] - i/o base - [1] - unused - [2] - dac#0 0=two's comp, 1=straight - [3] - dac#0 0=bipolar, 1=unipolar - [4] - dac#1 ... - ... - [17] - dac#7 ... -*/ + * Driver: rti802 + * Description: Analog Devices RTI-802 + * Author: Anders Blomdell <anders.blomdell@control.lth.se> + * Devices: (Analog Devices) RTI-802 [rti802] + * Status: works + * + * Configuration Options: + * [0] - i/o base + * [1] - unused + * [2,4,6,8,10,12,14,16] - dac#[0-7] 0=two's comp, 1=straight + * [3,5,7,9,11,13,15,17] - dac#[0-7] 0=bipolar, 1=unipolar + */ #include <linux/module.h> #include "../comedidev.h" -#define RTI802_SIZE 4 - -#define RTI802_SELECT 0 -#define RTI802_DATALOW 1 -#define RTI802_DATAHIGH 2 +/* + * Register I/O map + */ +#define RTI802_SELECT 0x00 +#define RTI802_DATALOW 0x01 +#define RTI802_DATAHIGH 0x02 struct rti802_private { enum { @@ -51,34 +50,45 @@ struct rti802_private { static int rti802_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; + data[i] = devpriv->ao_readback[chan]; - return i; + return insn->n; } static int rti802_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; - int i, d; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + RTI802_SELECT); for (i = 0; i < insn->n; i++) { - d = devpriv->ao_readback[chan] = data[i]; + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* munge offset binary to two's complement if needed */ if (devpriv->dac_coding[chan] == dac_2comp) - d ^= 0x800; - outb(chan, dev->iobase + RTI802_SELECT); - outb(d & 0xff, dev->iobase + RTI802_DATALOW); - outb(d >> 8, dev->iobase + RTI802_DATAHIGH); + val = comedi_offset_munge(s, val); + + outb(val & 0xff, dev->iobase + RTI802_DATALOW); + outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH); } - return i; + + return insn->n; } static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -88,7 +98,7 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) int i; int ret; - ret = comedi_request_region(dev, it->options[0], RTI802_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x04); if (ret) return ret; @@ -100,22 +110,21 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; + /* Analog Output subdevice */ s = &dev->subdevices[0]; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 0xfff; - s->n_chan = 8; - s->insn_read = rti802_ao_insn_read; - s->insn_write = rti802_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->maxdata = 0xfff; + s->n_chan = 8; + s->insn_read = rti802_ao_insn_read; + s->insn_write = rti802_ao_insn_write; s->range_table_list = devpriv->range_type_list; for (i = 0; i < 8; i++) { devpriv->dac_coding[i] = (it->options[3 + 2 * i]) - ? (dac_straight) - : (dac_2comp); + ? (dac_straight) : (dac_2comp); devpriv->range_type_list[i] = (it->options[2 + 2 * i]) - ? &range_unipolar10 : &range_bipolar10; + ? &range_unipolar10 : &range_bipolar10; } return 0; @@ -130,5 +139,5 @@ static struct comedi_driver rti802_driver = { module_comedi_driver(rti802_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 9950f59b119..85d2b7a3c12 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -420,15 +420,28 @@ static int s526_ai_insn_config(struct comedi_device *dev, return result; } +static int s526_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + REG_ISR); + if (status & ISR_ADC_DONE) + return 0; + return -EBUSY; +} + static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct s526_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - int n, i; + int n; unsigned short value; unsigned int d; - unsigned int status; + int ret; /* Set configured delay, enable channel for this channel only, * select "ADC read" channel, set "ADC start" bit. */ @@ -440,17 +453,12 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outw(value, dev->iobase + REG_ADC); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + REG_ISR); - if (status & ISR_ADC_DONE) { - outw(ISR_ADC_DONE, dev->iobase + REG_ISR); - break; - } - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0); + if (ret) + return ret; + + outw(ISR_ADC_DONE, dev->iobase + REG_ISR); /* read data */ d = inw(dev->iobase + REG_ADD); @@ -604,7 +612,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = s526_dio_insn_bits; s->insn_config = s526_dio_insn_config; - return 1; + return 0; } static struct comedi_driver s526_driver = { diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 19da1dbea49..0838f8aa695 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -106,16 +106,16 @@ struct s626_private { struct s626_enc_info { /* Pointers to functions that differ for A and B counters: */ /* Return clock enable. */ - uint16_t(*get_enable)(struct comedi_device *dev, + uint16_t (*get_enable)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return interrupt source. */ - uint16_t(*get_int_src)(struct comedi_device *dev, + uint16_t (*get_int_src)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return preload trigger source. */ - uint16_t(*get_load_trig)(struct comedi_device *dev, + uint16_t (*get_load_trig)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return standardized operating mode. */ - uint16_t(*get_mode)(struct comedi_device *dev, + uint16_t (*get_mode)(struct comedi_device *dev, const struct s626_enc_info *k); /* Generate soft index strobe. */ void (*pulse_index)(struct comedi_device *dev, @@ -209,6 +209,8 @@ static const struct comedi_lrange s626_range_table = { static void s626_debi_transfer(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; + static const int timeout = 10000; + int i; /* Initiate upload of shadow RAM to DEBI control register */ s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2); @@ -217,12 +219,23 @@ static void s626_debi_transfer(struct comedi_device *dev) * Wait for completion of upload from shadow RAM to * DEBI control register. */ - while (!s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) - ; + for (i = 0; i < timeout; i++) { + if (s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, + "Timeout while uploading to DEBI control register."); /* Wait until DEBI transfer is done */ - while (readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S) - ; + for (i = 0; i < timeout; i++) { + if (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, "DEBI transfer timeout."); } /* @@ -282,10 +295,24 @@ static void s626_debi_replace(struct comedi_device *dev, unsigned int addr, /* ************** EEPROM ACCESS FUNCTIONS ************** */ -static uint32_t s626_i2c_handshake(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 + S626_P_I2CCTRL); @@ -295,8 +322,9 @@ static uint32_t s626_i2c_handshake(struct comedi_device *dev, uint32_t val) * wait for upload confirmation. */ s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); - while (!s626_mc_test(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 { @@ -351,14 +379,57 @@ static const uint8_t s626_trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 }; +enum { + s626_send_dac_wait_not_mc1_a2out, + s626_send_dac_wait_ssr_af2_out, + s626_send_dac_wait_fb_buffer2_msb_00, + s626_send_dac_wait_fb_buffer2_msb_ff +}; + +static int s626_send_dac_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; + + switch (context) { + case s626_send_dac_wait_not_mc1_a2out: + status = readl(devpriv->mmio + S626_P_MC1); + if (!(status & S626_MC1_A2OUT)) + return 0; + break; + case s626_send_dac_wait_ssr_af2_out: + status = readl(devpriv->mmio + S626_P_SSR); + if (status & S626_SSR_AF2_OUT) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_00: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (!(status & 0xff000000)) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_ff: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (status & 0xff000000) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Private helper function: Transmit serial data to DAC via Audio * channel 2. Assumes: (1) TSL2 slot records initialized, and (2) * dacpol contains valid target image. */ -static void s626_send_dac(struct comedi_device *dev, uint32_t val) +static int s626_send_dac(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; + int ret; /* START THE SERIAL CLOCK RUNNING ------------- */ @@ -404,8 +475,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * Done by polling the DMAC enable flag; this flag is automatically * cleared when the transfer has finished. */ - while (readl(devpriv->mmio + S626_P_MC1) & S626_MC1_A2OUT) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_not_mc1_a2out); + if (ret) { + comedi_error(dev, "DMA transfer timeout."); + return ret; + } /* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */ @@ -425,8 +500,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * finished transferring the DAC's data DWORD from the output FIFO * to the output buffer register. */ - while (!(readl(devpriv->mmio + S626_P_SSR) & S626_SSR_AF2_OUT)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_ssr_af2_out); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 1 to execute."); + return ret; + } /* * Set up to trap execution at slot 0 when the TSL sequencer cycles @@ -466,8 +545,13 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * from 0xFF to 0x00, which slot 0 causes to happen by shifting * out/in on SD2 the 0x00 that is always referenced by slot 5. */ - while (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_00); + if (ret) { + comedi_error(dev, + "TSL timeout waiting for slot 0 to execute."); + return ret; + } } /* * Either (1) we were too late setting the slot 0 trap; the TSL @@ -486,14 +570,19 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * the next DAC write. This is detected when FB_BUFFER2 MSB changes * from 0x00 to 0xFF. */ - while (!(readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_ff); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 0 to execute."); + return ret; + } + return 0; } /* * Private helper function: Write setpoint to an application DAC channel. */ -static void s626_set_dac(struct comedi_device *dev, uint16_t chan, +static int s626_set_dac(struct comedi_device *dev, uint16_t chan, int16_t dacdata) { struct s626_private *devpriv = dev->private; @@ -556,10 +645,10 @@ static void s626_set_dac(struct comedi_device *dev, uint16_t chan, val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel * within the device. */ val |= (uint32_t)dacdata; /* Include DAC setpoint data. */ - s626_send_dac(dev, val); + return s626_send_dac(dev, val); } -static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, +static int s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, uint8_t dac_data) { struct s626_private *devpriv = dev->private; @@ -606,17 +695,22 @@ static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, * Address the DAC channel within the trimdac device. * Include DAC setpoint data. */ - s626_send_dac(dev, (chan << 8) | dac_data); + return s626_send_dac(dev, (chan << 8) | dac_data); } -static void s626_load_trim_dacs(struct comedi_device *dev) +static int s626_load_trim_dacs(struct comedi_device *dev) { uint8_t i; + int ret; /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ - for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) - s626_write_trim_dac(dev, i, + for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) { + ret = s626_write_trim_dac(dev, i, s626_i2c_read(dev, s626_trimadrs[i])); + if (ret) + return ret; + } + return 0; } /* ****** COUNTER FUNCTIONS ******* */ @@ -1534,7 +1628,6 @@ static bool s626_handle_eos_interrupt(struct comedi_device *dev) readaddr++; /* put data into read buffer */ - /* comedi_buf_put(async, tempdata); */ cfc_write_to_buffer(s, tempdata); } @@ -1846,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) @@ -1856,6 +1963,7 @@ static int s626_ai_insn_read(struct comedi_device *dev, uint16_t adc_spec = 0; uint32_t gpio_image; uint32_t tmp; + int ret; int n; /* @@ -1897,8 +2005,9 @@ static int s626_ai_insn_read(struct comedi_device *dev, */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2)) - ; + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; /* Fetch ADC data */ if (n != 0) { @@ -1934,8 +2043,9 @@ static int s626_ai_insn_read(struct comedi_device *dev, /* Wait for the data to arrive in FB BUFFER 1 register. */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2)) - ; + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; /* Fetch ADC data from audio interface's input shift register. */ @@ -1965,9 +2075,12 @@ static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd) } 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 */ @@ -1985,7 +2098,7 @@ static int s626_ai_inttrig(struct comedi_device *dev, * 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) +static int s626_ns_to_timer(unsigned int *nanosec, int round_mode) { int divider, base; @@ -2093,7 +2206,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * interval */ k = &s626_enc_chan_info[5]; - tick = s626_ns_to_timer((int *)&cmd->scan_begin_arg, + tick = s626_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ @@ -2116,7 +2229,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * interval */ k = &s626_enc_chan_info[4]; - tick = s626_ns_to_timer((int *)&cmd->convert_arg, + tick = s626_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ @@ -2175,7 +2288,7 @@ 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 */ @@ -2203,12 +2316,18 @@ 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) @@ -2252,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); } } @@ -2299,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; @@ -2307,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); - s626_set_dac(dev, chan, dacdata); + ret = s626_set_dac(dev, chan, dacdata); + if (ret) + return ret; } return i; @@ -2543,12 +2661,13 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev) return 0; } -static void s626_initialize(struct comedi_device *dev) +static int s626_initialize(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; dma_addr_t phys_buf; uint16_t chan; int i; + int ret; /* Enable DEBI and audio pins, enable I2C interface */ s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C, @@ -2582,8 +2701,9 @@ static void s626_initialize(struct comedi_device *dev) writel(S626_I2C_CLKSEL | S626_I2C_ABORT, devpriv->mmio + S626_P_I2CSTAT); s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); - while (!(readl(devpriv->mmio + S626_P_MC2) & S626_MC2_UPLD_IIC)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; /* * Per SAA7146 data sheet, write to STATUS @@ -2592,8 +2712,9 @@ static void s626_initialize(struct comedi_device *dev) for (i = 0; i < 2; i++) { writel(S626_I2C_CLKSEL, devpriv->mmio + S626_P_I2CSTAT); s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); - while (!s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; } /* @@ -2749,7 +2870,9 @@ static void s626_initialize(struct comedi_device *dev) * sometimes causes the first few TrimDAC writes to malfunction. */ s626_load_trim_dacs(dev); - s626_load_trim_dacs(dev); + ret = s626_load_trim_dacs(dev); + if (ret) + return ret; /* * Manually init all gate array hardware in case this is a soft @@ -2763,8 +2886,11 @@ static void s626_initialize(struct comedi_device *dev) * Init all DAC outputs to 0V and init all DAC setpoint and * polarity images. */ - for (chan = 0; chan < S626_DAC_CHANNELS; chan++) - s626_set_dac(dev, chan, 0); + for (chan = 0; chan < S626_DAC_CHANNELS; chan++) { + ret = s626_set_dac(dev, chan, 0); + if (ret) + return ret; + } /* Init counters */ s626_counters_init(dev); @@ -2780,6 +2906,8 @@ static void s626_initialize(struct comedi_device *dev) /* Initialize the digital I/O subsystem */ s626_dio_init(dev); + + return 0; } static int s626_auto_attach(struct comedi_device *dev, @@ -2900,9 +3028,9 @@ static int s626_auto_attach(struct comedi_device *dev, s->insn_read = s626_enc_insn_read; s->insn_write = s626_enc_insn_write; - s626_initialize(dev); - - dev_info(dev->class_dev, "%s attached\n", dev->board_name); + ret = s626_initialize(dev); + if (ret) + return ret; return 0; } diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index 77e2059ff62..3bfa221faf4 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -142,6 +142,29 @@ static int skel_ns_to_timer(unsigned int *ns, int round) } /* + * This function doesn't require a particular form, this is just + * what happens to be used in some of the drivers. The comedi_timeout() + * helper uses this callback to check for the end-of-conversion while + * waiting for up to 1 second. This function should return 0 when the + * conversion is finished and -EBUSY to keep waiting. Any other errno + * will terminate comedi_timeout() and return that errno to the caller. + * If the timeout occurs, comedi_timeout() will return -ETIMEDOUT. + */ +static int skel_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + /* status = inb(dev->iobase + SKEL_STATUS); */ + status = 1; + if (status) + return 0; + return -EBUSY; +} + +/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ @@ -149,9 +172,9 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct skel_board *thisboard = comedi_board(dev); - int n, i; + int n; unsigned int d; - unsigned int status; + int ret; /* a typical programming sequence */ @@ -165,18 +188,10 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ /* outw(0,dev->iobase + SKEL_CONVERT); */ -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = 1; - /* status = inb(dev->iobase + SKEL_STATUS); */ - if (status) - break; - } - if (i == TIMEOUT) { - dev_warn(dev->class_dev, "ai timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0); + if (ret) + return ret; /* read data */ /* d = inw(dev->iobase + SKEL_AI_DATA); */ @@ -205,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 */ @@ -271,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); } } @@ -456,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; } diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index df22a78d2b7..848c3080158 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -161,8 +161,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(PCMR, CSCIR); outb((inb(CSCDR) & 0xAA), CSCDR); - dev_info(dev->class_dev, "%s: attached\n", dev->board_name); - return 1; + return 0; } static void dnp_detach(struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 71db683098d..5f65e4213c6 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -202,14 +202,11 @@ struct usbdux_private { /* input buffer for single insn */ uint16_t *insn_buf; - uint8_t ao_chanlist[USBDUX_NUM_AO_CHAN]; unsigned int ao_readback[USBDUX_NUM_AO_CHAN]; unsigned int high_speed:1; unsigned int ai_cmd_running:1; - unsigned int ai_continous:1; unsigned int ao_cmd_running:1; - unsigned int ao_continous:1; unsigned int pwm_cmd_running:1; /* number of samples to acquire */ @@ -266,7 +263,8 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) struct comedi_device *dev = urb->context; struct comedi_subdevice *s = dev->read_subdev; struct usbdux_private *devpriv = dev->private; - int i, err, n; + struct comedi_cmd *cmd = &s->async->cmd; + int i, err; /* first we test if something unusual has just happened */ switch (urb->status) { @@ -349,7 +347,7 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) devpriv->ai_counter = devpriv->ai_timer; /* test, if we transmit only a fixed number of samples */ - if (!devpriv->ai_continous) { + if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ devpriv->ai_sample_count--; /* all samples received? */ @@ -363,9 +361,8 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) } } /* 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++) { - unsigned int range = CR_RANGE(s->async->cmd.chanlist[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 */ @@ -373,7 +370,7 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) val ^= ((s->maxdata + 1) >> 1); /* transfer data */ - err = comedi_buf_put(s->async, val); + err = comedi_buf_put(s, val); if (unlikely(err == 0)) { /* buffer overflow */ usbdux_ai_stop(dev, 0); @@ -414,8 +411,8 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) 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 len; int ret; int i; @@ -463,7 +460,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) devpriv->ao_counter = devpriv->ao_timer; /* handle non continous acquisition */ - if (!devpriv->ao_continous) { + if (cmd->stop_src == TRIG_COUNT) { /* fixed number of samples */ devpriv->ao_sample_count--; if (devpriv->ao_sample_count < 0) { @@ -478,13 +475,12 @@ static void usbduxsub_ao_isoc_irq(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 < s->async->cmd.chanlist_len; i++) { - unsigned int chan = devpriv->ao_chanlist[i]; + *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 | @@ -493,7 +489,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) /* pointer to the DA */ *datap++ = val & 0xff; *datap++ = (val >> 8) & 0xff; - *datap++ = chan; + *datap++ = chan << 6; devpriv->ao_readback[chan] = val; s->async->events |= COMEDI_CB_BLOCK; @@ -692,15 +688,16 @@ static int receive_dux_commands(struct comedi_device *dev, unsigned int command) static int usbdux_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbdux_private *devpriv = dev->private; - int ret = -EINVAL; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; - down(&devpriv->sem); + if (trig_num != cmd->start_arg) + return -EINVAL; - if (trignum != 0) - goto ai_trig_exit; + down(&devpriv->sem); if (!devpriv->ai_cmd_running) { devpriv->ai_cmd_running = 1; @@ -777,10 +774,8 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->stop_src == TRIG_COUNT) { /* data arrives as one packet */ devpriv->ai_sample_count = cmd->stop_arg; - devpriv->ai_continous = 0; } else { /* continous acquisition */ - devpriv->ai_continous = 1; devpriv->ai_sample_count = 0; } @@ -913,15 +908,16 @@ ao_write_exit: static int usbdux_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbdux_private *devpriv = dev->private; - int ret = -EINVAL; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; - down(&devpriv->sem); + if (trig_num != cmd->start_arg) + return -EINVAL; - if (trignum != 0) - goto ao_trig_exit; + down(&devpriv->sem); if (!devpriv->ao_cmd_running) { devpriv->ao_cmd_running = 1; @@ -1030,7 +1026,6 @@ 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; int ret = -EBUSY; - int i; down(&devpriv->sem); @@ -1040,12 +1035,6 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; - for (i = 0; i < cmd->chanlist_len; ++i) { - unsigned int chan = CR_CHAN(cmd->chanlist[i]); - - devpriv->ao_chanlist[i] = chan << 6; - } - /* we count in steps of 1ms (125us) */ /* 125us mode not used yet */ if (0) { /* (devpriv->high_speed) */ @@ -1077,10 +1066,8 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* data arrives as one packet */ devpriv->ao_sample_count = cmd->stop_arg; } - devpriv->ao_continous = 0; } else { /* continous acquisition */ - devpriv->ao_continous = 1; devpriv->ao_sample_count = 0; } diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 5f85c55c110..85f9dcf5940 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -154,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 */ @@ -239,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; @@ -285,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)) { @@ -372,7 +372,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT | TRIG_INT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + TRIG_FOLLOW | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -398,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; @@ -424,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: @@ -454,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); @@ -514,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; @@ -822,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 */ @@ -848,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); diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 88c60b6020c..ccc3ef7ba55 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -161,14 +161,11 @@ struct usbduxsigma_private { /* input buffer for single insn */ uint8_t *insn_buf; - uint8_t ao_chanlist[USBDUXSIGMA_NUM_AO_CHAN]; 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 */ @@ -223,6 +220,7 @@ 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; uint32_t val; int ret; @@ -301,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) { @@ -314,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 */ @@ -360,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; @@ -403,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) { @@ -417,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->ao_chanlist[i]; + *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 | @@ -596,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; } @@ -663,12 +658,13 @@ 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); @@ -738,7 +734,6 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, } s->async->inttrig = NULL; } else { /* TRIG_INT */ - /* wait for an internal signal and submit the urbs later */ s->async->inttrig = usbduxsigma_ai_inttrig; } @@ -856,12 +851,13 @@ 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); @@ -985,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; } @@ -1004,14 +998,11 @@ 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->ao_chanlist[i] = CR_CHAN(cmd->chanlist[i]); devpriv->ao_counter = devpriv->ao_timer; @@ -1027,7 +1018,6 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, } s->async->inttrig = NULL; } else { /* TRIG_INT */ - /* wait for an internal signal and submit the urbs later */ s->async->inttrig = usbduxsigma_ao_inttrig; } diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index 7dc5a18e69d..8777f958c04 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -41,7 +41,8 @@ struct comedi_device *comedi_open(const char *filename) 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; diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c index da6bc5855eb..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,11 +33,8 @@ 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_get_from_minor(i); diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index 46b3da68638..b6849545b81 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -143,28 +143,23 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int chanspec; int chan, range_len, i; - if (s->range_table || s->range_table_list) { - 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; - } + 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; } |
