diff options
Diffstat (limited to 'drivers/staging/comedi')
117 files changed, 4234 insertions, 10410 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 152f4c12ea43..a8201fe87512 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -384,6 +384,7 @@ config COMEDI_DT282X config COMEDI_DMM32AT tristate "Diamond Systems MM-32-AT PC/104 board support" + select COMEDI_8255 ---help--- Enable support for Diamond Systems MM-32-AT PC/104 boards @@ -564,11 +565,14 @@ config COMEDI_S526 endif # COMEDI_ISA_DRIVERS menuconfig COMEDI_PCI_DRIVERS - bool "Comedi PCI drivers" + tristate "Comedi PCI drivers" depends on PCI ---help--- Enable support for comedi PCI drivers. + To compile this support as a module, choose M here: the module will + be called comedi_pci. + if COMEDI_PCI_DRIVERS config COMEDI_8255_PCI @@ -595,14 +599,6 @@ config COMEDI_ADDI_WATCHDOG boards. This module will be automatically selected when needed. The module will be called addi_watchdog. -config COMEDI_ADDI_APCI_035 - tristate "ADDI-DATA APCI_035 support" - ---help--- - Enable support for ADDI-DATA APCI_035 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_035. - config COMEDI_ADDI_APCI_1032 tristate "ADDI-DATA APCI_1032 support" ---help--- @@ -939,11 +935,11 @@ config COMEDI_CB_PCIDDA called cb_pcidda. config COMEDI_CB_PCIMDAS - tristate "MeasurementComputing PCIM-DAS1602/16 support" + tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support" select COMEDI_8255 ---help--- Enable support for ComputerBoards/MeasurementComputing PCI Migration - series PCIM-DAS1602/16 + series PCIM-DAS1602/16 and PCIe-DAS1602/16. To compile this driver as a module, choose M here: the module will be called cb_pcimdas. @@ -1084,11 +1080,14 @@ config COMEDI_NI_TIOCMD endif # COMEDI_PCI_DRIVERS menuconfig COMEDI_PCMCIA_DRIVERS - bool "Comedi PCMCIA drivers" + tristate "Comedi PCMCIA drivers" depends on PCMCIA ---help--- Enable support for comedi PCMCIA drivers. + To compile this support as a module, choose M here: the module will + be called comedi_pcmcia. + if COMEDI_PCMCIA_DRIVERS config COMEDI_CB_DAS16_CS @@ -1160,11 +1159,14 @@ config COMEDI_QUATECH_DAQP_CS endif # COMEDI_PCMCIA_DRIVERS menuconfig COMEDI_USB_DRIVERS - bool "Comedi USB drivers" + tristate "Comedi USB drivers" depends on USB ---help--- Enable support for comedi USB drivers. + To compile this support as a module, choose M here: the module will + be called comedi_usb. + if COMEDI_USB_DRIVERS config COMEDI_DT9812 diff --git a/drivers/staging/comedi/Makefile b/drivers/staging/comedi/Makefile index fae2d9090006..7f9dfb3923ab 100644 --- a/drivers/staging/comedi/Makefile +++ b/drivers/staging/comedi/Makefile @@ -2,12 +2,13 @@ ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG comedi-y := comedi_fops.o range.o drivers.o \ comedi_buf.o -comedi-$(CONFIG_COMEDI_PCI_DRIVERS) += comedi_pci.o -comedi-$(CONFIG_COMEDI_PCMCIA_DRIVERS) += comedi_pcmcia.o -comedi-$(CONFIG_COMEDI_USB_DRIVERS) += comedi_usb.o comedi-$(CONFIG_PROC_FS) += proc.o comedi-$(CONFIG_COMPAT) += comedi_compat32.o +obj-$(CONFIG_COMEDI_PCI_DRIVERS) += comedi_pci.o +obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS) += comedi_pcmcia.o +obj-$(CONFIG_COMEDI_USB_DRIVERS) += comedi_usb.o + obj-$(CONFIG_COMEDI) += comedi.o obj-$(CONFIG_COMEDI) += kcomedilib/ diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index c8c99e65423b..745574077352 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -367,6 +367,8 @@ enum comedi_support_level { #define COMEDI_BUFCONFIG _IOR(CIO, 13, struct comedi_bufconfig) #define COMEDI_BUFINFO _IOWR(CIO, 14, struct comedi_bufinfo) #define COMEDI_POLL _IO(CIO, 15) +#define COMEDI_SETRSUBD _IO(CIO, 16) +#define COMEDI_SETWSUBD _IO(CIO, 17) /* structures */ @@ -514,17 +516,6 @@ struct comedi_bufinfo { #define COMEDI_MIN_SPEED ((unsigned int)0xffffffff) -/* callback stuff */ -/* only relevant to kernel modules. */ - -#define COMEDI_CB_EOS 1 /* end of scan */ -#define COMEDI_CB_EOA 2 /* end of acquisition/output */ -#define COMEDI_CB_BLOCK 4 /* data has arrived: - * wakes up read() / write() */ -#define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */ -#define COMEDI_CB_ERROR 16 /* card error during acquisition */ -#define COMEDI_CB_OVERFLOW 32 /* buffer overflow/underflow */ - /**********************************************************/ /* everything after this line is ALPHA */ /**********************************************************/ diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index c60a45ad12b9..19e7b229d15e 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -236,6 +236,7 @@ void comedi_buf_reset(struct comedi_subdevice *s) async->buf_read_ptr = 0; async->cur_chan = 0; + async->scans_done = 0; async->scan_progress = 0; async->munge_chan = 0; async->munge_count = 0; @@ -252,15 +253,15 @@ static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) return free_end - async->buf_write_alloc_count; } -static unsigned int __comedi_buf_write_alloc(struct comedi_subdevice *s, - unsigned int nbytes, - int strict) +/* allocates chunk for the writer from free buffer space */ +unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, + unsigned int nbytes) { struct comedi_async *async = s->async; unsigned int available = comedi_buf_write_n_available(s); if (nbytes > available) - nbytes = strict ? 0 : available; + nbytes = available; async->buf_write_alloc_count += nbytes; @@ -272,13 +273,6 @@ static unsigned int __comedi_buf_write_alloc(struct comedi_subdevice *s, return nbytes; } - -/* allocates chunk for the writer from free buffer space */ -unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, - unsigned int nbytes) -{ - return __comedi_buf_write_alloc(s, nbytes, 0); -} EXPORT_SYMBOL_GPL(comedi_buf_write_alloc); /* @@ -290,7 +284,7 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s, { struct comedi_async *async = s->async; unsigned int count = 0; - const unsigned num_sample_bytes = bytes_per_sample(s); + const unsigned num_sample_bytes = comedi_bytes_per_sample(s); if (!s->munge || (async->cmd.flags & CMDF_RAWDATA)) { async->munge_count += num_bytes; @@ -427,43 +421,11 @@ unsigned int comedi_buf_read_free(struct comedi_subdevice *s, } EXPORT_SYMBOL_GPL(comedi_buf_read_free); -int comedi_buf_put(struct comedi_subdevice *s, unsigned short x) -{ - 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(s, sizeof(short)); - return 1; -} -EXPORT_SYMBOL_GPL(comedi_buf_put); - -int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x) +static void comedi_buf_memcpy_to(struct comedi_subdevice *s, + const void *data, unsigned int num_bytes) { 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(s, sizeof(short)); - *x = *(unsigned short *)(async->prealloc_buf + async->buf_read_ptr); - comedi_buf_read_free(s, sizeof(short)); - return 1; -} -EXPORT_SYMBOL_GPL(comedi_buf_get); - -void comedi_buf_memcpy_to(struct comedi_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) - write_ptr %= async->prealloc_bufsz; + unsigned int write_ptr = async->buf_write_ptr; while (num_bytes) { unsigned int block_size; @@ -481,17 +443,13 @@ void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset, write_ptr = 0; } } -EXPORT_SYMBOL_GPL(comedi_buf_memcpy_to); -void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset, - void *dest, unsigned int nbytes) +static void comedi_buf_memcpy_from(struct comedi_subdevice *s, + 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) - read_ptr %= async->prealloc_bufsz; + unsigned int read_ptr = async->buf_read_ptr; while (nbytes) { unsigned int block_size; @@ -509,69 +467,84 @@ void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset, read_ptr = 0; } } -EXPORT_SYMBOL_GPL(comedi_buf_memcpy_from); /** - * comedi_write_array_to_buffer - write data to comedi buffer + * comedi_buf_write_samples - write sample data to comedi buffer * @s: comedi_subdevice struct - * @data: destination - * @num_bytes: number of bytes to write + * @data: samples + * @nsamples: number of samples * - * Writes up to num_bytes bytes of data to the comedi buffer associated with - * the subdevice, marks it as written and updates the acquisition scan - * progress. + * Writes nsamples to the comedi buffer associated with the subdevice, marks + * it as written and updates the acquisition scan progress. * * Returns the amount of data written in bytes. */ -unsigned int comedi_write_array_to_buffer(struct comedi_subdevice *s, - const void *data, - unsigned int num_bytes) +unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, + const void *data, unsigned int nsamples) { - struct comedi_async *async = s->async; - unsigned int retval; - - if (num_bytes == 0) - return 0; + unsigned int max_samples; + unsigned int nbytes; - retval = comedi_buf_write_alloc(s, num_bytes); - if (retval != num_bytes) { + /* + * Make sure there is enough room in the buffer for all the samples. + * If not, clamp the nsamples to the number that will fit, flag the + * buffer overrun and add the samples that fit. + */ + max_samples = comedi_bytes_to_samples(s, + comedi_buf_write_n_available(s)); + if (nsamples > max_samples) { dev_warn(s->device->class_dev, "buffer overrun\n"); - async->events |= COMEDI_CB_OVERFLOW; - return 0; + s->async->events |= COMEDI_CB_OVERFLOW; + nsamples = max_samples; } - comedi_buf_memcpy_to(s, 0, data, num_bytes); - comedi_buf_write_free(s, num_bytes); - comedi_inc_scan_progress(s, num_bytes); - async->events |= COMEDI_CB_BLOCK; + if (nsamples == 0) + return 0; - return num_bytes; + nbytes = comedi_buf_write_alloc(s, + comedi_samples_to_bytes(s, nsamples)); + comedi_buf_memcpy_to(s, data, nbytes); + comedi_buf_write_free(s, nbytes); + comedi_inc_scan_progress(s, nbytes); + s->async->events |= COMEDI_CB_BLOCK; + + return nbytes; } -EXPORT_SYMBOL_GPL(comedi_write_array_to_buffer); +EXPORT_SYMBOL_GPL(comedi_buf_write_samples); /** - * comedi_read_array_from_buffer - read data from comedi buffer + * comedi_buf_read_samples - read sample data from comedi buffer * @s: comedi_subdevice struct * @data: destination - * @num_bytes: number of bytes to read + * @nsamples: maximum number of samples to read * - * Reads up to num_bytes bytes of data from the comedi buffer associated with - * the subdevice, marks it as read and updates the acquisition scan progress. + * Reads up to nsamples from the comedi buffer associated with the subdevice, + * marks it as read and updates the acquisition scan progress. * * Returns the amount of data read in bytes. */ -unsigned int comedi_read_array_from_buffer(struct comedi_subdevice *s, - void *data, unsigned int num_bytes) +unsigned int comedi_buf_read_samples(struct comedi_subdevice *s, + void *data, unsigned int nsamples) { - if (num_bytes == 0) + unsigned int max_samples; + unsigned int nbytes; + + /* clamp nsamples to the number of full samples available */ + max_samples = comedi_bytes_to_samples(s, + comedi_buf_read_n_available(s)); + if (nsamples > max_samples) + nsamples = max_samples; + + if (nsamples == 0) return 0; - 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); - comedi_inc_scan_progress(s, num_bytes); + nbytes = comedi_buf_read_alloc(s, + comedi_samples_to_bytes(s, nsamples)); + comedi_buf_memcpy_from(s, data, nbytes); + comedi_buf_read_free(s, nbytes); + comedi_inc_scan_progress(s, nbytes); s->async->events |= COMEDI_CB_BLOCK; - return num_bytes; + return nbytes; } -EXPORT_SYMBOL_GPL(comedi_read_array_from_buffer); +EXPORT_SYMBOL_GPL(comedi_buf_read_samples); diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index 9b6f96f1591c..5a4c74f703b3 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -416,6 +416,8 @@ static inline int raw_ioctl(struct file *file, unsigned int cmd, case COMEDI_UNLOCK: case COMEDI_CANCEL: case COMEDI_POLL: + case COMEDI_SETRSUBD: + case COMEDI_SETWSUBD: /* No translation needed. */ rc = translated_ioctl(file, cmd, arg); break; diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 9c32f0276009..f143cb64d69e 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -43,6 +43,22 @@ #include "comedi_internal.h" +/** + * struct comedi_file - per-file private data for comedi device + * @dev: comedi_device struct + * @read_subdev: current "read" subdevice + * @write_subdev: current "write" subdevice + * @last_detach_count: last known detach count + * @last_attached: last known attached/detached state + */ +struct comedi_file { + struct comedi_device *dev; + struct comedi_subdevice *read_subdev; + struct comedi_subdevice *write_subdev; + unsigned int last_detach_count; + bool last_attached:1; +}; + #define COMEDI_NUM_MINORS 0x100 #define COMEDI_NUM_SUBDEVICE_MINORS \ (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS) @@ -239,6 +255,54 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor) return dev->write_subdev; } +static void comedi_file_reset(struct file *file) +{ + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; + struct comedi_subdevice *s, *read_s, *write_s; + unsigned int minor = iminor(file_inode(file)); + + read_s = dev->read_subdev; + write_s = dev->write_subdev; + if (minor >= COMEDI_NUM_BOARD_MINORS) { + s = comedi_subdevice_from_minor(dev, minor); + if (s == NULL || s->subdev_flags & SDF_CMD_READ) + read_s = s; + if (s == NULL || s->subdev_flags & SDF_CMD_WRITE) + write_s = s; + } + cfp->last_attached = dev->attached; + cfp->last_detach_count = dev->detach_count; + ACCESS_ONCE(cfp->read_subdev) = read_s; + ACCESS_ONCE(cfp->write_subdev) = write_s; +} + +static void comedi_file_check(struct file *file) +{ + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; + + if (cfp->last_attached != dev->attached || + cfp->last_detach_count != dev->detach_count) + comedi_file_reset(file); +} + +static struct comedi_subdevice *comedi_file_read_subdevice(struct file *file) +{ + struct comedi_file *cfp = file->private_data; + + comedi_file_check(file); + return ACCESS_ONCE(cfp->read_subdev); +} + +static struct comedi_subdevice *comedi_file_write_subdevice(struct file *file) +{ + struct comedi_file *cfp = file->private_data; + + comedi_file_check(file); + return ACCESS_ONCE(cfp->write_subdev); +} + static int resize_async_buffer(struct comedi_device *dev, struct comedi_subdevice *s, unsigned new_size) { @@ -776,7 +840,6 @@ static int do_devinfo_ioctl(struct comedi_device *dev, struct comedi_devinfo __user *arg, struct file *file) { - const unsigned minor = iminor(file_inode(file)); struct comedi_subdevice *s; struct comedi_devinfo devinfo; @@ -788,13 +851,13 @@ static int do_devinfo_ioctl(struct comedi_device *dev, strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN); strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN); - s = comedi_read_subdevice(dev, minor); + s = comedi_file_read_subdevice(file); if (s) devinfo.read_subdevice = s->index; else devinfo.read_subdevice = -1; - s = comedi_write_subdevice(dev, minor); + s = comedi_file_write_subdevice(file); if (s) devinfo.write_subdevice = s->index; else @@ -991,7 +1054,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, if (s->busy != file) return -EACCES; - if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) { + if (bi.bytes_read && !(async->cmd.flags & CMDF_WRITE)) { bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read); comedi_buf_read_free(s, bi.bytes_read); @@ -1001,7 +1064,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, } } - if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) { + if (bi.bytes_written && (async->cmd.flags & CMDF_WRITE)) { bi.bytes_written = comedi_buf_write_alloc(s, bi.bytes_written); comedi_buf_write_free(s, bi.bytes_written); @@ -1451,6 +1514,21 @@ static int __comedi_get_user_cmd(struct comedi_device *dev, return -EINVAL; } + /* + * Set the CMDF_WRITE flag to the correct state if the subdevice + * supports only "read" commands or only "write" commands. + */ + switch (s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) { + case SDF_CMD_READ: + cmd->flags &= ~CMDF_WRITE; + break; + case SDF_CMD_WRITE: + cmd->flags |= CMDF_WRITE; + break; + default: + break; + } + return 0; } @@ -1552,9 +1630,7 @@ static int do_cmd_ioctl(struct comedi_device *dev, comedi_buf_reset(s); - async->cb_mask = - COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW; + async->cb_mask = COMEDI_CB_BLOCK | COMEDI_CB_CANCEL_MASK; if (async->cmd.flags & CMDF_WAKE_EOS) async->cb_mask |= COMEDI_CB_EOS; @@ -1720,7 +1796,6 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg, void *file) { struct comedi_subdevice *s; - int ret; if (arg >= dev->n_subdevices) return -EINVAL; @@ -1734,9 +1809,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg, if (s->busy != file) return -EBUSY; - ret = do_cancel(dev, s); - - return ret; + return do_cancel(dev, s); } /* @@ -1774,11 +1847,96 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg, return -EINVAL; } +/* + * COMEDI_SETRSUBD ioctl + * sets the current "read" subdevice on a per-file basis + * + * arg: + * subdevice number + * + * reads: + * nothing + * + * writes: + * nothing + */ +static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg, + struct file *file) +{ + struct comedi_file *cfp = file->private_data; + struct comedi_subdevice *s_old, *s_new; + + if (arg >= dev->n_subdevices) + return -EINVAL; + + s_new = &dev->subdevices[arg]; + s_old = comedi_file_read_subdevice(file); + if (s_old == s_new) + return 0; /* no change */ + + if (!(s_new->subdev_flags & SDF_CMD_READ)) + return -EINVAL; + + /* + * Check the file isn't still busy handling a "read" command on the + * old subdevice (if any). + */ + if (s_old && s_old->busy == file && s_old->async && + !(s_old->async->cmd.flags & CMDF_WRITE)) + return -EBUSY; + + ACCESS_ONCE(cfp->read_subdev) = s_new; + return 0; +} + +/* + * COMEDI_SETWSUBD ioctl + * sets the current "write" subdevice on a per-file basis + * + * arg: + * subdevice number + * + * reads: + * nothing + * + * writes: + * nothing + */ +static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg, + struct file *file) +{ + struct comedi_file *cfp = file->private_data; + struct comedi_subdevice *s_old, *s_new; + + if (arg >= dev->n_subdevices) + return -EINVAL; + + s_new = &dev->subdevices[arg]; + s_old = comedi_file_write_subdevice(file); + if (s_old == s_new) + return 0; /* no change */ + + if (!(s_new->subdev_flags & SDF_CMD_WRITE)) + return -EINVAL; + + /* + * Check the file isn't still busy handling a "write" command on the + * old subdevice (if any). + */ + if (s_old && s_old->busy == file && s_old->async && + (s_old->async->cmd.flags & CMDF_WRITE)) + return -EBUSY; + + ACCESS_ONCE(cfp->write_subdev) = s_new; + return 0; +} + static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = file->private_data; + unsigned minor = iminor(file_inode(file)); + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; int rc; mutex_lock(&dev->mutex); @@ -1867,6 +2025,12 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, case COMEDI_POLL: rc = do_poll_ioctl(dev, arg, file); break; + case COMEDI_SETRSUBD: + rc = do_setrsubd_ioctl(dev, arg, file); + break; + case COMEDI_SETWSUBD: + rc = do_setwsubd_ioctl(dev, arg, file); + break; default: rc = -ENOTTY; break; @@ -1900,8 +2064,8 @@ static struct vm_operations_struct comedi_vm_ops = { static int comedi_mmap(struct file *file, struct vm_area_struct *vma) { - const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = file->private_data; + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; struct comedi_subdevice *s; struct comedi_async *async; struct comedi_buf_map *bm = NULL; @@ -1927,9 +2091,9 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } if (vma->vm_flags & VM_WRITE) - s = comedi_write_subdevice(dev, minor); + s = comedi_file_write_subdevice(file); else - s = comedi_read_subdevice(dev, minor); + s = comedi_file_read_subdevice(file); if (!s) { retval = -EINVAL; goto done; @@ -1992,8 +2156,8 @@ done: static unsigned int comedi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = file->private_data; + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; struct comedi_subdevice *s; mutex_lock(&dev->mutex); @@ -2003,21 +2167,23 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) goto done; } - s = comedi_read_subdevice(dev, minor); + s = comedi_file_read_subdevice(file); if (s && s->async) { poll_wait(file, &s->async->wait_head, wait); if (!s->busy || !comedi_is_subdevice_running(s) || + (s->async->cmd.flags & CMDF_WRITE) || comedi_buf_read_n_available(s) > 0) mask |= POLLIN | POLLRDNORM; } - s = comedi_write_subdevice(dev, minor); + s = comedi_file_write_subdevice(file); if (s && s->async) { - unsigned int bps = bytes_per_sample(s); + unsigned int bps = comedi_bytes_per_sample(s); poll_wait(file, &s->async->wait_head, wait); comedi_buf_write_alloc(s, s->async->prealloc_bufsz); if (!s->busy || !comedi_is_subdevice_running(s) || + !(s->async->cmd.flags & CMDF_WRITE) || comedi_buf_write_n_allocated(s) >= bps) mask |= POLLOUT | POLLWRNORM; } @@ -2034,8 +2200,8 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, struct comedi_async *async; int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); - const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = file->private_data; + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; bool on_wait_queue = false; bool attach_locked; unsigned int old_detach_count; @@ -2051,7 +2217,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, goto out; } - s = comedi_write_subdevice(dev, minor); + s = comedi_file_write_subdevice(file); if (!s || !s->async) { retval = -EIO; goto out; @@ -2065,6 +2231,10 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, retval = -EACCES; goto out; } + if (!(async->cmd.flags & CMDF_WRITE)) { + retval = -EINVAL; + goto out; + } add_wait_queue(&async->wait_head, &wait); on_wait_queue = true; @@ -2099,7 +2269,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, * meantime!), but check the subdevice pointer * as well just in case. */ - new_s = comedi_write_subdevice(dev, minor); + new_s = comedi_file_write_subdevice(file); if (dev->attached && old_detach_count == dev->detach_count && s == new_s && new_s->async == async) @@ -2136,6 +2306,10 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, retval = -EACCES; break; } + if (!(async->cmd.flags & CMDF_WRITE)) { + retval = -EINVAL; + break; + } continue; } @@ -2170,8 +2344,8 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, struct comedi_async *async; int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); - const unsigned minor = iminor(file_inode(file)); - struct comedi_device *dev = file->private_data; + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; unsigned int old_detach_count; bool become_nonbusy = false; bool attach_locked; @@ -2187,7 +2361,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, goto out; } - s = comedi_read_subdevice(dev, minor); + s = comedi_file_read_subdevice(file); if (!s || !s->async) { retval = -EIO; goto out; @@ -2200,6 +2374,10 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, retval = -EACCES; goto out; } + if (async->cmd.flags & CMDF_WRITE) { + retval = -EINVAL; + goto out; + } add_wait_queue(&async->wait_head, &wait); while (nbytes > 0 && !retval) { @@ -2239,6 +2417,10 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, retval = -EACCES; break; } + if (async->cmd.flags & CMDF_WRITE) { + retval = -EINVAL; + break; + } continue; } m = copy_to_user(buf, async->prealloc_buf + @@ -2276,7 +2458,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, * meantime!), but check the subdevice pointer as well just in * case. */ - new_s = comedi_read_subdevice(dev, minor); + new_s = comedi_file_read_subdevice(file); if (dev->attached && old_detach_count == dev->detach_count && s == new_s && new_s->async == async) { if (become_nonbusy || comedi_buf_n_bytes_ready(s) == 0) @@ -2294,6 +2476,7 @@ out: static int comedi_open(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); + struct comedi_file *cfp; struct comedi_device *dev = comedi_dev_get_from_minor(minor); int rc; @@ -2302,6 +2485,12 @@ static int comedi_open(struct inode *inode, struct file *file) return -ENODEV; } + cfp = kzalloc(sizeof(*cfp), GFP_KERNEL); + if (!cfp) + return -ENOMEM; + + cfp->dev = dev; + mutex_lock(&dev->mutex); if (!dev->attached && !capable(CAP_NET_ADMIN)) { dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n"); @@ -2323,26 +2512,31 @@ static int comedi_open(struct inode *inode, struct file *file) } dev->use_count++; - file->private_data = dev; + file->private_data = cfp; + comedi_file_reset(file); rc = 0; out: mutex_unlock(&dev->mutex); - if (rc) + if (rc) { comedi_dev_put(dev); + kfree(cfp); + } return rc; } static int comedi_fasync(int fd, struct file *file, int on) { - struct comedi_device *dev = file->private_data; + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; return fasync_helper(fd, file, on, &dev->async_queue); } static int comedi_close(struct inode *inode, struct file *file) { - struct comedi_device *dev = file->private_data; + struct comedi_file *cfp = file->private_data; + struct comedi_device *dev = cfp->dev; struct comedi_subdevice *s = NULL; int i; @@ -2368,6 +2562,7 @@ static int comedi_close(struct inode *inode, struct file *file) mutex_unlock(&dev->mutex); comedi_dev_put(dev); + kfree(cfp); return 0; } @@ -2395,14 +2590,14 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) if (!comedi_is_subdevice_running(s)) return; - if (s-> - async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { + if (s->async->events & COMEDI_CB_CANCEL_MASK) runflags_mask |= SRF_RUNNING; - } - /* remember if an error event has occurred, so an error - * can be returned the next time the user does a read() */ - if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { + + /* + * Remember if an error event has occurred, so an error + * can be returned the next time the user does a read(). + */ + if (s->async->events & COMEDI_CB_ERROR_MASK) { runflags_mask |= SRF_ERROR; runflags |= SRF_ERROR; } diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/staging/comedi/comedi_pci.c index aa0795a2660e..6ba59c977006 100644 --- a/drivers/staging/comedi/comedi_pci.c +++ b/drivers/staging/comedi/comedi_pci.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -168,3 +169,18 @@ void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, comedi_driver_unregister(comedi_driver); } EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister); + +static int __init comedi_pci_init(void) +{ + return 0; +} +module_init(comedi_pci_init); + +static void __exit comedi_pci_exit(void) +{ +} +module_exit(comedi_pci_exit); + +MODULE_AUTHOR("http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi PCI interface module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/staging/comedi/comedi_pcmcia.c index 9d49d5d01ad9..0529bae8e5ac 100644 --- a/drivers/staging/comedi/comedi_pcmcia.c +++ b/drivers/staging/comedi/comedi_pcmcia.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include <linux/module.h> #include <linux/kernel.h> #include <pcmcia/cistpl.h> @@ -154,3 +155,18 @@ void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver, comedi_driver_unregister(comedi_driver); } EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_unregister); + +static int __init comedi_pcmcia_init(void) +{ + return 0; +} +module_init(comedi_pcmcia_init); + +static void __exit comedi_pcmcia_exit(void) +{ +} +module_exit(comedi_pcmcia_exit); + +MODULE_AUTHOR("http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi PCMCIA interface module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/staging/comedi/comedi_usb.c index 13f18bef6091..0b862a64c049 100644 --- a/drivers/staging/comedi/comedi_usb.c +++ b/drivers/staging/comedi/comedi_usb.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include <linux/module.h> #include <linux/usb.h> #include "comedidev.h" @@ -114,3 +115,18 @@ void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver, comedi_driver_unregister(comedi_driver); } EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister); + +static int __init comedi_usb_init(void) +{ + return 0; +} +module_init(comedi_usb_init); + +static void __exit comedi_usb_exit(void) +{ +} +module_exit(comedi_usb_exit); + +MODULE_AUTHOR("http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi USB interface module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index 1b2bbd56f6ef..77be191988ca 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -121,6 +121,7 @@ struct comedi_buf_map { * @buf_read_ptr: buffer position for reader * @cur_chan: current position in chanlist for scan (for those * drivers that use it) + * @scans_done: the number of scans completed (COMEDI_CB_EOS) * @scan_progress: amount received or sent for current scan (in bytes) * @munge_chan: current position in chanlist for "munging" * @munge_count: "munge" count (in bytes, modulo 2**32) @@ -201,6 +202,7 @@ struct comedi_async { unsigned int buf_write_ptr; unsigned int buf_read_ptr; unsigned int cur_chan; + unsigned int scans_done; unsigned int scan_progress; unsigned int munge_chan; unsigned int munge_count; @@ -213,6 +215,28 @@ struct comedi_async { unsigned int x); }; +/** + * comedi_async callback "events" + * @COMEDI_CB_EOS: end-of-scan + * @COMEDI_CB_EOA: end-of-acquisition/output + * @COMEDI_CB_BLOCK: data has arrived, wakes up read() / write() + * @COMEDI_CB_EOBUF: DEPRECATED: end of buffer + * @COMEDI_CB_ERROR: card error during acquisition + * @COMEDI_CB_OVERFLOW: buffer overflow/underflow + * + * @COMEDI_CB_ERROR_MASK: events that indicate an error has occurred + * @COMEDI_CB_CANCEL_MASK: events that will cancel an async command + */ +#define COMEDI_CB_EOS (1 << 0) +#define COMEDI_CB_EOA (1 << 1) +#define COMEDI_CB_BLOCK (1 << 2) +#define COMEDI_CB_EOBUF (1 << 3) +#define COMEDI_CB_ERROR (1 << 4) +#define COMEDI_CB_OVERFLOW (1 << 5) + +#define COMEDI_CB_ERROR_MASK (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW) +#define COMEDI_CB_CANCEL_MASK (COMEDI_CB_EOA | COMEDI_CB_ERROR_MASK) + struct comedi_driver { struct comedi_driver *next; @@ -391,12 +415,61 @@ static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, return val ^ s->maxdata ^ (s->maxdata >> 1); } -static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) +/** + * comedi_bytes_per_sample - determine subdevice sample size + * @s: comedi_subdevice struct + * + * The sample size will be 4 (sizeof int) or 2 (sizeof short) depending on + * whether the SDF_LSAMPL subdevice flag is set or not. + * + * Returns the subdevice sample size. + */ +static inline unsigned int comedi_bytes_per_sample(struct comedi_subdevice *s) +{ + return s->subdev_flags & SDF_LSAMPL ? sizeof(int) : sizeof(short); +} + +/** + * comedi_sample_shift - determine log2 of subdevice sample size + * @s: comedi_subdevice struct + * + * The sample size will be 4 (sizeof int) or 2 (sizeof short) depending on + * whether the SDF_LSAMPL subdevice flag is set or not. The log2 of the + * sample size will be 2 or 1 and can be used as the right operand of a + * bit-shift operator to multiply or divide something by the sample size. + * + * Returns log2 of the subdevice sample size. + */ +static inline unsigned int comedi_sample_shift(struct comedi_subdevice *s) { - if (subd->subdev_flags & SDF_LSAMPL) - return sizeof(unsigned int); + return s->subdev_flags & SDF_LSAMPL ? 2 : 1; +} - return sizeof(short); +/** + * comedi_bytes_to_samples - converts a number of bytes to a number of samples + * @s: comedi_subdevice struct + * @nbytes: number of bytes + * + * Returns the number of bytes divided by the subdevice sample size. + */ +static inline unsigned int comedi_bytes_to_samples(struct comedi_subdevice *s, + unsigned int nbytes) +{ + return nbytes >> comedi_sample_shift(s); +} + +/** + * comedi_samples_to_bytes - converts a number of samples to a number of bytes + * @s: comedi_subdevice struct + * @nsamples: number of samples + * + * Returns the number of samples multiplied by the subdevice sample size. + * Does not check for arithmetic overflow. + */ +static inline unsigned int comedi_samples_to_bytes(struct comedi_subdevice *s, + unsigned int nsamples) +{ + return nsamples << comedi_sample_shift(s); } /* @@ -419,18 +492,10 @@ 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_subdevice *s, unsigned short x); -int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x); - -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_subdevice *s, unsigned int offset, - void *destination, unsigned int num_bytes); -unsigned int comedi_write_array_to_buffer(struct comedi_subdevice *s, - const void *data, - unsigned int num_bytes); -unsigned int comedi_read_array_from_buffer(struct comedi_subdevice *s, - void *data, unsigned int num_bytes); +unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, + const void *data, unsigned int nsamples); +unsigned int comedi_buf_read_samples(struct comedi_subdevice *s, + void *data, unsigned int nsamples); /* drivers.c - general comedi driver functions */ @@ -451,6 +516,10 @@ int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *, unsigned int comedi_dio_update_state(struct comedi_subdevice *, unsigned int *data); unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s); +unsigned int comedi_nscans_left(struct comedi_subdevice *s, + unsigned int nscans); +unsigned int comedi_nsamples_left(struct comedi_subdevice *s, + unsigned int nsamples); void comedi_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes); @@ -493,8 +562,6 @@ void comedi_driver_unregister(struct comedi_driver *); module_driver(__comedi_driver, comedi_driver_register, \ comedi_driver_unregister) -#ifdef CONFIG_COMEDI_PCI_DRIVERS - /* comedi_pci.c - comedi PCI driver specific functions */ /* @@ -538,36 +605,6 @@ void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *); module_driver(__comedi_driver, comedi_pci_driver_register, \ comedi_pci_driver_unregister, &(__pci_driver)) -#else - -/* - * Some of the comedi mixed ISA/PCI drivers call the PCI specific - * functions. Provide some dummy functions if CONFIG_COMEDI_PCI_DRIVERS - * is not enabled. - */ - -static inline struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) -{ - return NULL; -} - -static inline int comedi_pci_enable(struct comedi_device *dev) -{ - return -ENOSYS; -} - -static inline void comedi_pci_disable(struct comedi_device *dev) -{ -} - -static inline void comedi_pci_detach(struct comedi_device *dev) -{ -} - -#endif /* CONFIG_COMEDI_PCI_DRIVERS */ - -#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS - /* comedi_pcmcia.c - comedi PCMCIA driver specific functions */ struct pcmcia_driver; @@ -601,10 +638,6 @@ void comedi_pcmcia_driver_unregister(struct comedi_driver *, module_driver(__comedi_driver, comedi_pcmcia_driver_register, \ comedi_pcmcia_driver_unregister, &(__pcmcia_driver)) -#endif /* CONFIG_COMEDI_PCMCIA_DRIVERS */ - -#ifdef CONFIG_COMEDI_USB_DRIVERS - /* comedi_usb.c - comedi USB driver specific functions */ struct usb_driver; @@ -634,6 +667,4 @@ void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *); module_driver(__comedi_driver, comedi_usb_driver_register, \ comedi_usb_driver_unregister, &(__usb_driver)) -#endif /* CONFIG_COMEDI_USB_DRIVERS */ - #endif /* _COMEDIDEV_H */ diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 3e5bccbc9c39..61802d7947ae 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -109,6 +109,10 @@ int comedi_alloc_subdev_readback(struct comedi_subdevice *s) s->readback = kcalloc(s->n_chan, sizeof(*s->readback), GFP_KERNEL); if (!s->readback) return -ENOMEM; + + if (!s->insn_read) + s->insn_read = comedi_readback_insn_read; + return 0; } EXPORT_SYMBOL_GPL(comedi_alloc_subdev_readback); @@ -316,19 +320,91 @@ unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s) 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; + bits_per_sample = 8 * comedi_bytes_per_sample(s); + num_samples = DIV_ROUND_UP(cmd->scan_end_arg, bits_per_sample); break; default: - num_samples = cmd->chanlist_len; + num_samples = cmd->scan_end_arg; break; } - return num_samples * bytes_per_sample(s); + return comedi_samples_to_bytes(s, num_samples); } EXPORT_SYMBOL_GPL(comedi_bytes_per_scan); /** + * comedi_nscans_left - return the number of scans left in the command + * @s: comedi_subdevice struct + * @nscans: the expected number of scans + * + * If nscans is 0, the number of scans available in the async buffer will be + * used. Otherwise the expected number of scans will be used. + * + * If the async command has a stop_src of TRIG_COUNT, the nscans will be + * checked against the number of scans left in the command. + * + * The return value will then be either the expected number of scans or the + * number of scans remaining in the command. + */ +unsigned int comedi_nscans_left(struct comedi_subdevice *s, + unsigned int nscans) +{ + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + + if (nscans == 0) { + unsigned int nbytes = comedi_buf_read_n_available(s); + + nscans = nbytes / comedi_bytes_per_scan(s); + } + + if (cmd->stop_src == TRIG_COUNT) { + unsigned int scans_left = 0; + + if (async->scans_done < cmd->stop_arg) + scans_left = cmd->stop_arg - async->scans_done; + + if (nscans > scans_left) + nscans = scans_left; + } + return nscans; +} +EXPORT_SYMBOL_GPL(comedi_nscans_left); + +/** + * comedi_nsamples_left - return the number of samples left in the command + * @s: comedi_subdevice struct + * @nsamples: the expected number of samples + * + * Returns the expected number of samples of the number of samples remaining + * in the command. + */ +unsigned int comedi_nsamples_left(struct comedi_subdevice *s, + unsigned int nsamples) +{ + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + + if (cmd->stop_src == TRIG_COUNT) { + /* +1 to force comedi_nscans_left() to return the scans left */ + unsigned int nscans = (nsamples / cmd->scan_end_arg) + 1; + unsigned int scans_left = comedi_nscans_left(s, nscans); + unsigned int scan_pos = + comedi_bytes_to_samples(s, async->scan_progress); + unsigned long long samples_left = 0; + + if (scans_left) { + samples_left = ((unsigned long long)scans_left * + cmd->scan_end_arg) - scan_pos; + } + + if (samples_left < nsamples) + nsamples = samples_left; + } + return nsamples; +} +EXPORT_SYMBOL_GPL(comedi_nsamples_left); + +/** * comedi_inc_scan_progress - update scan progress in asynchronous command * @s: comedi_subdevice struct * @num_bytes: amount of data in bytes to increment scan progress @@ -342,10 +418,24 @@ void comedi_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes) { struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; unsigned int scan_length = comedi_bytes_per_scan(s); + /* track the 'cur_chan' for non-SDF_PACKED subdevices */ + if (!(s->subdev_flags & SDF_PACKED)) { + async->cur_chan += comedi_bytes_to_samples(s, num_bytes); + async->cur_chan %= cmd->chanlist_len; + } + async->scan_progress += num_bytes; if (async->scan_progress >= scan_length) { + unsigned int nscans = async->scan_progress / scan_length; + + if (async->scans_done < (UINT_MAX - nscans)) + async->scans_done += nscans; + else + async->scans_done = UINT_MAX; + async->scan_progress %= scan_length; async->events |= COMEDI_CB_EOS; } @@ -376,7 +466,7 @@ unsigned int comedi_handle_events(struct comedi_device *dev, if (events == 0) return events; - if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) + if (events & COMEDI_CB_CANCEL_MASK) s->cancel(dev, s); comedi_event(dev, s); diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 6bc9ef3b25b3..84fdf20ca986 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -60,7 +60,6 @@ obj-$(CONFIG_COMEDI_S526) += s526.o # Comedi PCI drivers obj-$(CONFIG_COMEDI_8255_PCI) += 8255_pci.o obj-$(CONFIG_COMEDI_ADDI_WATCHDOG) += addi_watchdog.o -obj-$(CONFIG_COMEDI_ADDI_APCI_035) += addi_apci_035.o obj-$(CONFIG_COMEDI_ADDI_APCI_1032) += addi_apci_1032.o obj-$(CONFIG_COMEDI_ADDI_APCI_1500) += addi_apci_1500.o obj-$(CONFIG_COMEDI_ADDI_APCI_1516) += addi_apci_1516.o diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c deleted file mode 100644 index 2e7fb218340f..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ /dev/null @@ -1,274 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; either version 2 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : ADDI DATA | Compiler : GCC | - | Modulname : addi_common.c | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Author : | Date : | - +-----------------------------------------------------------------------+ - | Description : ADDI COMMON Main Module | - +-----------------------------------------------------------------------+ -*/ - -static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv = dev->private; - unsigned short w_Address = CR_CHAN(insn->chanspec); - unsigned short w_Data; - - w_Data = addi_eeprom_readw(devpriv->i_IobaseAmcc, - this_board->pc_EepromChip, 2 * w_Address); - data[0] = w_Data; - - return insn->n; -} - -static irqreturn_t v_ADDI_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - const struct addi_board *this_board = dev->board_ptr; - - this_board->interrupt(irq, d); - return IRQ_RETVAL(1); -} - -static int i_ADDI_Reset(struct comedi_device *dev) -{ - const struct addi_board *this_board = dev->board_ptr; - - this_board->reset(dev); - return 0; -} - -static int addi_auto_attach(struct comedi_device *dev, - unsigned long context_unused) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv; - struct comedi_subdevice *s; - int ret, n_subdevices; - unsigned int dw_Dummy; - - dev->board_name = this_board->pc_DriverName; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - ret = comedi_pci_enable(dev); - if (ret) - return ret; - - if (this_board->i_IorangeBase1) - dev->iobase = pci_resource_start(pcidev, 1); - else - dev->iobase = pci_resource_start(pcidev, 0); - - devpriv->iobase = dev->iobase; - devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); - devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); - devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); - - /* Initialize parameters that can be overridden in EEPROM */ - devpriv->s_EeParameters.i_NbrAiChannel = this_board->i_NbrAiChannel; - devpriv->s_EeParameters.i_NbrAoChannel = this_board->i_NbrAoChannel; - devpriv->s_EeParameters.i_AiMaxdata = this_board->i_AiMaxdata; - devpriv->s_EeParameters.i_AoMaxdata = this_board->i_AoMaxdata; - devpriv->s_EeParameters.i_NbrDiChannel = this_board->i_NbrDiChannel; - devpriv->s_EeParameters.i_NbrDoChannel = this_board->i_NbrDoChannel; - devpriv->s_EeParameters.i_DoMaxdata = this_board->i_DoMaxdata; - devpriv->s_EeParameters.i_Timer = this_board->i_Timer; - devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = - this_board->ui_MinAcquisitiontimeNs; - devpriv->s_EeParameters.ui_MinDelaytimeNs = - this_board->ui_MinDelaytimeNs; - - /* ## */ - - 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; - } - - /* Read eepeom and fill addi_board Structure */ - - if (this_board->i_PCIEeprom) { - if (!(strcmp(this_board->pc_EepromChip, "S5920"))) { - /* Set 3 wait stait */ - if (!(strcmp(dev->board_name, "apci035"))) - outl(0x80808082, devpriv->i_IobaseAmcc + 0x60); - else - outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); - - /* Enable the interrupt for the controller */ - dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); - outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); - } - addi_eeprom_read_info(dev, pci_resource_start(pcidev, 0)); - } - - n_subdevices = 7; - ret = comedi_alloc_subdevices(dev, n_subdevices); - if (ret) - return ret; - - /* Allocate and Initialise AI Subdevice Structures */ - s = &dev->subdevices[0]; - if ((devpriv->s_EeParameters.i_NbrAiChannel) - || (this_board->i_NbrAiChannelDiff)) { - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_COMMON | SDF_GROUND - | SDF_DIFF; - if (devpriv->s_EeParameters.i_NbrAiChannel) - s->n_chan = devpriv->s_EeParameters.i_NbrAiChannel; - else - s->n_chan = this_board->i_NbrAiChannelDiff; - s->maxdata = devpriv->s_EeParameters.i_AiMaxdata; - s->len_chanlist = this_board->i_AiChannelList; - s->range_table = this_board->pr_AiRangelist; - - s->insn_config = this_board->ai_config; - s->insn_read = this_board->ai_read; - s->insn_write = this_board->ai_write; - s->insn_bits = this_board->ai_bits; - s->do_cmdtest = this_board->ai_cmdtest; - s->do_cmd = this_board->ai_cmd; - s->cancel = this_board->ai_cancel; - - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* Allocate and Initialise AO Subdevice Structures */ - s = &dev->subdevices[1]; - if (devpriv->s_EeParameters.i_NbrAoChannel) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel; - s->maxdata = devpriv->s_EeParameters.i_AoMaxdata; - s->len_chanlist = - devpriv->s_EeParameters.i_NbrAoChannel; - s->insn_write = this_board->ao_write; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - /* Allocate and Initialise DI Subdevice Structures */ - s = &dev->subdevices[2]; - if (devpriv->s_EeParameters.i_NbrDiChannel) { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = devpriv->s_EeParameters.i_NbrDiChannel; - s->maxdata = 1; - s->len_chanlist = - devpriv->s_EeParameters.i_NbrDiChannel; - s->range_table = &range_digital; - s->insn_config = this_board->di_config; - s->insn_read = this_board->di_read; - s->insn_write = this_board->di_write; - s->insn_bits = this_board->di_bits; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - /* Allocate and Initialise DO Subdevice Structures */ - s = &dev->subdevices[3]; - if (devpriv->s_EeParameters.i_NbrDoChannel) { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = devpriv->s_EeParameters.i_NbrDoChannel; - s->maxdata = devpriv->s_EeParameters.i_DoMaxdata; - s->len_chanlist = - devpriv->s_EeParameters.i_NbrDoChannel; - s->range_table = &range_digital; - - /* insn_config - for digital output memory */ - s->insn_config = this_board->do_config; - s->insn_write = this_board->do_write; - s->insn_bits = this_board->do_bits; - s->insn_read = this_board->do_read; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* Allocate and Initialise Timer Subdevice Structures */ - s = &dev->subdevices[4]; - if (devpriv->s_EeParameters.i_Timer) { - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; - s->range_table = &range_digital; - - s->insn_write = this_board->timer_write; - s->insn_read = this_board->timer_read; - s->insn_config = this_board->timer_config; - s->insn_bits = this_board->timer_bits; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* Allocate and Initialise TTL */ - s = &dev->subdevices[5]; - s->type = COMEDI_SUBD_UNUSED; - - /* EEPROM */ - s = &dev->subdevices[6]; - if (this_board->i_PCIEeprom) { - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE | SDF_INTERNAL; - s->n_chan = 256; - s->maxdata = 0xffff; - s->insn_read = i_ADDIDATA_InsnReadEeprom; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - i_ADDI_Reset(dev); - return 0; -} - -static void i_ADDI_Detach(struct comedi_device *dev) -{ - if (dev->iobase) - i_ADDI_Reset(dev); - comedi_pci_detach(dev); -} diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h deleted file mode 100644 index e2a3ffeee5cf..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - * - * ADDI-DATA GmbH - * Dieselstrasse 3 - * D-77833 Ottersweier - * Tel: +19(0)7223/9493-0 - * Fax: +49(0)7223/9493-92 - * http://www.addi-data.com - * info@addi-data.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include <linux/sched.h> -#include <linux/interrupt.h> - -struct addi_board { - const char *pc_DriverName; /* driver name */ - int i_IorangeBase1; - int i_PCIEeprom; /* eeprom present or not */ - char *pc_EepromChip; /* type of chip */ - int i_NbrAiChannel; /* num of A/D chans */ - int i_NbrAiChannelDiff; /* num of A/D chans in diff mode */ - int i_AiChannelList; /* len of chanlist */ - int i_NbrAoChannel; /* num of D/A chans */ - int i_AiMaxdata; /* resolution of A/D */ - int i_AoMaxdata; /* resolution of D/A */ - const struct comedi_lrange *pr_AiRangelist; /* rangelist for A/D */ - - int i_NbrDiChannel; /* Number of DI channels */ - int i_NbrDoChannel; /* Number of DO channels */ - int i_DoMaxdata; /* data to set all channels high */ - - int i_Timer; /* timer subdevice present or not */ - unsigned int ui_MinAcquisitiontimeNs; /* Minimum Acquisition in Nano secs */ - unsigned int ui_MinDelaytimeNs; /* Minimum Delay in Nano secs */ - - /* interrupt and reset */ - void (*interrupt)(int irq, void *d); - int (*reset)(struct comedi_device *); - - /* Subdevice functions */ - - /* ANALOG INPUT */ - int (*ai_config)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*ai_read)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*ai_write)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*ai_bits)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*ai_cmdtest)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_cmd *); - int (*ai_cmd)(struct comedi_device *, struct comedi_subdevice *); - int (*ai_cancel)(struct comedi_device *, struct comedi_subdevice *); - - /* Analog Output */ - int (*ao_write)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - - /* Digital Input */ - int (*di_config)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*di_read)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*di_write)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*di_bits)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - - /* Digital Output */ - int (*do_config)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*do_write)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*do_bits)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*do_read)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - - /* TIMER */ - int (*timer_config)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*timer_write)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*timer_read)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*timer_bits)(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); -}; - -struct addi_private { - int iobase; - int i_IobaseAmcc; /* base+size for AMCC chip */ - int i_IobaseAddon; /* addon base address */ - int i_IobaseReserved; - unsigned int ui_AiActualScan; /* how many scans we finished */ - unsigned int ui_AiNbrofChannels; /* how many channels is measured */ - unsigned int ui_AiChannelList[32]; /* actual chanlist */ - unsigned int ui_AiReadData[32]; - 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 */ - unsigned short *ul_DmaBufferVirtual[2]; /* pointers to DMA buffer */ - dma_addr_t ul_DmaBufferHw[2]; /* hw address of DMA buff */ - unsigned int ui_DmaBufferSize[2]; /* size of dma buffer in bytes */ - unsigned int ui_DmaBufferUsesize[2]; /* which size we may now used for transfer */ - unsigned char b_DigitalOutputRegister; /* Digital Output Register */ - unsigned char b_OutputMemoryStatus; - unsigned char b_TimerSelectMode; /* Contain data written at iobase + 0C */ - unsigned char b_ModeSelectRegister; /* Contain data written at iobase + 0E */ - unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */ - unsigned char b_Timer2Mode; /* Specify the timer 2 mode */ - unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */ - 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; - unsigned char b_ExttrigEnable; /* To enable or disable external trigger */ - - /* Pointer to the current process */ - struct task_struct *tsk_Current; - - /* Parameters read from EEPROM overriding static board info */ - struct { - int i_NbrAiChannel; /* num of A/D chans */ - int i_NbrAoChannel; /* num of D/A chans */ - int i_AiMaxdata; /* resolution of A/D */ - int i_AoMaxdata; /* resolution of D/A */ - int i_NbrDiChannel; /* Number of DI channels */ - int i_NbrDoChannel; /* Number of DO channels */ - int i_DoMaxdata; /* data to set all channels high */ - int i_Timer; /* timer subdevice present or not */ - unsigned int ui_MinAcquisitiontimeNs; - /* Minimum Acquisition in Nano secs */ - unsigned int ui_MinDelaytimeNs; - /* Minimum Delay in Nano secs */ - } s_EeParameters; -}; diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c deleted file mode 100644 index b731856c27da..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * addi_eeprom.c - ADDI EEPROM Module - * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - * Project manager: Eric Stolz - * - * ADDI-DATA GmbH - * Dieselstrasse 3 - * D-77833 Ottersweier - * Tel: +19(0)7223/9493-0 - * Fax: +49(0)7223/9493-92 - * http://www.addi-data.com - * info@addi-data.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <linux/delay.h> - -#define NVRAM_USER_DATA_START 0x100 - -#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ -#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ -#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ - -#define EE93C76_CLK_BIT (1 << 0) -#define EE93C76_CS_BIT (1 << 1) -#define EE93C76_DOUT_BIT (1 << 2) -#define EE93C76_DIN_BIT (1 << 3) -#define EE93C76_READ_CMD (0x0180 << 4) -#define EE93C76_CMD_LEN 13 - -#define EEPROM_DIGITALINPUT 0 -#define EEPROM_DIGITALOUTPUT 1 -#define EEPROM_ANALOGINPUT 2 -#define EEPROM_ANALOGOUTPUT 3 -#define EEPROM_TIMER 4 -#define EEPROM_WATCHDOG 5 -#define EEPROM_TIMER_WATCHDOG_COUNTER 10 - -static void addi_eeprom_clk_93c76(unsigned long iobase, unsigned int val) -{ - outl(val & ~EE93C76_CLK_BIT, iobase); - udelay(100); - - outl(val | EE93C76_CLK_BIT, iobase); - udelay(100); -} - -static unsigned int addi_eeprom_cmd_93c76(unsigned long iobase, - unsigned int cmd, - unsigned char len) -{ - unsigned int val = EE93C76_CS_BIT; - int i; - - /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */ - outl(val, iobase); - udelay(100); - - /* Send EEPROM command - one bit at a time */ - for (i = (len - 1); i >= 0; i--) { - if (cmd & (1 << i)) - val |= EE93C76_DOUT_BIT; - else - val &= ~EE93C76_DOUT_BIT; - - /* Write the command */ - outl(val, iobase); - udelay(100); - - addi_eeprom_clk_93c76(iobase, val); - } - return val; -} - -static unsigned short addi_eeprom_readw_93c76(unsigned long iobase, - unsigned short addr) -{ - unsigned short val = 0; - unsigned int cmd; - unsigned int tmp; - int i; - - /* Send EEPROM read command and offset to EEPROM */ - cmd = EE93C76_READ_CMD | (addr / 2); - cmd = addi_eeprom_cmd_93c76(iobase, cmd, EE93C76_CMD_LEN); - - /* Get the 16-bit value */ - for (i = 0; i < 16; i++) { - addi_eeprom_clk_93c76(iobase, cmd); - - tmp = inl(iobase); - udelay(100); - - val <<= 1; - if (tmp & EE93C76_DIN_BIT) - val |= 0x1; - } - - /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */ - outl(0, iobase); - udelay(100); - - return val; -} - -static void addi_eeprom_nvram_wait(unsigned long iobase) -{ - unsigned char val; - - do { - val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD); - } while (val & 0x80); -} - -static unsigned short addi_eeprom_readw_nvram(unsigned long iobase, - unsigned short addr) -{ - unsigned short val = 0; - unsigned char tmp; - unsigned char i; - - for (i = 0; i < 2; i++) { - /* Load the low 8 bit address */ - outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD); - addi_eeprom_nvram_wait(iobase); - outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); - addi_eeprom_nvram_wait(iobase); - - /* Load the high 8 bit address */ - outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD); - addi_eeprom_nvram_wait(iobase); - outb(((addr + i) >> 8) & 0xff, - iobase + AMCC_OP_REG_MCSR_NVDATA); - addi_eeprom_nvram_wait(iobase); - - /* Read the eeprom data byte */ - outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); - addi_eeprom_nvram_wait(iobase); - tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); - addi_eeprom_nvram_wait(iobase); - - if (i == 0) - val |= tmp; - else - val |= (tmp << 8); - } - - return val; -} - -static unsigned short addi_eeprom_readw(unsigned long iobase, - char *type, - unsigned short addr) -{ - unsigned short val = 0; - - /* Add the offset to the start of the user data */ - addr += NVRAM_USER_DATA_START; - - if (!strcmp(type, "S5920") || !strcmp(type, "S5933")) - val = addi_eeprom_readw_nvram(iobase, addr); - - if (!strcmp(type, "93C76")) - val = addi_eeprom_readw_93c76(iobase, addr); - - return val; -} - -static void addi_eeprom_read_di_info(struct comedi_device *dev, - unsigned long iobase, - unsigned short addr) -{ - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv = dev->private; - char *type = this_board->pc_EepromChip; - unsigned short tmp; - - /* Number of channels */ - tmp = addi_eeprom_readw(iobase, type, addr + 6); - devpriv->s_EeParameters.i_NbrDiChannel = tmp; - - /* Interruptible or not */ - tmp = addi_eeprom_readw(iobase, type, addr + 8); - tmp = (tmp >> 7) & 0x01; - - /* How many interruptible logic */ - tmp = addi_eeprom_readw(iobase, type, addr + 10); -} - -static void addi_eeprom_read_do_info(struct comedi_device *dev, - unsigned long iobase, - unsigned short addr) -{ - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv = dev->private; - char *type = this_board->pc_EepromChip; - unsigned short tmp; - - /* Number of channels */ - tmp = addi_eeprom_readw(iobase, type, addr + 6); - devpriv->s_EeParameters.i_NbrDoChannel = tmp; - - devpriv->s_EeParameters.i_DoMaxdata = 0xffffffff >> (32 - tmp); -} - -static void addi_eeprom_read_timer_info(struct comedi_device *dev, - unsigned long iobase, - unsigned short addr) -{ - struct addi_private *devpriv = dev->private; -#if 0 - const struct addi_board *this_board = dev->board_ptr; - char *type = this_board->pc_EepromChip; - unsigned short offset = 0; - unsigned short ntimers; - unsigned short tmp; - int i; - - /* Number of Timers */ - ntimers = addi_eeprom_readw(iobase, type, addr + 6); - - /* Read header size */ - for (i = 0; i < ntimers; i++) { - unsigned short size; - unsigned short res; - unsigned short mode; - unsigned short min_timing; - unsigned short timebase; - - size = addi_eeprom_readw(iobase, type, addr + 8 + offset + 0); - - /* Resolution / Mode */ - tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 2); - res = (tmp >> 10) & 0x3f; - mode = (tmp >> 4) & 0x3f; - - /* MinTiming / Timebase */ - tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 4); - min_timing = (tmp >> 6) & 0x3ff; - Timebase = tmp & 0x3f; - - offset += size; - } -#endif - /* Timer subdevice present */ - devpriv->s_EeParameters.i_Timer = 1; -} - -static void addi_eeprom_read_ao_info(struct comedi_device *dev, - unsigned long iobase, - unsigned short addr) -{ - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv = dev->private; - char *type = this_board->pc_EepromChip; - unsigned short tmp; - - /* No of channels for 1st hard component */ - tmp = addi_eeprom_readw(iobase, type, addr + 10); - devpriv->s_EeParameters.i_NbrAoChannel = (tmp >> 4) & 0x3ff; - - /* Resolution for 1st hard component */ - tmp = addi_eeprom_readw(iobase, type, addr + 16); - tmp = (tmp >> 8) & 0xff; - devpriv->s_EeParameters.i_AoMaxdata = 0xfff >> (16 - tmp); -} - -static void addi_eeprom_read_ai_info(struct comedi_device *dev, - unsigned long iobase, - unsigned short addr) -{ - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv = dev->private; - char *type = this_board->pc_EepromChip; - unsigned short offset; - unsigned short tmp; - - /* No of channels for 1st hard component */ - tmp = addi_eeprom_readw(iobase, type, addr + 10); - devpriv->s_EeParameters.i_NbrAiChannel = (tmp >> 4) & 0x3ff; - if (!strcmp(this_board->pc_DriverName, "apci3200")) - devpriv->s_EeParameters.i_NbrAiChannel *= 4; - - tmp = addi_eeprom_readw(iobase, type, addr + 16); - devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = tmp * 1000; - - tmp = addi_eeprom_readw(iobase, type, addr + 30); - devpriv->s_EeParameters.ui_MinDelaytimeNs = tmp * 1000; - - tmp = addi_eeprom_readw(iobase, type, addr + 20); - /* dma = (tmp >> 13) & 0x01; */ - - tmp = addi_eeprom_readw(iobase, type, addr + 72) & 0xff; - if (tmp) { /* > 0 */ - /* offset of first analog input single header */ - offset = 74 + (2 * tmp) + (10 * (1 + (tmp / 16))); - } else { /* = 0 */ - offset = 74; - } - - /* Resolution */ - tmp = addi_eeprom_readw(iobase, type, addr + offset + 2) & 0x1f; - devpriv->s_EeParameters.i_AiMaxdata = 0xffff >> (16 - tmp); -} - -static void addi_eeprom_read_info(struct comedi_device *dev, - unsigned long iobase) -{ - const struct addi_board *this_board = dev->board_ptr; - char *type = this_board->pc_EepromChip; - unsigned short size; - unsigned char nfuncs; - int i; - - size = addi_eeprom_readw(iobase, type, 8); - nfuncs = addi_eeprom_readw(iobase, type, 10) & 0xff; - - /* Read functionality details */ - for (i = 0; i < nfuncs; i++) { - unsigned short offset = i * 4; - unsigned short addr; - unsigned char func; - - func = addi_eeprom_readw(iobase, type, 12 + offset) & 0x3f; - addr = addi_eeprom_readw(iobase, type, 14 + offset); - - switch (func) { - case EEPROM_DIGITALINPUT: - addi_eeprom_read_di_info(dev, iobase, addr); - break; - - case EEPROM_DIGITALOUTPUT: - addi_eeprom_read_do_info(dev, iobase, addr); - break; - - case EEPROM_ANALOGINPUT: - addi_eeprom_read_ai_info(dev, iobase, addr); - break; - - case EEPROM_ANALOGOUTPUT: - addi_eeprom_read_ao_info(dev, iobase, addr); - break; - - case EEPROM_TIMER: - case EEPROM_WATCHDOG: - case EEPROM_TIMER_WATCHDOG_COUNTER: - addi_eeprom_read_timer_info(dev, iobase, addr); - break; - } - } -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c deleted file mode 100644 index 53bb51bd77b5..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - * - * ADDI-DATA GmbH - * Dieselstrasse 3 - * D-77833 Ottersweier - * Tel: +19(0)7223/9493-0 - * Fax: +49(0)7223/9493-92 - * http://www.addi-data.com - * info@addi-data.com - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - */ - -/* Card Specific information */ -#define APCI035_ADDRESS_RANGE 255 - -/* Timer / Watchdog Related Defines */ -#define APCI035_TCW_SYNC_ENABLEDISABLE 0 -#define APCI035_TCW_RELOAD_VALUE 4 -#define APCI035_TCW_TIMEBASE 8 -#define APCI035_TCW_PROG 12 -#define APCI035_TCW_TRIG_STATUS 16 -#define APCI035_TCW_IRQ 20 -#define APCI035_TCW_WARN_TIMEVAL 24 -#define APCI035_TCW_WARN_TIMEBASE 28 - -#define ADDIDATA_TIMER 0 -/* #define ADDIDATA_WATCHDOG 1 */ - -#define APCI035_TW1 0 -#define APCI035_TW2 32 -#define APCI035_TW3 64 -#define APCI035_TW4 96 - -#define APCI035_AI_OFFSET 0 -#define APCI035_TEMP 128 -#define APCI035_ALR_SEQ 4 -#define APCI035_START_STOP_INDEX 8 -#define APCI035_ALR_START_STOP 12 -#define APCI035_ALR_IRQ 16 -#define APCI035_EOS 20 -#define APCI035_CHAN_NO 24 -#define APCI035_CHAN_VAL 28 -#define APCI035_CONV_TIME_TIME_BASE 36 -#define APCI035_RELOAD_CONV_TIME_VAL 32 -#define APCI035_DELAY_TIME_TIME_BASE 44 -#define APCI035_RELOAD_DELAY_TIME_VAL 40 -#define ENABLE_EXT_TRIG 1 -#define ENABLE_EXT_GATE 2 -#define ENABLE_EXT_TRIG_GATE 3 - -#define ANALOG_INPUT 0 -#define TEMPERATURE 1 -#define RESISTANCE 2 - -#define ADDIDATA_GREATER_THAN_TEST 0 -#define ADDIDATA_LESS_THAN_TEST 1 - -#define APCI035_MAXVOLT 2.5 - -#define ADDIDATA_UNIPOLAR 1 -#define ADDIDATA_BIPOLAR 2 - -/* ANALOG INPUT RANGE */ -static struct comedi_lrange range_apci035_ai = { - 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -static int i_WatchdogNbr; -static int i_Temp; -static int i_Flag = 1; - -/* - * 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; - 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) - ui_Mode = 2; - else - ui_Mode = 0; - - ui_Command = 0; - outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - /* Set the reload value */ - outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); - - /* 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 */ - /* - Disable the warning */ - /* - Disable the reset */ - /* - Enable the timer mode */ - /* - Set the timer mode */ - - ui_Command = - (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; - - } 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 */ - - ui_Command = ui_Command & 0xFFF819E2UL; - - } 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 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - /* Disable the hardware trigger */ - ui_Command = ui_Command & 0xFFFFF89FUL; - if (data[4] == 1) { - /* Set the hardware trigger level */ - ui_Command = ui_Command | (data[5] << 5); - } - outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - /* Disable the hardware gate */ - ui_Command = ui_Command & 0xFFFFF87FUL; - if (data[6] == 1) { - /* Set the hardware gate level */ - ui_Command = ui_Command | (data[7] << 7); - } - outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - /* Disable the hardware output */ - ui_Command = ui_Command & 0xFFFFF9FBUL; - - /* 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] == 1) { - /* 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 = 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 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - /* Set the interrupt selection */ - ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); - - ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); - outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - - return insn->n; -} - -/* - * 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; - 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] == 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 */ - ui_Command = 0; - /* - * 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[0] == 3) { - /* stop all Watchdogs */ - ui_Command = 0; - for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) - ui_Command = 0x2UL; - else - ui_Command = 0x10UL; - - i_WatchdogNbr = i_Count; - outl(ui_Command, - devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + - 0); - } - - } - 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) - ui_Command = 0x1UL; - 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 */ - ui_Command = 0; - for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) - ui_Command = 0x4UL; - else - ui_Command = 0x20UL; - - i_WatchdogNbr = i_Count; - outl(ui_Command, - devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + - 0); - } - i_Temp = 1; - } - return insn->n; -} - -/* - * 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; /* 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) - data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); - - return insn->n; -} - -/* - * 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 */ - outl(0x300 | 0, devpriv->iobase + 128 + 0x4); - outl((data[0] << 8), devpriv->iobase + 128 + 0); - outl(0x200000UL, devpriv->iobase + 128 + 12); - - return insn->n; -} - -/* - * 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; - - /* Set the start */ - ui_CommandRegister = 0x80000; - - /* Write the command register */ - outl(ui_CommandRegister, devpriv->iobase + 128 + 8); - - /* Read the digital value of the input */ - data[0] = inl(devpriv->iobase + 128 + 28); - return insn->n; -} - -static int apci035_reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - int i_Count; - - for (i_Count = 1; i_Count <= 4; i_Count++) { - i_WatchdogNbr = i_Count; - - /* stop all timers */ - outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); - } - outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ - - return 0; -} - -static void apci035_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct addi_private *devpriv = dev->private; - 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 */ - ui_StatusRegister2 = - inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); - - /* 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 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); - } -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 0ea081e1e119..bfa9228c833f 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -158,7 +158,7 @@ static int apci1500_di_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0; int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0; int i_PatternTransitionCount = 0, i_RegValue; @@ -466,7 +466,7 @@ static int apci1500_di_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; int i_Event1InterruptStatus = 0, i_Event2InterruptStatus = 0, i_RegValue; @@ -653,7 +653,7 @@ static int apci1500_di_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; int i_DummyRead = 0; /* Software reset */ @@ -789,7 +789,7 @@ static int apci1500_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; data[1] = inw(devpriv->i_IobaseAddon + APCI1500_DIGITAL_IP); @@ -807,7 +807,7 @@ static int apci1500_do_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; devpriv->b_OutputMemoryStatus = data[0]; return insn->n; @@ -821,7 +821,7 @@ static int apci1500_do_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; static unsigned int ui_Temp; unsigned int ui_Temp1; unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ @@ -981,7 +981,7 @@ static int apci1500_timer_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; int i_TimerCounterMode, i_MasterConfiguration; devpriv->tsk_Current = current; @@ -1471,7 +1471,7 @@ static int apci1500_timer_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; int i_CommandAndStatusValue; switch (data[0]) { @@ -1731,7 +1731,7 @@ static int apci1500_timer_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; int i_CommandAndStatusValue; switch (data[0]) { @@ -1895,7 +1895,7 @@ static int apci1500_do_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; unsigned int ui_Status; int i_RegValue; int i_Constant; @@ -2011,11 +2011,11 @@ static int apci1500_do_bits(struct comedi_device *dev, return insn->n; } -static void apci1500_interrupt(int irq, void *d) +static irqreturn_t apci1500_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; unsigned int ui_InterruptStatus = 0; int i_RegValue = 0; @@ -2180,11 +2180,13 @@ static void apci1500_interrupt(int irq, void *d) "Interrupt from unknown source\n"); } + + return IRQ_HANDLED; } static int apci1500_reset(struct comedi_device *dev) { - struct addi_private *devpriv = dev->private; + struct apci1500_private *devpriv = dev->private; int i_DummyRead = 0; i_TimerCounter1Init = 0; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index 98de96953a29..fa99c8ca4f95 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -16,244 +16,189 @@ #define ADDIDATA_TIMER 0 #define ADDIDATA_COUNTER 1 #define ADDIDATA_WATCHDOG 2 -#define APCI1564_COUNTER1 0 -#define APCI1564_COUNTER2 1 -#define APCI1564_COUNTER3 2 -#define APCI1564_COUNTER4 3 - -/* - * devpriv->amcc_iobase 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_COUNTER_REG(x) (0x00 + ((x) * 0x20)) -#define APCI1564_COUNTER_RELOAD_REG(x) (0x04 + ((x) * 0x20)) -#define APCI1564_COUNTER_TIMEBASE_REG(x) (0x08 + ((x) * 0x20)) -#define APCI1564_COUNTER_CTRL_REG(x) (0x0c + ((x) * 0x20)) -#define APCI1564_COUNTER_STATUS_REG(x) (0x10 + ((x) * 0x20)) -#define APCI1564_COUNTER_IRQ_REG(x) (0x14 + ((x) * 0x20)) -#define APCI1564_COUNTER_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20)) -#define APCI1564_COUNTER_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20)) - -/* - * Configures The Timer or Counter - * - * data[0] Configure as: 0 = Timer, 1 = Counter - * 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) + +static int apci1564_timer_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci1564_private *devpriv = dev->private; - unsigned int ul_Command1 = 0; + unsigned int ctrl; devpriv->tsk_current = current; - if (data[0] == ADDIDATA_TIMER) { - /* First Stop The Timer */ - ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - /* Stop The Timer */ - outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - - devpriv->timer_select_mode = ADDIDATA_TIMER; - if (data[1] == 1) { - /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x02, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DO_IRQ_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_IRQ_REG); - outl(0x0, dev->iobase + - APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER1)); - outl(0x0, dev->iobase + - APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER2)); - outl(0x0, dev->iobase + - APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER3)); - outl(0x0, dev->iobase + - APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER4)); - } else { - /* disable Timer interrupt */ - outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - } - /* Loading Timebase */ - outl(data[2], devpriv->amcc_iobase + APCI1564_TIMER_TIMEBASE_REG); - - /* Loading the Reload value */ - outl(data[3], devpriv->amcc_iobase + APCI1564_TIMER_RELOAD_REG); - - ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - /* mode 2 */ - outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - } else if (data[0] == ADDIDATA_COUNTER) { - devpriv->timer_select_mode = ADDIDATA_COUNTER; - devpriv->mode_select_register = data[5]; - - /* First Stop The Counter */ - ul_Command1 = inl(dev->iobase + - APCI1564_COUNTER_CTRL_REG(data[5] - 1)); - ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - /* Stop The Timer */ - outl(ul_Command1, dev->iobase + - APCI1564_COUNTER_CTRL_REG(data[5] - 1)); - - /* Set the reload value */ - outl(data[3], dev->iobase + - APCI1564_COUNTER_RELOAD_REG(data[5] - 1)); - - /* Set the mode : */ - /* - Disable the hardware */ - /* - Disable the counter mode */ - /* - Disable the warning */ - /* - 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, dev->iobase + - APCI1564_COUNTER_CTRL_REG(data[5] - 1)); - - /* Enable or Disable Interrupt */ - ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); - outl(ul_Command1, dev->iobase + - APCI1564_COUNTER_CTRL_REG(data[5] - 1)); - - /* Set the Up/Down selection */ - ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18); - outl(ul_Command1, dev->iobase + - APCI1564_COUNTER_CTRL_REG(data[5] - 1)); + /* First Stop The Timer */ + ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); + ctrl &= 0xfffff9fe; + /* Stop The Timer */ + outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); + + if (data[1] == 1) { + /* Enable timer int & disable all the other int sources */ + outl(0x02, devpriv->timer + ADDI_TCW_CTRL_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + outl(0x0, dev->iobase + APCI1564_DO_IRQ_REG); + outl(0x0, dev->iobase + APCI1564_WDOG_IRQ_REG); + if (devpriv->counters) { + unsigned long iobase; + + iobase = devpriv->counters + ADDI_TCW_IRQ_REG; + outl(0x0, iobase + APCI1564_COUNTER(0)); + outl(0x0, iobase + APCI1564_COUNTER(1)); + outl(0x0, iobase + APCI1564_COUNTER(2)); + } } else { - dev_err(dev->class_dev, "Invalid subdevice.\n"); + /* disable Timer interrupt */ + outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); } + + /* Loading Timebase */ + outl(data[2], devpriv->timer + ADDI_TCW_TIMEBASE_REG); + + /* Loading the Reload value */ + outl(data[3], devpriv->timer + ADDI_TCW_RELOAD_REG); + + ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); + ctrl &= 0xfff719e2; + ctrl |= (2 << 13) | 0x10; + /* mode 2 */ + outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); + return insn->n; } -/* - * Start / Stop The Selected Timer or Counter - * - * data[0] Configure as: 0 = Timer, 1 = Counter - * 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) +static int apci1564_timer_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci1564_private *devpriv = dev->private; - unsigned int ul_Command1 = 0; + unsigned int ctrl; + + ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); + switch (data[1]) { + case 0: /* Stop The Timer */ + ctrl &= 0xfffff9fe; + break; + case 1: /* Enable the Timer */ + ctrl &= 0xfffff9ff; + ctrl |= 0x1; + break; + } + outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); - if (devpriv->timer_select_mode == ADDIDATA_TIMER) { - if (data[1] == 1) { - ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; + return insn->n; +} - /* Enable the Timer */ - outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - } else if (data[1] == 0) { - /* Stop The Timer */ +static int apci1564_timer_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + + /* Stores the status of the Timer */ + data[0] = inl(devpriv->timer + ADDI_TCW_STATUS_REG) & 0x1; + + /* Stores the Actual value of the Timer */ + data[1] = inl(devpriv->timer + ADDI_TCW_VAL_REG); - ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - } - } else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) { - ul_Command1 = - inl(dev->iobase + - APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1)); - if (data[1] == 1) { - /* Start the Counter subdevice */ - ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - } else if (data[1] == 0) { - /* Stops the Counter subdevice */ - ul_Command1 = 0; - - } else if (data[1] == 2) { - /* Clears the Counter subdevice */ - ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; - } - outl(ul_Command1, dev->iobase + - APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1)); - } else { - dev_err(dev->class_dev, "Invalid subdevice.\n"); - } return insn->n; } -/* - * Read The Selected Timer or Counter - */ -static int apci1564_timer_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci1564_counter_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci1564_private *devpriv = dev->private; - unsigned int ul_Command1 = 0; - - if (devpriv->timer_select_mode == ADDIDATA_TIMER) { - /* Stores the status of the Timer */ - data[0] = inl(devpriv->amcc_iobase + APCI1564_TIMER_STATUS_REG) & 0x1; - - /* Stores the Actual value of the Timer */ - data[1] = inl(devpriv->amcc_iobase + APCI1564_TIMER_REG); - } else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) { - /* Read the Counter Actual Value. */ - data[0] = - inl(dev->iobase + - APCI1564_COUNTER_REG(devpriv->mode_select_register - 1)); - ul_Command1 = - inl(dev->iobase + - APCI1564_COUNTER_STATUS_REG(devpriv->mode_select_register - 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 { - dev_err(dev->class_dev, "Invalid subdevice.\n"); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); + unsigned int ctrl; + + devpriv->tsk_current = current; + + /* First Stop The Counter */ + ctrl = inl(iobase + ADDI_TCW_CTRL_REG); + ctrl &= 0xfffff9fe; + /* Stop The Timer */ + outl(ctrl, iobase + ADDI_TCW_CTRL_REG); + + /* Set the reload value */ + outl(data[3], iobase + ADDI_TCW_RELOAD_REG); + + /* Set the mode : */ + /* - Disable the hardware */ + /* - Disable the counter mode */ + /* - Disable the warning */ + /* - Disable the reset */ + /* - Disable the timer mode */ + /* - Enable the counter mode */ + + ctrl &= 0xfffc19e2; + ctrl |= 0x80000 | (data[4] << 16); + outl(ctrl, iobase + ADDI_TCW_CTRL_REG); + + /* Enable or Disable Interrupt */ + ctrl &= 0xfffff9fd; + ctrl |= (data[1] << 1); + outl(ctrl, iobase + ADDI_TCW_CTRL_REG); + + /* Set the Up/Down selection */ + ctrl &= 0xfffbf9ff; + ctrl |= (data[6] << 18); + outl(ctrl, iobase + ADDI_TCW_CTRL_REG); + + return insn->n; +} + +static int apci1564_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); + unsigned int ctrl; + + ctrl = inl(iobase + ADDI_TCW_CTRL_REG); + switch (data[1]) { + case 0: /* Stops the Counter subdevice */ + ctrl = 0; + break; + case 1: /* Start the Counter subdevice */ + ctrl &= 0xfffff9ff; + ctrl |= 0x1; + break; + case 2: /* Clears the Counter subdevice */ + ctrl &= 0xfffff9ff; + ctrl |= 0x400; + break; } + outl(ctrl, iobase + ADDI_TCW_CTRL_REG); + + return insn->n; +} + +static int apci1564_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); + unsigned int status; + + /* Read the Counter Actual Value. */ + data[0] = inl(iobase + ADDI_TCW_VAL_REG); + + status = inl(iobase + ADDI_TCW_STATUS_REG); + data[1] = (status >> 1) & 1; /* software trigger status */ + data[2] = (status >> 2) & 1; /* hardware trigger status */ + data[3] = (status >> 3) & 1; /* software clear status */ + data[4] = (status >> 0) & 1; /* overflow status */ + return insn->n; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c deleted file mode 100644 index 2950815b65f4..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ /dev/null @@ -1,2050 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : APCI-3120 | Compiler : GCC | - | Module name : hwdrv_apci3120.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description :APCI3120 Module. Hardware abstraction Layer for APCI3120| - +-----------------------------------------------------------------------+ - | UPDATE'S | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -#include <linux/delay.h> - -/* - * ADDON RELATED ADDITIONS - */ -/* Constant */ -#define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00 -#define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200 -#define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L -#define APCI3120_AMWEN_ENABLE 0x02 -#define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01 -#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L -#define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L -#define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L -#define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0 -#define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0 -#define APCI3120_DISABLE_BUS_MASTER_PCI 0x0 - -/* ADD_ON ::: this needed since apci supports 16 bit interface to add on */ -#define APCI3120_ADD_ON_AGCSTS_LOW 0x3C -#define APCI3120_ADD_ON_AGCSTS_HIGH (APCI3120_ADD_ON_AGCSTS_LOW + 2) -#define APCI3120_ADD_ON_MWAR_LOW 0x24 -#define APCI3120_ADD_ON_MWAR_HIGH (APCI3120_ADD_ON_MWAR_LOW + 2) -#define APCI3120_ADD_ON_MWTC_LOW 0x058 -#define APCI3120_ADD_ON_MWTC_HIGH (APCI3120_ADD_ON_MWTC_LOW + 2) - -/* AMCC */ -#define APCI3120_AMCC_OP_MCSR 0x3C -#define APCI3120_AMCC_OP_REG_INTCSR 0x38 - -/* for transfer count enable bit */ -#define AGCSTS_TC_ENABLE 0x10000000 - -/* used for test on mixture of BIP/UNI ranges */ -#define APCI3120_BIPOLAR_RANGES 4 - -#define APCI3120_ADDRESS_RANGE 16 - -#define APCI3120_DISABLE 0 -#define APCI3120_ENABLE 1 - -#define APCI3120_START 1 -#define APCI3120_STOP 0 - -#define APCI3120_EOC_MODE 1 -#define APCI3120_EOS_MODE 2 -#define APCI3120_DMA_MODE 3 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI3120_DIGITAL_OUTPUT 0x0d -#define APCI3120_RD_STATUS 0x02 -#define APCI3120_RD_FIFO 0x00 - -/* digital output insn_write ON /OFF selection */ -#define APCI3120_SET4DIGITALOUTPUTON 1 -#define APCI3120_SET4DIGITALOUTPUTOFF 0 - -/* analog output SELECT BIT */ -#define APCI3120_ANALOG_OP_CHANNEL_1 0x0000 -#define APCI3120_ANALOG_OP_CHANNEL_2 0x4000 -#define APCI3120_ANALOG_OP_CHANNEL_3 0x8000 -#define APCI3120_ANALOG_OP_CHANNEL_4 0xc000 -#define APCI3120_ANALOG_OP_CHANNEL_5 0x0000 -#define APCI3120_ANALOG_OP_CHANNEL_6 0x4000 -#define APCI3120_ANALOG_OP_CHANNEL_7 0x8000 -#define APCI3120_ANALOG_OP_CHANNEL_8 0xc000 - -/* Enable external trigger bit in nWrAddress */ -#define APCI3120_ENABLE_EXT_TRIGGER 0x8000 - -/* ANALOG OUTPUT AND INPUT DEFINE */ -#define APCI3120_UNIPOLAR 0x80 -#define APCI3120_BIPOLAR 0x00 -#define APCI3120_ANALOG_OUTPUT_1 0x08 -#define APCI3120_ANALOG_OUTPUT_2 0x0a -#define APCI3120_1_GAIN 0x00 -#define APCI3120_2_GAIN 0x10 -#define APCI3120_5_GAIN 0x20 -#define APCI3120_10_GAIN 0x30 -#define APCI3120_SEQ_RAM_ADDRESS 0x06 -#define APCI3120_RESET_FIFO 0x0c -#define APCI3120_TIMER_0_MODE_2 0x01 -#define APCI3120_TIMER_0_MODE_4 0x2 -#define APCI3120_SELECT_TIMER_0_WORD 0x00 -#define APCI3120_ENABLE_TIMER0 0x1000 -#define APCI3120_CLEAR_PR 0xf0ff -#define APCI3120_CLEAR_PA 0xfff0 -#define APCI3120_CLEAR_PA_PR (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA) - -/* nWrMode_Select */ -#define APCI3120_ENABLE_SCAN 0x8 -#define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN) -#define APCI3120_ENABLE_EOS_INT 0x2 - -#define APCI3120_DISABLE_EOS_INT (~APCI3120_ENABLE_EOS_INT) -#define APCI3120_ENABLE_EOC_INT 0x1 -#define APCI3120_DISABLE_EOC_INT (~APCI3120_ENABLE_EOC_INT) -#define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER \ - (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) -#define APCI3120_DISABLE_ALL_INTERRUPT \ - (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) - -/* status register bits */ -#define APCI3120_EOC 0x8000 -#define APCI3120_EOS 0x2000 - -/* software trigger dummy register */ -#define APCI3120_START_CONVERSION 0x02 - -/* TIMER DEFINE */ -#define APCI3120_QUARTZ_A 70 -#define APCI3120_QUARTZ_B 50 -#define APCI3120_TIMER 1 -#define APCI3120_WATCHDOG 2 -#define APCI3120_TIMER_DISABLE 0 -#define APCI3120_TIMER_ENABLE 1 -#define APCI3120_ENABLE_TIMER2 0x4000 -#define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) -#define APCI3120_ENABLE_TIMER_INT 0x04 -#define APCI3120_DISABLE_TIMER_INT (~APCI3120_ENABLE_TIMER_INT) -#define APCI3120_WRITE_MODE_SELECT 0x0e -#define APCI3120_SELECT_TIMER_0_WORD 0x00 -#define APCI3120_SELECT_TIMER_1_WORD 0x01 -#define APCI3120_TIMER_1_MODE_2 0x4 - -/* $$ BIT FOR MODE IN nCsTimerCtr1 */ -#define APCI3120_TIMER_2_MODE_0 0x0 -#define APCI3120_TIMER_2_MODE_2 0x10 -#define APCI3120_TIMER_2_MODE_5 0x30 - -/* $$ BIT FOR MODE IN nCsTimerCtr0 */ -#define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02 -#define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03 - -#define APCI3120_TIMER_CRT0 0x0d -#define APCI3120_TIMER_CRT1 0x0c - -#define APCI3120_TIMER_VALUE 0x04 -#define APCI3120_TIMER_STATUS_REGISTER 0x0d -#define APCI3120_RD_STATUS 0x02 -#define APCI3120_WR_ADDRESS 0x00 -#define APCI3120_ENABLE_WATCHDOG 0x20 -#define APCI3120_DISABLE_WATCHDOG (~APCI3120_ENABLE_WATCHDOG) -#define APCI3120_ENABLE_TIMER_COUNTER 0x10 -#define APCI3120_DISABLE_TIMER_COUNTER (~APCI3120_ENABLE_TIMER_COUNTER) -#define APCI3120_FC_TIMER 0x1000 -#define APCI3120_ENABLE_TIMER0 0x1000 -#define APCI3120_ENABLE_TIMER1 0x2000 -#define APCI3120_ENABLE_TIMER2 0x4000 -#define APCI3120_DISABLE_TIMER0 (~APCI3120_ENABLE_TIMER0) -#define APCI3120_DISABLE_TIMER1 (~APCI3120_ENABLE_TIMER1) -#define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) - -#define APCI3120_TIMER2_SELECT_EOS 0xc0 -#define APCI3120_COUNTER 3 -#define APCI3120_DISABLE_ALL_TIMER (APCI3120_DISABLE_TIMER0 & \ - APCI3120_DISABLE_TIMER1 & \ - APCI3120_DISABLE_TIMER2) - -#define MAX_ANALOGINPUT_CHANNELS 32 - -struct str_AnalogReadInformation { - /* EOC or EOS */ - unsigned char b_Type; - /* Interrupt use or not */ - unsigned char b_InterruptFlag; - /* Selection of the conversion time */ - unsigned int ui_ConvertTiming; - /* Number of channel to read */ - unsigned char b_NbrOfChannel; - /* Number of the channel to be read */ - unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS]; - /* Gain of each channel */ - unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS]; -}; - -/* ANALOG INPUT RANGE */ -static const struct comedi_lrange range_apci3120_ai = { - 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -/* ANALOG OUTPUT RANGE */ -static const struct comedi_lrange range_apci3120_ao = { - 2, { - BIP_RANGE(10), - UNI_RANGE(10) - } -}; - - -/* FUNCTION DEFINITIONS */ -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 = dev->board_ptr; - struct addi_private *devpriv = dev->private; - unsigned int i; - - if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE)) - return -1; - - /* Check for Conversion time to be added */ - devpriv->ui_EocEosConversionTime = data[2]; - - if (data[0] == APCI3120_EOS_MODE) { - - /* Test the number of the channel */ - for (i = 0; i < data[3]; i++) { - - if (CR_CHAN(data[4 + i]) >= - this_board->i_NbrAiChannel) { - dev_err(dev->class_dev, "bad channel list\n"); - return -2; - } - } - - devpriv->b_InterruptMode = APCI3120_EOS_MODE; - - if (data[1]) - devpriv->b_EocEosInterrupt = APCI3120_ENABLE; - else - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - /* Copy channel list and Range List to devpriv */ - devpriv->ui_AiNbrofChannels = data[3]; - for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) - devpriv->ui_AiChannelList[i] = data[4 + i]; - - } else { /* EOC */ - devpriv->b_InterruptMode = APCI3120_EOC_MODE; - if (data[1]) - devpriv->b_EocEosInterrupt = APCI3120_ENABLE; - else - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - } - - return insn->n; -} - -/* - * This function will first check channel list is ok or not and then - * initialize the sequence RAM with the polarity, Gain,Channel number. - * If the last argument of function "check"is 1 then it only checks - * the channel list is ok or not. - */ -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; - unsigned int gain; - unsigned short us_TmpValue; - - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - if (!check) - dev_err(dev->class_dev, - "range/channel list is empty!\n"); - return 0; - } - /* All is ok, so we can setup channel/range list */ - if (check) - return 1; - - /* Code to set the PA and PR...Here it set PA to 0 */ - devpriv->us_OutputRegister = - devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR; - devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - - for (i = 0; i < n_chan; i++) { - /* store range list to card */ - us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number */ - - if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) - us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */ - else - us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar */ - - gain = CR_RANGE(chanlist[i]); /* get gain number */ - us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */ - us_TmpValue |= i << 8; /* To select the RAM LOCATION */ - outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); - } - return 1; /* we can serve this with scan logic */ -} - -/* - * Reads analog input in synchronous mode EOC and EOS is selected - * as per configured if no conversion time is set uses default - * conversion time 10 microsec. - */ -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 = dev->board_ptr; - struct addi_private *devpriv = dev->private; - unsigned short us_ConvertTiming, us_TmpValue, i; - unsigned char b_Tmp; - - /* fix conversion time to 10 us */ - if (!devpriv->ui_EocEosConversionTime) - us_ConvertTiming = 10; - else - us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */ - - /* Clear software registers */ - devpriv->b_TimerSelectMode = 0; - devpriv->b_ModeSelectRegister = 0; - devpriv->us_OutputRegister = 0; - - if (insn->unused[0] == 222) { /* second insn read */ - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ui_AiReadData[i]; - } else { - devpriv->tsk_Current = current; /* Save the current process task structure */ - - /* - * Testing if board have the new Quartz and calculate the time value - * to set in the timer - */ - us_TmpValue = - (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); - - /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */ - if ((us_TmpValue & 0x00B0) == 0x00B0 - || !strcmp(this_board->pc_DriverName, "apci3001")) { - us_ConvertTiming = (us_ConvertTiming * 2) - 2; - } else { - us_ConvertTiming = - ((us_ConvertTiming * 12926) / 10000) - 1; - } - - us_TmpValue = (unsigned short) devpriv->b_InterruptMode; - - switch (us_TmpValue) { - - case APCI3120_EOC_MODE: - - /* - * Testing the interrupt flag and set the EOC bit Clears the FIFO - */ - inw(devpriv->iobase + APCI3120_RESET_FIFO); - - /* Initialize the sequence array */ - if (!apci3120_setup_chan_list(dev, s, 1, - &insn->chanspec, 0)) - return -EINVAL; - - /* Initialize Timer 0 mode 4 */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0xFC) | - APCI3120_TIMER_0_MODE_4; - outb(devpriv->b_TimerSelectMode, - devpriv->iobase + APCI3120_TIMER_CRT1); - - /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_SCAN; - - if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { - - /* Disables the EOS,DMA and enables the EOC interrupt */ - devpriv->b_ModeSelectRegister = - (devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_EOS_INT) | - APCI3120_ENABLE_EOC_INT; - inw(devpriv->iobase); - - } else { - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER; - } - - outb(devpriv->b_ModeSelectRegister, - devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - - /* Sets gate 0 */ - devpriv->us_OutputRegister = - (devpriv-> - us_OutputRegister & APCI3120_CLEAR_PA_PR) | - APCI3120_ENABLE_TIMER0; - outw(devpriv->us_OutputRegister, - devpriv->iobase + APCI3120_WR_ADDRESS); - - /* Select Timer 0 */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_0_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - - /* Set the conversion time */ - outw(us_ConvertTiming, - devpriv->iobase + APCI3120_TIMER_VALUE); - - us_TmpValue = - (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); - - if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) { - - do { - /* Waiting for the end of conversion */ - us_TmpValue = - inw(devpriv->iobase + - APCI3120_RD_STATUS); - } while ((us_TmpValue & APCI3120_EOC) == - APCI3120_EOC); - - /* Read the result in FIFO and put it in insn data pointer */ - us_TmpValue = inw(devpriv->iobase + 0); - *data = us_TmpValue; - - inw(devpriv->iobase + APCI3120_RESET_FIFO); - } - - break; - - case APCI3120_EOS_MODE: - - inw(devpriv->iobase); - /* Clears the FIFO */ - inw(devpriv->iobase + APCI3120_RESET_FIFO); - /* clear PA PR and disable timer 0 */ - - devpriv->us_OutputRegister = - (devpriv-> - us_OutputRegister & APCI3120_CLEAR_PA_PR) | - APCI3120_DISABLE_TIMER0; - - outw(devpriv->us_OutputRegister, - devpriv->iobase + APCI3120_WR_ADDRESS); - - if (!apci3120_setup_chan_list(dev, s, - devpriv->ui_AiNbrofChannels, - devpriv->ui_AiChannelList, 0)) - return -EINVAL; - - /* Initialize Timer 0 mode 2 */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0xFC) | - APCI3120_TIMER_0_MODE_2; - outb(devpriv->b_TimerSelectMode, - devpriv->iobase + APCI3120_TIMER_CRT1); - - /* Select Timer 0 */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_0_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - - /* Set the conversion time */ - outw(us_ConvertTiming, - devpriv->iobase + APCI3120_TIMER_VALUE); - - /* Set the scan bit */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister | APCI3120_ENABLE_SCAN; - outb(devpriv->b_ModeSelectRegister, - devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - - /* If Interrupt function is loaded */ - if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { - /* Disables the EOC,DMA and enables the EOS interrupt */ - devpriv->b_ModeSelectRegister = - (devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_EOC_INT) | - APCI3120_ENABLE_EOS_INT; - inw(devpriv->iobase); - - } else - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER; - - outb(devpriv->b_ModeSelectRegister, - devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - - inw(devpriv->iobase + APCI3120_RD_STATUS); - - /* Sets gate 0 */ - devpriv->us_OutputRegister = - devpriv-> - us_OutputRegister | APCI3120_ENABLE_TIMER0; - outw(devpriv->us_OutputRegister, - devpriv->iobase + APCI3120_WR_ADDRESS); - - /* Start conversion */ - outw(0, devpriv->iobase + APCI3120_START_CONVERSION); - - /* Waiting of end of conversion if interrupt is not installed */ - if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) { - /* Waiting the end of conversion */ - do { - us_TmpValue = - inw(devpriv->iobase + - APCI3120_RD_STATUS); - } while ((us_TmpValue & APCI3120_EOS) != - APCI3120_EOS); - - for (i = 0; i < devpriv->ui_AiNbrofChannels; - i++) { - /* Read the result in FIFO and write them in shared memory */ - us_TmpValue = inw(devpriv->iobase); - data[i] = (unsigned int) us_TmpValue; - } - - devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults */ - } - break; - - default: - dev_err(dev->class_dev, "inputs wrong\n"); - - } - devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable */ - } - - return insn->n; - -} - -static int apci3120_reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - unsigned int i; - unsigned short us_TmpValue; - - 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 */ - - /* variables used in timer subdevice */ - devpriv->b_Timer2Mode = 0; - devpriv->b_Timer2Interrupt = 0; - devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */ - - /* Disable all interrupts, watchdog for the anolog output */ - devpriv->b_ModeSelectRegister = 0; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - - /* Disables all counters, ext trigger and clears PA, PR */ - devpriv->us_OutputRegister = 0; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - - /* - * Code to set the all anolog o/p channel to 0v 8191 is decimal - * value for zero(0 v)volt in bipolar mode(default) - */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */ - - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */ - - udelay(10); - - inw(dev->iobase + 0); /* make a dummy read */ - inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */ - inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */ - - /* code to reset the RAM sequence */ - for (i = 0; i < 16; i++) { - us_TmpValue = i << 8; /* select the location */ - outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); - } - return 0; -} - -static int apci3120_exttrig_enable(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - - devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - return 0; -} - -static int apci3120_exttrig_disable(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - - devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - return 0; -} - -static int apci3120_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct addi_private *devpriv = dev->private; - - /* Disable A2P Fifo write and AMWEN signal */ - outw(0, devpriv->i_IobaseAddon + 4); - - /* Disable Bus Master ADD ON */ - outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); - outw(0, devpriv->i_IobaseAddon + 2); - outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); - outw(0, devpriv->i_IobaseAddon + 2); - - /* Disable BUS Master PCI */ - outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - - /* Disable ext trigger */ - apci3120_exttrig_disable(dev); - - devpriv->us_OutputRegister = 0; - /* stop counters */ - outw(devpriv-> - us_OutputRegister & APCI3120_DISABLE_TIMER0 & - APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS); - - outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS); - - /* DISABLE_ALL_INTERRUPT */ - outb(APCI3120_DISABLE_ALL_INTERRUPT, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - /* Flush FIFO */ - inb(dev->iobase + APCI3120_RESET_FIFO); - inw(dev->iobase + APCI3120_RD_STATUS); - devpriv->ui_AiActualScan = 0; - s->async->cur_chan = 0; - devpriv->ui_DmaActualBuffer = 0; - - devpriv->ai_running = 0; - devpriv->b_InterruptMode = APCI3120_EOC_MODE; - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - apci3120_reset(dev); - return 0; -} - -static int apci3120_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->start_src); - err |= cfc_check_trigger_is_unique(cmd->scan_begin_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); - - if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */ - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000); - - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->convert_arg) - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - 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_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 (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) - return 4; - - return 0; -} - -/* - * This is used for analog input cyclic acquisition. - * Performs the command operations. - * If DMA is configured does DMA initialization otherwise does the - * acquisition with EOS interrupt. - */ -static int apci3120_cyclic_ai(int mode, - struct comedi_device *dev, - struct comedi_subdevice *s) -{ - const struct addi_board *this_board = dev->board_ptr; - 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; - - /* Resets the FIFO */ - inb(dev->iobase + APCI3120_RESET_FIFO); - - devpriv->ai_running = 1; - - /* clear software registers */ - devpriv->b_TimerSelectMode = 0; - devpriv->us_OutputRegister = 0; - devpriv->b_ModeSelectRegister = 0; - - /* Clear Timer Write TC int */ - outl(APCI3120_CLEAR_WRITE_TC_INT, - devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR); - - /* Disables All Timer */ - /* Sets PR and PA to 0 */ - devpriv->us_OutputRegister = devpriv->us_OutputRegister & - APCI3120_DISABLE_TIMER0 & - APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR; - - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - - /* Resets the FIFO */ - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - inb(devpriv->iobase + APCI3120_RESET_FIFO); - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - - devpriv->ui_AiActualScan = 0; - s->async->cur_chan = 0; - devpriv->ui_DmaActualBuffer = 0; - - /* value for timer2 minus -2 has to be done */ - ui_TimerValue2 = cmd->stop_arg - 2; - ui_ConvertTiming = cmd->convert_arg; - - if (mode == 2) - ui_DelayTiming = cmd->scan_begin_arg; - - /* Initializes the sequence array */ - 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); - - /* EL241003 Begin: add this section to replace floats calculation by integer calculations */ - /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */ - if ((us_TmpValue & 0x00B0) == 0x00B0 - || !strcmp(this_board->pc_DriverName, "apci3001")) { - ui_TimerValue0 = ui_ConvertTiming * 2 - 2000; - ui_TimerValue0 = ui_TimerValue0 / 1000; - - if (mode == 2) { - ui_DelayTiming = ui_DelayTiming / 1000; - ui_TimerValue1 = ui_DelayTiming * 2 - 200; - ui_TimerValue1 = ui_TimerValue1 / 100; - } - } else { - ui_ConvertTiming = ui_ConvertTiming / 1000; - ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000; - ui_TimerValue0 = ui_TimerValue0 / 10000; - - if (mode == 2) { - ui_DelayTiming = ui_DelayTiming / 1000; - ui_TimerValue1 = ui_DelayTiming * 12926 - 1; - ui_TimerValue1 = ui_TimerValue1 / 1000000; - } - } - /* EL241003 End */ - - if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) - apci3120_exttrig_enable(dev); /* activate EXT trigger */ - switch (mode) { - case 1: - /* init timer0 in mode 2 */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2; - outb(devpriv->b_TimerSelectMode, - dev->iobase + APCI3120_TIMER_CRT1); - - /* Select Timer 0 */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_0_WORD; - outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - /* Set the conversion time */ - outw(((unsigned short) ui_TimerValue0), - dev->iobase + APCI3120_TIMER_VALUE); - break; - - case 2: - /* init timer1 in mode 2 */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2; - outb(devpriv->b_TimerSelectMode, - dev->iobase + APCI3120_TIMER_CRT1); - - /* Select Timer 1 */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_1_WORD; - outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - /* Set the conversion time */ - outw(((unsigned short) ui_TimerValue1), - dev->iobase + APCI3120_TIMER_VALUE); - - /* init timer0 in mode 2 */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2; - outb(devpriv->b_TimerSelectMode, - dev->iobase + APCI3120_TIMER_CRT1); - - /* Select Timer 0 */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_0_WORD; - outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - - /* Set the conversion time */ - outw(((unsigned short) ui_TimerValue0), - dev->iobase + APCI3120_TIMER_VALUE); - break; - - } - /* common for all modes */ - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & - APCI3120_DISABLE_SCAN; - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - - /* If DMA is disabled */ - if (devpriv->us_UseDma == APCI3120_DISABLE) { - /* disable EOC and enable EOS */ - devpriv->b_InterruptMode = APCI3120_EOS_MODE; - devpriv->b_EocEosInterrupt = APCI3120_ENABLE; - - devpriv->b_ModeSelectRegister = - (devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) | - APCI3120_ENABLE_EOS_INT; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - - 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) - */ - devpriv->us_OutputRegister = - devpriv-> - us_OutputRegister & APCI3120_DISABLE_TIMER2; - outw(devpriv->us_OutputRegister, - dev->iobase + APCI3120_WR_ADDRESS); - - /* DISABLE TIMER intERRUPT */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_TIMER_INT & 0xEF; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - - /* (1) Init timer 2 in mode 0 and write timer value */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0x0F) | - APCI3120_TIMER_2_MODE_0; - outb(devpriv->b_TimerSelectMode, - dev->iobase + APCI3120_TIMER_CRT1); - - /* Writing LOW unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_LOW_WORD; - outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - outw(ui_TimerValue2 & 0xffff, - dev->iobase + APCI3120_TIMER_VALUE); - - /* Writing HIGH unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_HIGH_WORD; - outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - outw((ui_TimerValue2 >> 16) & 0xffff, - dev->iobase + APCI3120_TIMER_VALUE); - - /* (2) Reset FC_TIMER BIT Clearing timer status register */ - inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - /* enable timer counter and disable watch dog */ - devpriv->b_ModeSelectRegister = - (devpriv-> - b_ModeSelectRegister | - APCI3120_ENABLE_TIMER_COUNTER) & - APCI3120_DISABLE_WATCHDOG; - /* select EOS clock input for timer 2 */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister | - APCI3120_TIMER2_SELECT_EOS; - /* Enable timer2 interrupt */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister | - APCI3120_ENABLE_TIMER_INT; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - devpriv->b_Timer2Mode = APCI3120_COUNTER; - devpriv->b_Timer2Interrupt = APCI3120_ENABLE; - } - } else { - /* If DMA Enabled */ - unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short); - - devpriv->b_InterruptMode = APCI3120_DMA_MODE; - - /* Disables the EOC, EOS interrupt */ - devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & - APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT; - - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - - dmalen0 = devpriv->ui_DmaBufferSize[0]; - dmalen1 = devpriv->ui_DmaBufferSize[1]; - - 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 (cmd->flags & CMDF_WAKE_EOS) { - /* don't we want wake up every scan? */ - if (dmalen0 > scan_bytes) { - dmalen0 = scan_bytes; - if (cmd->scan_end_arg & 1) - dmalen0 += 2; - } - 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 > 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; - - /* Initialize DMA */ - - /* - * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS - * register 1 - */ - ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; - outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS); - - /* changed since 16 bit interface for add on */ - /* ENABLE BUS MASTER */ - outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, - devpriv->i_IobaseAddon + 2); - - outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, - devpriv->i_IobaseAddon + 2); - - /* - * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux - * driver - */ - outw(0x1000, devpriv->i_IobaseAddon + 2); - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - - /* 2 No change */ - /* A2P FIFO MANAGEMENT */ - /* A2P fifo reset & transfer control enable */ - outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc + - APCI3120_AMCC_OP_MCSR); - - /* - * 3 - * beginning address of dma buf The 32 bit address of dma buffer - * is converted into two 16 bit addresses Can done by using _attach - * and put into into an array array used may be for differnet pages - */ - - /* DMA Start Address Low */ - outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); - outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF), - devpriv->i_IobaseAddon + 2); - - /* DMA Start Address High */ - outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); - outw((devpriv->ul_DmaBufferHw[0] / 65536), - devpriv->i_IobaseAddon + 2); - - /* - * 4 - * amount of bytes to be transferred set transfer count used ADDON - * MWTC register commented testing - */ - - /* Nbr of acquisition LOW */ - outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); - outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF), - devpriv->i_IobaseAddon + 2); - - /* Nbr of acquisition HIGH */ - outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); - outw((devpriv->ui_DmaBufferUsesize[0] / 65536), - devpriv->i_IobaseAddon + 2); - - /* - * 5 - * To configure A2P FIFO testing outl( - * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); - */ - - /* A2P FIFO RESET */ - /* - * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux - * driver - */ - outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - - /* - * 6 - * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE | - * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 - */ - - /* - * 7 - * initialise end of dma interrupt AINT_WRITE_COMPL = - * ENABLE_WRITE_TC_INT(ADDI) - */ - /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */ - outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | - APCI3120_ENABLE_WRITE_TC_INT), - devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); - - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */ - outw(3, devpriv->i_IobaseAddon + 4); - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - - /* A2P FIFO RESET */ - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - outl(0x04000000UL, - devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR); - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - } - - 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; - outw(devpriv->us_OutputRegister, - dev->iobase + APCI3120_WR_ADDRESS); - } - - switch (mode) { - case 1: - /* set gate 0 to start conversion */ - devpriv->us_OutputRegister = - devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0; - outw(devpriv->us_OutputRegister, - dev->iobase + APCI3120_WR_ADDRESS); - break; - case 2: - /* set gate 0 and gate 1 */ - devpriv->us_OutputRegister = - devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1; - devpriv->us_OutputRegister = - devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0; - outw(devpriv->us_OutputRegister, - dev->iobase + APCI3120_WR_ADDRESS); - break; - - } - - return 0; - -} - -/* - * Does asynchronous acquisition. - * Determines the mode 1 or 2. - */ -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_AiNbrofChannels = cmd->chanlist_len; - - if (cmd->start_src == TRIG_EXT) - devpriv->b_ExttrigEnable = APCI3120_ENABLE; - else - devpriv->b_ExttrigEnable = APCI3120_DISABLE; - - if (cmd->scan_begin_src == TRIG_FOLLOW) - return apci3120_cyclic_ai(1, dev, s); - /* TRIG_TIMER */ - return apci3120_cyclic_ai(2, dev, s); -} - -/* - * This function copies the data from DMA buffer to the Comedi buffer. - */ -static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned short *dma_buffer, - unsigned int num_samples) -{ - struct addi_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - - devpriv->ui_AiActualScan += - (s->async->cur_chan + num_samples) / cmd->scan_end_arg; - s->async->cur_chan += num_samples; - s->async->cur_chan %= cmd->scan_end_arg; - - cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); -} - -/* - * This is a handler for the DMA interrupt. - * This function copies the data to Comedi Buffer. - * For continuous DMA it reinitializes the DMA operation. - * For single mode DMA it stop the acquisition. - */ -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; - - samplesinbuf = - devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] - - inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC); - - if (samplesinbuf < - devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) { - dev_err(dev->class_dev, "Interrupted DMA transfer!\n"); - } - if (samplesinbuf & 1) { - dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n"); - apci3120_cancel(dev, s); - return; - } - samplesinbuf = samplesinbuf >> 1; /* number of received samples */ - if (devpriv->b_DmaDoubleBuffer) { - /* switch DMA buffers if is used double buffering */ - next_dma_buf = 1 - devpriv->ui_DmaActualBuffer; - - ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; - outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - - /* changed since 16 bit interface for add on */ - outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, - devpriv->i_IobaseAddon + 2); - outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */ - - var = devpriv->ul_DmaBufferHw[next_dma_buf]; - low_word = var & 0xffff; - var = devpriv->ul_DmaBufferHw[next_dma_buf]; - high_word = var / 65536; - - /* DMA Start Address Low */ - outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - - /* DMA Start Address High */ - outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); - outw(high_word, devpriv->i_IobaseAddon + 2); - - var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; - low_word = var & 0xffff; - var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; - high_word = var / 65536; - - /* Nbr of acquisition LOW */ - outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - - /* Nbr of acquisition HIGH */ - outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); - outw(high_word, devpriv->i_IobaseAddon + 2); - - /* - * To configure A2P FIFO - * ENABLE A2P FIFO WRITE AND ENABLE AMWEN - * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 - */ - outw(3, devpriv->i_IobaseAddon + 4); - /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ - outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | - APCI3120_ENABLE_WRITE_TC_INT), - devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); - - } - if (samplesinbuf) { - v_APCI3120_InterruptDmaMoveBlock16bit(dev, s, - devpriv->ul_DmaBufferVirtual[devpriv-> - ui_DmaActualBuffer], samplesinbuf); - - if (!(cmd->flags & CMDF_WAKE_EOS)) { - s->async->events |= COMEDI_CB_EOS; - comedi_event(dev, s); - } - } - if (cmd->stop_src == TRIG_COUNT) - if (devpriv->ui_AiActualScan >= cmd->stop_arg) { - /* all data sampled */ - apci3120_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } - - if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */ - devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer; - } else { - /* - * restart DMA if is not used double buffering - * ADDED REINITIALISE THE DMA - */ - ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; - outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - - /* changed since 16 bit interface for add on */ - outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, - devpriv->i_IobaseAddon + 2); - outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); - /* - * A2P FIFO MANAGEMENT - * A2P fifo reset & transfer control enable - */ - outl(APCI3120_A2P_FIFO_MANAGEMENT, - devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - - var = devpriv->ul_DmaBufferHw[0]; - low_word = var & 0xffff; - var = devpriv->ul_DmaBufferHw[0]; - high_word = var / 65536; - outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); - outw(high_word, devpriv->i_IobaseAddon + 2); - - var = devpriv->ui_DmaBufferUsesize[0]; - low_word = var & 0xffff; /* changed */ - var = devpriv->ui_DmaBufferUsesize[0]; - high_word = var / 65536; - outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); - outw(high_word, devpriv->i_IobaseAddon + 2); - - /* - * To configure A2P FIFO - * ENABLE A2P FIFO WRITE AND ENABLE AMWEN - * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 - */ - outw(3, devpriv->i_IobaseAddon + 4); - /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ - outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | - APCI3120_ENABLE_WRITE_TC_INT), - devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); - } -} - -/* - * This function handles EOS interrupt. - * This function copies the acquired data(from FIFO) to Comedi buffer. - */ -static int apci3120_interrupt_handle_eos(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - int n_chan, i; - int err = 1; - - n_chan = devpriv->ui_AiNbrofChannels; - - for (i = 0; i < n_chan; i++) - err &= comedi_buf_put(s, inw(dev->iobase + 0)); - - s->async->events |= COMEDI_CB_EOS; - - if (err == 0) - s->async->events |= COMEDI_CB_OVERFLOW; - - comedi_event(dev, s); - - return 0; -} - -static void apci3120_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct addi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned short int_daq; - unsigned int int_amcc, ui_Check, i; - unsigned short us_TmpValue; - unsigned char b_DummyRead; - - ui_Check = 1; - - int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */ - int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */ - - if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) { - dev_err(dev->class_dev, "IRQ from unknown source\n"); - return; - } - - outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */ - - int_daq = (int_daq >> 12) & 0xF; - - if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { - /* Disable ext trigger */ - apci3120_exttrig_disable(dev); - devpriv->b_ExttrigEnable = APCI3120_DISABLE; - } - /* clear the timer 2 interrupt */ - inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER); - - if (int_amcc & MASTER_ABORT_INT) - dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n"); - if (int_amcc & TARGET_ABORT_INT) - dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n"); - - /* Ckeck if EOC interrupt */ - if (((int_daq & 0x8) == 0) - && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) { - if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { - - /* Read the AI Value */ - devpriv->ui_AiReadData[0] = - (unsigned int) inw(devpriv->iobase + 0); - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } else { - /* Disable EOC Interrupt */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT; - outb(devpriv->b_ModeSelectRegister, - devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - - } - } - - /* Check If EOS interrupt */ - if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) { - - if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */ - - if (devpriv->ai_running) { - ui_Check = 0; - apci3120_interrupt_handle_eos(dev); - devpriv->ui_AiActualScan++; - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister | - APCI3120_ENABLE_EOS_INT; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + - APCI3120_WRITE_MODE_SELECT); - } else { - ui_Check = 0; - for (i = 0; i < devpriv->ui_AiNbrofChannels; - i++) { - us_TmpValue = inw(devpriv->iobase + 0); - devpriv->ui_AiReadData[i] = - (unsigned int) us_TmpValue; - } - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - devpriv->b_InterruptMode = APCI3120_EOC_MODE; - - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - - } - - } else { - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */ - devpriv->b_InterruptMode = APCI3120_EOC_MODE; - } - - } - /* Timer2 interrupt */ - if (int_daq & 0x1) { - - switch (devpriv->b_Timer2Mode) { - case APCI3120_COUNTER: - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - - /* stop timer 2 */ - devpriv->us_OutputRegister = - devpriv-> - us_OutputRegister & APCI3120_DISABLE_ALL_TIMER; - outw(devpriv->us_OutputRegister, - dev->iobase + APCI3120_WR_ADDRESS); - - /* stop timer 0 and timer 1 */ - apci3120_cancel(dev, s); - - /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - - break; - - case APCI3120_TIMER: - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - break; - - case APCI3120_WATCHDOG: - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - break; - - default: - - /* disable Timer Interrupt */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_TIMER_INT; - - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); - - } - - b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - - } - - if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) { - if (devpriv->ai_running) { - - /* Clear Timer Write TC int */ - outl(APCI3120_CLEAR_WRITE_TC_INT, - devpriv->i_IobaseAmcc + - APCI3120_AMCC_OP_REG_INTCSR); - - /* Clears the timer status register */ - inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - /* do some data transfer */ - apci3120_interrupt_dma(irq, d); - } else { - /* Stops the Timer */ - outw(devpriv-> - us_OutputRegister & APCI3120_DISABLE_TIMER0 & - APCI3120_DISABLE_TIMER1, - dev->iobase + APCI3120_WR_ADDRESS); - } - - } -} - -/* - * Configure Timer 2 - * - * data[0] = TIMER configure as timer - * = WATCHDOG configure as watchdog - * data[1] = Timer constant - * data[2] = Timer2 interrupt (1)enable or(0) disable - */ -static int apci3120_config_insn_timer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv = dev->private; - unsigned int ui_Timervalue2; - unsigned short us_TmpValue; - unsigned char b_Tmp; - - if (!data[1]) - dev_err(dev->class_dev, "No timer constant!\n"); - - devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */ - - ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */ - - us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); - - /* - * EL250804: Testing if board APCI3120 have the new Quartz or if it - * is an APCI3001 and calculate the time value to set in the timer - */ - if ((us_TmpValue & 0x00B0) == 0x00B0 - || !strcmp(this_board->pc_DriverName, "apci3001")) { - /* Calculate the time value to set in the timer */ - ui_Timervalue2 = ui_Timervalue2 / 50; - } else { - /* Calculate the time value to set in the timer */ - ui_Timervalue2 = ui_Timervalue2 / 70; - } - - /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */ - devpriv->us_OutputRegister = - devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2; - outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - - /* Disable TIMER Interrupt */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF; - - /* Disable Eoc and Eos Interrupts */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT & - APCI3120_DISABLE_EOS_INT; - outb(devpriv->b_ModeSelectRegister, - devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - if (data[0] == APCI3120_TIMER) { /* initialize timer */ - /* Set the Timer 2 in mode 2(Timer) */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2; - outb(devpriv->b_TimerSelectMode, - devpriv->iobase + APCI3120_TIMER_CRT1); - - /* - * Configure the timer 2 for writing the LOW unsigned short of timer - * is Delay value You must make a b_tmp variable with - * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 - * you can set the digital output and configure the timer 2,and if - * you don't make this, digital output are erase (Set to 0) - */ - - /* Writing LOW unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_LOW_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - outw(ui_Timervalue2 & 0xffff, - devpriv->iobase + APCI3120_TIMER_VALUE); - - /* Writing HIGH unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_HIGH_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - outw((ui_Timervalue2 >> 16) & 0xffff, - devpriv->iobase + APCI3120_TIMER_VALUE); - /* timer2 in Timer mode enabled */ - devpriv->b_Timer2Mode = APCI3120_TIMER; - - } else { /* Initialize Watch dog */ - - /* Set the Timer 2 in mode 5(Watchdog) */ - devpriv->b_TimerSelectMode = - (devpriv-> - b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5; - outb(devpriv->b_TimerSelectMode, - devpriv->iobase + APCI3120_TIMER_CRT1); - - /* - * Configure the timer 2 for writing the LOW unsigned short of timer - * is Delay value You must make a b_tmp variable with - * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 - * you can set the digital output and configure the timer 2,and if - * you don't make this, digital output are erase (Set to 0) - */ - - /* Writing LOW unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_LOW_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - outw(ui_Timervalue2 & 0xffff, - devpriv->iobase + APCI3120_TIMER_VALUE); - - /* Writing HIGH unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_HIGH_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - - outw((ui_Timervalue2 >> 16) & 0xffff, - devpriv->iobase + APCI3120_TIMER_VALUE); - /* watchdog enabled */ - devpriv->b_Timer2Mode = APCI3120_WATCHDOG; - - } - - return insn->n; - -} - -/* - * To start and stop the timer - * - * data[0] = 1 (start) - * = 0 (stop) - * = 2 (write new value) - * data[1] = new value - * - * devpriv->b_Timer2Mode = 0 DISABLE - * = 1 Timer - * = 2 Watch dog - */ -static int apci3120_write_insn_timer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct addi_board *this_board = dev->board_ptr; - struct addi_private *devpriv = dev->private; - unsigned int ui_Timervalue2 = 0; - unsigned short us_TmpValue; - unsigned char b_Tmp; - - if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) - && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { - dev_err(dev->class_dev, "timer2 not configured\n"); - return -EINVAL; - } - - if (data[0] == 2) { /* write new value */ - if (devpriv->b_Timer2Mode != APCI3120_TIMER) { - dev_err(dev->class_dev, - "timer2 not configured in TIMER MODE\n"); - return -EINVAL; - } - - if (data[1]) - ui_Timervalue2 = data[1]; - else - ui_Timervalue2 = 0; - } - - switch (data[0]) { - case APCI3120_START: - - /* Reset FC_TIMER BIT */ - inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); - if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */ - /* Enable Timer */ - devpriv->b_ModeSelectRegister = - devpriv->b_ModeSelectRegister & 0x0B; - } else { /* start watch dog */ - /* Enable WatchDog */ - devpriv->b_ModeSelectRegister = - (devpriv-> - b_ModeSelectRegister & 0x0B) | - APCI3120_ENABLE_WATCHDOG; - } - - /* enable disable interrupt */ - if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) { - - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister | - APCI3120_ENABLE_TIMER_INT; - /* save the task structure to pass info to user */ - devpriv->tsk_Current = current; - } else { - - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_TIMER_INT; - } - outb(devpriv->b_ModeSelectRegister, - devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - - if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */ - /* For Timer mode is Gate2 must be activated timer started */ - devpriv->us_OutputRegister = - devpriv-> - us_OutputRegister | APCI3120_ENABLE_TIMER2; - outw(devpriv->us_OutputRegister, - devpriv->iobase + APCI3120_WR_ADDRESS); - } - - break; - - case APCI3120_STOP: - if (devpriv->b_Timer2Mode == APCI3120_TIMER) { - /* Disable timer */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_TIMER_COUNTER; - } else { - /* Disable WatchDog */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & - APCI3120_DISABLE_WATCHDOG; - } - /* Disable timer interrupt */ - devpriv->b_ModeSelectRegister = - devpriv-> - b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT; - - /* Write above states to register */ - outb(devpriv->b_ModeSelectRegister, - devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - - /* Reset Gate 2 */ - devpriv->us_OutputRegister = - devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT; - outw(devpriv->us_OutputRegister, - devpriv->iobase + APCI3120_WR_ADDRESS); - - /* Reset FC_TIMER BIT */ - inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); - - break; - - case 2: /* write new value to Timer */ - if (devpriv->b_Timer2Mode != APCI3120_TIMER) { - dev_err(dev->class_dev, - "timer2 not configured in TIMER MODE\n"); - return -EINVAL; - } - us_TmpValue = - (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); - - /* - * EL250804: Testing if board APCI3120 have the new Quartz or if it - * is an APCI3001 and calculate the time value to set in the timer - */ - if ((us_TmpValue & 0x00B0) == 0x00B0 - || !strcmp(this_board->pc_DriverName, "apci3001")) { - /* Calculate the time value to set in the timer */ - ui_Timervalue2 = ui_Timervalue2 / 50; - } else { - /* Calculate the time value to set in the timer */ - ui_Timervalue2 = ui_Timervalue2 / 70; - } - /* Writing LOW unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_LOW_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - - outw(ui_Timervalue2 & 0xffff, - devpriv->iobase + APCI3120_TIMER_VALUE); - - /* Writing HIGH unsigned short */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_HIGH_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - - outw((ui_Timervalue2 >> 16) & 0xffff, - devpriv->iobase + APCI3120_TIMER_VALUE); - - break; - default: - return -EINVAL; /* Not a valid input */ - } - - return insn->n; -} - -/* - * Read the Timer value - * - * for Timer: data[0]= Timer constant - * - * for watchdog: data[0] = 0 (still running) - * = 1 (run down) - */ -static int apci3120_read_insn_timer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned char b_Tmp; - unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue; - - if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) - && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { - dev_err(dev->class_dev, "timer2 not configured\n"); - } - if (devpriv->b_Timer2Mode == APCI3120_TIMER) { - - /* Read the LOW unsigned short of Timer 2 register */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_LOW_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - - us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE); - - /* Read the HIGH unsigned short of Timer 2 register */ - b_Tmp = ((devpriv-> - b_DigitalOutputRegister) & 0xF0) | - APCI3120_SELECT_TIMER_2_HIGH_WORD; - outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - - us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE); - - /* combining both words */ - data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16)); - - } else { /* Read watch dog status */ - - us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS); - us_StatusValue = - ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1; - if (us_StatusValue == 1) { - /* RESET FC_TIMER BIT */ - inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); - } - data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */ - } - return insn->n; -} - -static int apci3120_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int val; - - /* the input channels are bits 11:8 of the status reg */ - val = inw(devpriv->iobase + APCI3120_RD_STATUS); - data[1] = (val >> 8) & 0xf; - - return insn->n; -} - -static int apci3120_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - - if (comedi_dio_update_state(s, data)) { - /* The do channels are bits 7:4 of the do register */ - devpriv->b_DigitalOutputRegister = s->state << 4; - - outb(devpriv->b_DigitalOutputRegister, - devpriv->iobase + APCI3120_DIGITAL_OUTPUT); - } - - data[1] = s->state; - - return insn->n; -} - -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; - unsigned short us_TmpValue; - - ui_Range = CR_RANGE(insn->chanspec); - ui_Channel = CR_CHAN(insn->chanspec); - - if (ui_Range) { /* if 1 then unipolar */ - - if (data[0] != 0) - data[0] = - ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 << - 13) | (data[0] + 8191)); - else - data[0] = - ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 << - 13) | 8192); - - } else { /* if 0 then bipolar */ - data[0] = - ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) | - data[0]); - - } - - do { /* Waiting of DA_READY BIT */ - us_TmpValue = - ((unsigned short) inw(devpriv->iobase + - APCI3120_RD_STATUS)) & 0x0001; - } while (us_TmpValue != 0x0001); - - if (ui_Channel <= 3) - /* - * for channel 0-3 out at the register 1 (wrDac1-8) data[i] - * typecasted to ushort since word write is to be done - */ - outw((unsigned short) data[0], - devpriv->iobase + APCI3120_ANALOG_OUTPUT_1); - else - /* - * for channel 4-7 out at the register 2 (wrDac5-8) data[i] - * typecasted to ushort since word write is to be done - */ - outw((unsigned short) data[0], - devpriv->iobase + APCI3120_ANALOG_OUTPUT_2); - - return insn->n; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c deleted file mode 100644 index 5e321f91172f..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ /dev/null @@ -1,3003 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-3200 | Compiler : GCC | - | Module name : hwdrv_apci3200.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-3200 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 02.07.04 | J. Krauth | Modification from the driver in order to | - | | | correct some errors when using several boards. | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ - | 26.10.04 | J. Krauth | - Update for COMEDI 0.7.68 | - | | | - Read eeprom value | - | | | - Append APCI-3300 | - +----------+-----------+------------------------------------------------+ -*/ - -/* Card Specific information */ -/* #define APCI3200_ADDRESS_RANGE 264 */ - -/* Analog Input related Defines */ -#define APCI3200_AI_OFFSET_GAIN 0 -#define APCI3200_AI_SC_TEST 4 -#define APCI3200_AI_IRQ 8 -#define APCI3200_AI_AUTOCAL 12 -#define APCI3200_RELOAD_CONV_TIME_VAL 32 -#define APCI3200_CONV_TIME_TIME_BASE 36 -#define APCI3200_RELOAD_DELAY_TIME_VAL 40 -#define APCI3200_DELAY_TIME_TIME_BASE 44 -#define APCI3200_AI_MODULE1 0 -#define APCI3200_AI_MODULE2 64 -#define APCI3200_AI_MODULE3 128 -#define APCI3200_AI_MODULE4 192 -#define TRUE 1 -#define FALSE 0 -#define APCI3200_AI_EOSIRQ 16 -#define APCI3200_AI_EOS 20 -#define APCI3200_AI_CHAN_ID 24 -#define APCI3200_AI_CHAN_VAL 28 -#define ANALOG_INPUT 0 -#define TEMPERATURE 1 -#define RESISTANCE 2 - -#define ENABLE_EXT_TRIG 1 -#define ENABLE_EXT_GATE 2 -#define ENABLE_EXT_TRIG_GATE 3 - -#define APCI3200_MAXVOLT 2.5 -#define ADDIDATA_GREATER_THAN_TEST 0 -#define ADDIDATA_LESS_THAN_TEST 1 - -#define ADDIDATA_UNIPOLAR 1 -#define ADDIDATA_BIPOLAR 2 - -#define MAX_MODULE 4 - -/* ANALOG INPUT RANGE */ -static const struct comedi_lrange range_apci3200_ai = { - 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -static const struct comedi_lrange range_apci3300_ai = { - 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -int MODULE_NO; -struct { - int i_Gain; - int i_Polarity; - int i_OffsetRange; - int i_Coupling; - int i_SingleDiff; - int i_AutoCalibration; - unsigned int ui_ReloadValue; - unsigned int ui_TimeUnitReloadVal; - int i_Interrupt; - int i_ModuleSelection; -} Config_Parameters_Module1, Config_Parameters_Module2, - Config_Parameters_Module3, Config_Parameters_Module4; - - -struct str_ADDIDATA_RTDStruct { - unsigned int ul_NumberOfValue; - unsigned int *pul_ResistanceValue; - unsigned int *pul_TemperatureValue; -}; - -struct str_Module { - unsigned long ul_CurrentSourceCJC; - unsigned long ul_CurrentSource[5]; - unsigned long ul_GainFactor[8]; /* Gain Factor */ - unsigned int w_GainValue[10]; -}; - -struct str_BoardInfos { - - int i_CJCAvailable; - int i_CJCPolarity; - int i_CJCGain; - int i_InterruptFlag; - int i_ADDIDATAPolarity; - int i_ADDIDATAGain; - int i_AutoCalibration; - int i_ADDIDATAConversionTime; - int i_ADDIDATAConversionTimeUnit; - int i_ADDIDATAType; - int i_ChannelNo; - int i_ChannelCount; - int i_ScanType; - int i_FirstChannel; - int i_LastChannel; - int i_Sum; - int i_Offset; - unsigned int ui_Channel_num; - int i_Count; - int i_Initialised; - unsigned int ui_InterruptChannelValue[144]; /* Buffer */ - unsigned char b_StructInitialized; - /* 7 is the maximal number of channels */ - unsigned int ui_ScanValueArray[7 + 12]; - - int i_ConnectionType; - int i_NbrOfModule; - struct str_Module s_Module[MAX_MODULE]; -}; - -/* BEGIN JK 06.07.04: Management of sevrals boards */ -/* - int i_CJCAvailable=1; - int i_CJCPolarity=0; - int i_CJCGain=2;/* changed from 0 to 2 */ - int i_InterruptFlag=0; - int i_ADDIDATAPolarity; - int i_ADDIDATAGain; - int i_AutoCalibration=0; /* : auto calibration */ - int i_ADDIDATAConversionTime; - int i_ADDIDATAConversionTimeUnit; - int i_ADDIDATAType; - int i_ChannelNo; - int i_ChannelCount=0; - int i_ScanType; - int i_FirstChannel; - int i_LastChannel; - int i_Sum=0; - int i_Offset; - unsigned int ui_Channel_num=0; - static int i_Count=0; - int i_Initialised=0; - unsigned int ui_InterruptChannelValue[96]; /* Buffer */ -*/ -struct str_BoardInfos s_BoardInfos[100]; /* 100 will be the max number of boards to be used */ -/* END JK 06.07.04: Management of sevrals boards */ - -#define AMCC_OP_REG_MCSR 0x3c -#define EEPROM_BUSY 0x80000000 -#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ -#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ -#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ -#define NVCMD_BEGIN_WRITE (0x6 << 5) /* EEPROM begin write command */ - -static int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, - unsigned int dw_PCIBoardEepromAddress, - unsigned short w_EepromStartAddress, - unsigned short *pw_DataRead) -{ - unsigned int dw_eeprom_busy = 0; - int i_Counter = 0; - int i_WordCounter; - int i; - unsigned char pb_ReadByte[1]; - unsigned char b_ReadLowByte = 0; - unsigned char b_ReadHighByte = 0; - unsigned char b_SelectedAddressLow = 0; - unsigned char b_SelectedAddressHigh = 0; - unsigned short w_ReadWord = 0; - - for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead; - i_WordCounter++) { - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - for (i_Counter = 0; i_Counter < 2; i_Counter++) { - b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256; /* Read the low 8 bit part */ - b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256; /* Read the high 8 bit part */ - - /* Select the load low address mode */ - outb(NVCMD_LOAD_LOW, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Load the low address */ - outb(b_SelectedAddressLow, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the load high address mode */ - outb(NVCMD_LOAD_HIGH, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Load the high address */ - outb(b_SelectedAddressHigh, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the READ mode */ - outb(NVCMD_BEGIN_READ, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Read data into the EEPROM */ - *pb_ReadByte = - inb(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR + 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the upper address part */ - if (i_Counter == 0) - b_ReadLowByte = pb_ReadByte[0]; - else - b_ReadHighByte = pb_ReadByte[0]; - - - /* Sleep */ - msleep(1); - - } - w_ReadWord = - (b_ReadLowByte | (((unsigned short)b_ReadHighByte) * - 256)); - - pw_DataRead[i_WordCounter] = w_ReadWord; - - w_EepromStartAddress += 2; /* to read the next word */ - - } /* for (...) i_NbOfWordsToRead */ - return 0; -} - -static void v_GetAPCI3200EepromCalibrationValue(unsigned int dw_PCIBoardEepromAddress, - struct str_BoardInfos *BoardInformations) -{ - unsigned short w_AnalogInputMainHeaderAddress; - unsigned short w_AnalogInputComponentAddress; - unsigned short w_NumberOfModuls = 0; - unsigned short w_CurrentSources[2]; - unsigned short w_ModulCounter = 0; - unsigned short w_FirstHeaderSize = 0; - unsigned short w_NumberOfInputs = 0; - unsigned short w_CJCFlag = 0; - unsigned short w_NumberOfGainValue = 0; - unsigned short w_SingleHeaderAddress = 0; - unsigned short w_SingleHeaderSize = 0; - unsigned short w_Input = 0; - unsigned short w_GainFactorAddress = 0; - unsigned short w_GainFactorValue[2]; - unsigned short w_GainIndex = 0; - unsigned short w_GainValue = 0; - - /*****************************************/ - /** Get the Analog input header address **/ - /*****************************************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, 0x116, /* w_EepromStartAddress: Analog input header address */ - &w_AnalogInputMainHeaderAddress); - - /*******************************************/ - /** Compute the real analog input address **/ - /*******************************************/ - w_AnalogInputMainHeaderAddress = w_AnalogInputMainHeaderAddress + 0x100; - - /******************************/ - /** Get the number of moduls **/ - /******************************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_AnalogInputMainHeaderAddress + 0x02, /* w_EepromStartAddress: Number of conponment */ - &w_NumberOfModuls); - - for (w_ModulCounter = 0; w_ModulCounter < w_NumberOfModuls; - w_ModulCounter++) { - /***********************************/ - /** Compute the component address **/ - /***********************************/ - w_AnalogInputComponentAddress = - w_AnalogInputMainHeaderAddress + - (w_FirstHeaderSize * w_ModulCounter) + 0x04; - - /****************************/ - /** Read first header size **/ - /****************************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress, /* Address of the first header */ - &w_FirstHeaderSize); - - w_FirstHeaderSize = w_FirstHeaderSize >> 4; - - /***************************/ - /** Read number of inputs **/ - /***************************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x06, /* Number of inputs for the first modul */ - &w_NumberOfInputs); - - w_NumberOfInputs = w_NumberOfInputs >> 4; - - /***********************/ - /** Read the CJC flag **/ - /***********************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x08, /* CJC flag */ - &w_CJCFlag); - - w_CJCFlag = (w_CJCFlag >> 3) & 0x1; /* Get only the CJC flag */ - - /*******************************/ - /** Read number of gain value **/ - /*******************************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x44, /* Number of gain value */ - &w_NumberOfGainValue); - - w_NumberOfGainValue = w_NumberOfGainValue & 0xFF; - - /***********************************/ - /** Compute single header address **/ - /***********************************/ - w_SingleHeaderAddress = - w_AnalogInputComponentAddress + 0x46 + - (((w_NumberOfGainValue / 16) + 1) * 2) + - (6 * w_NumberOfGainValue) + - (4 * (((w_NumberOfGainValue / 16) + 1) * 2)); - - /********************************************/ - /** Read current sources value for input 1 **/ - /********************************************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_SingleHeaderAddress, /* w_EepromStartAddress: Single header address */ - &w_SingleHeaderSize); - - w_SingleHeaderSize = w_SingleHeaderSize >> 4; - - /*************************************/ - /** Read gain factor for the module **/ - /*************************************/ - w_GainFactorAddress = w_AnalogInputComponentAddress; - - for (w_GainIndex = 0; w_GainIndex < w_NumberOfGainValue; - w_GainIndex++) { - /************************************/ - /** Read gain value for the module **/ - /************************************/ - i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + (2 * (1 + (w_NumberOfGainValue / 16))) + (0x02 * w_GainIndex), /* Gain value */ - &w_GainValue); - - BoardInformations->s_Module[w_ModulCounter]. - w_GainValue[w_GainIndex] = w_GainValue; - - /*************************************/ - /** Read gain factor for the module **/ - /*************************************/ - i_AddiHeaderRW_ReadEeprom(2, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + ((2 * w_NumberOfGainValue) + (2 * (1 + (w_NumberOfGainValue / 16)))) + (0x04 * w_GainIndex), /* Gain factor */ - w_GainFactorValue); - - BoardInformations->s_Module[w_ModulCounter]. - ul_GainFactor[w_GainIndex] = - (w_GainFactorValue[1] << 16) + - w_GainFactorValue[0]; - } - - /***************************************************************/ - /** Read current source value for each channels of the module **/ - /***************************************************************/ - for (w_Input = 0; w_Input < w_NumberOfInputs; w_Input++) { - /********************************************/ - /** Read current sources value for input 1 **/ - /********************************************/ - i_AddiHeaderRW_ReadEeprom(2, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, - (w_Input * w_SingleHeaderSize) + - w_SingleHeaderAddress + 0x0C, w_CurrentSources); - - /************************************/ - /** Save the current sources value **/ - /************************************/ - BoardInformations->s_Module[w_ModulCounter]. - ul_CurrentSource[w_Input] = - (w_CurrentSources[0] + - ((w_CurrentSources[1] & 0xFFF) << 16)); - } - - /***************************************/ - /** Read the CJC current source value **/ - /***************************************/ - i_AddiHeaderRW_ReadEeprom(2, /* i_NbOfWordsToRead */ - dw_PCIBoardEepromAddress, - (w_Input * w_SingleHeaderSize) + w_SingleHeaderAddress + - 0x0C, w_CurrentSources); - - /************************************/ - /** Save the current sources value **/ - /************************************/ - BoardInformations->s_Module[w_ModulCounter]. - ul_CurrentSourceCJC = - (w_CurrentSources[0] + - ((w_CurrentSources[1] & 0xFFF) << 16)); - } -} - -static int i_APCI3200_GetChannelCalibrationValue(struct comedi_device *dev, - unsigned int ui_Channel_num, - unsigned int *CJCCurrentSource, - unsigned int *ChannelCurrentSource, - unsigned int *ChannelGainFactor) -{ - int i_DiffChannel = 0; - int i_Module = 0; - - /* Test if single or differential mode */ - if (s_BoardInfos[dev->minor].i_ConnectionType == 1) { - /* if diff */ - - if (ui_Channel_num <= 1) - i_DiffChannel = ui_Channel_num, i_Module = 0; - else if ((ui_Channel_num >= 2) && (ui_Channel_num <= 3)) - i_DiffChannel = ui_Channel_num - 2, i_Module = 1; - else if ((ui_Channel_num >= 4) && (ui_Channel_num <= 5)) - i_DiffChannel = ui_Channel_num - 4, i_Module = 2; - else if ((ui_Channel_num >= 6) && (ui_Channel_num <= 7)) - i_DiffChannel = ui_Channel_num - 6, i_Module = 3; - - } else { - /* if single */ - if ((ui_Channel_num == 0) || (ui_Channel_num == 1)) - i_DiffChannel = 0, i_Module = 0; - else if ((ui_Channel_num == 2) || (ui_Channel_num == 3)) - i_DiffChannel = 1, i_Module = 0; - else if ((ui_Channel_num == 4) || (ui_Channel_num == 5)) - i_DiffChannel = 0, i_Module = 1; - else if ((ui_Channel_num == 6) || (ui_Channel_num == 7)) - i_DiffChannel = 1, i_Module = 1; - else if ((ui_Channel_num == 8) || (ui_Channel_num == 9)) - i_DiffChannel = 0, i_Module = 2; - else if ((ui_Channel_num == 10) || (ui_Channel_num == 11)) - i_DiffChannel = 1, i_Module = 2; - else if ((ui_Channel_num == 12) || (ui_Channel_num == 13)) - i_DiffChannel = 0, i_Module = 3; - else if ((ui_Channel_num == 14) || (ui_Channel_num == 15)) - i_DiffChannel = 1, i_Module = 3; - } - - /* Test if thermocouple or RTD mode */ - *CJCCurrentSource = - s_BoardInfos[dev->minor].s_Module[i_Module].ul_CurrentSourceCJC; - - *ChannelCurrentSource = - s_BoardInfos[dev->minor].s_Module[i_Module]. - ul_CurrentSource[i_DiffChannel]; - /* } */ - /* } */ - - /* Channle gain factor */ - *ChannelGainFactor = - s_BoardInfos[dev->minor].s_Module[i_Module]. - ul_GainFactor[s_BoardInfos[dev->minor].i_ADDIDATAGain]; - /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - return 0; -} - -static int apci3200_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_IobaseReserved) & 0xf; - - return insn->n; -} - -static int apci3200_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_IobaseAddon) & 0xf; - - if (comedi_dio_update_state(s, data)) - outl(s->state, devpriv->i_IobaseAddon); - - data[1] = s->state; - - return insn->n; -} - -static int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_EOC = 0; - unsigned int ui_ChannelNo = 0; - unsigned int ui_CommandRegister = 0; - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_ChannelNo=i_ChannelNo; */ - ui_ChannelNo = s_BoardInfos[dev->minor].i_ChannelNo; - - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /*********************************/ - /* Write the channel to configure */ - /*********************************/ - /* Begin JK 20.10.2004: Bad channel value is used when using differential mode */ - /* outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); */ - /* outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); */ - outl(0 | s_BoardInfos[dev->minor].i_ChannelNo, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4); - /* End JK 20.10.2004: Bad channel value is used when using differential mode */ - - /*******************************/ - /* Set the convert timing unit */ - /*******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); - - /**************************/ - /* Set the convert timing */ - /**************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); - - /**************************************************************************/ - /* Set the start end stop index to the selected channel and set the start */ - /**************************************************************************/ - - ui_CommandRegister = ui_ChannelNo | (ui_ChannelNo << 8) | 0x80000; - - /*Test if the interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { - /* Enable the interrupt */ - ui_CommandRegister = ui_CommandRegister | 0x00100000; - } - - /******************************/ - /* Write the command register */ - /******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8); */ - outl(ui_CommandRegister, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - - /*Test if interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - do { - /*************************/ - /*Read the EOC Status bit */ - /*************************/ - - /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ - ui_EOC = inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 20) & 1; - - } while (ui_EOC != 1); - - /***************************************/ - /* Read the digital value of the input */ - /***************************************/ - - /* data[0] = inl (devpriv->iobase+i_Offset + 28); */ - data[0] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - /* END JK 06.07.04: Management of sevrals boards */ - - } - return 0; -} - -static int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_Temp = 0, ui_EOC = 0; - unsigned int ui_CommandRegister = 0; - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /*********************************/ - /* Write the channel to configure */ - /*********************************/ - /* Begin JK 20.10.2004: This seems not necessary ! */ - /* outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); */ - /* outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); */ - /* End JK 20.10.2004: This seems not necessary ! */ - - /*******************************/ - /* Set the convert timing unit */ - /*******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); - /**************************/ - /* Set the convert timing */ - /**************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); - /*****************************/ - /*Read the calibration offset */ - /*****************************/ - /* ui_Temp = inl(devpriv->iobase+i_Offset + 12); */ - ui_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - - /*********************************/ - /*Configure the Offset Conversion */ - /*********************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl((ui_Temp | 0x00020000), devpriv->iobase+i_Offset + 12); */ - outl((ui_Temp | 0x00020000), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /*******************************/ - /*Initialise ui_CommandRegister */ - /*******************************/ - - ui_CommandRegister = 0; - - /*Test if the interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { - /*Enable the interrupt */ - ui_CommandRegister = ui_CommandRegister | 0x00100000; - } - - /**********************/ - /*Start the conversion */ - /**********************/ - ui_CommandRegister = ui_CommandRegister | 0x00080000; - - /***************************/ - /*Write the command regiter */ - /***************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8); */ - outl(ui_CommandRegister, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - - /*Test if interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - do { - /*******************/ - /*Read the EOC flag */ - /*******************/ - - /* ui_EOC = inl (devpriv->iobase+i_Offset + 20) & 1; */ - ui_EOC = inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 20) & 1; - - } while (ui_EOC != 1); - - /**************************************************/ - /*Read the digital value of the calibration Offset */ - /**************************************************/ - - /* data[0] = inl(devpriv->iobase+i_Offset+ 28); */ - data[0] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - } - return 0; -} - -static int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_EOC = 0; - int ui_CommandRegister = 0; - - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /*********************************/ - /* Write the channel to configure */ - /*********************************/ - /* Begin JK 20.10.2004: This seems not necessary ! */ - /* outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); */ - /* outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); */ - /* End JK 20.10.2004: This seems not necessary ! */ - - /***************************/ - /*Read the calibration gain */ - /***************************/ - /*******************************/ - /* Set the convert timing unit */ - /*******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); - /**************************/ - /* Set the convert timing */ - /**************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); - /*******************************/ - /*Configure the Gain Conversion */ - /*******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(0x00040000 , devpriv->iobase+i_Offset + 12); */ - outl(0x00040000, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - - /*******************************/ - /*Initialise ui_CommandRegister */ - /*******************************/ - - ui_CommandRegister = 0; - - /*Test if the interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { - /*Enable the interrupt */ - ui_CommandRegister = ui_CommandRegister | 0x00100000; - } - - /**********************/ - /*Start the conversion */ - /**********************/ - - ui_CommandRegister = ui_CommandRegister | 0x00080000; - /***************************/ - /*Write the command regiter */ - /***************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8); */ - outl(ui_CommandRegister, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - - /*Test if interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - do { - - /*******************/ - /*Read the EOC flag */ - /*******************/ - - /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ - ui_EOC = inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 20) & 1; - - } while (ui_EOC != 1); - - /************************************************/ - /*Read the digital value of the calibration Gain */ - /************************************************/ - - /* data[0] = inl(devpriv->iobase+i_Offset + 28); */ - data[0] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - - } - return 0; -} - -static int i_APCI3200_ReadCJCValue(struct comedi_device *dev, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_EOC = 0; - int ui_CommandRegister = 0; - - /******************************/ - /*Set the converting time unit */ - /******************************/ - - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); - /**************************/ - /* Set the convert timing */ - /**************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); - - /******************************/ - /*Configure the CJC Conversion */ - /******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl( 0x00000400 , devpriv->iobase+i_Offset + 4); */ - outl(0x00000400, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); - /*******************************/ - /*Initialise dw_CommandRegister */ - /*******************************/ - ui_CommandRegister = 0; - /*Test if the interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { - /*Enable the interrupt */ - ui_CommandRegister = ui_CommandRegister | 0x00100000; - } - - /**********************/ - /*Start the conversion */ - /**********************/ - - ui_CommandRegister = ui_CommandRegister | 0x00080000; - - /***************************/ - /*Write the command regiter */ - /***************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8); */ - outl(ui_CommandRegister, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - - /*Test if interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - do { - - /*******************/ - /*Read the EOC flag */ - /*******************/ - - /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ - ui_EOC = inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 20) & 1; - - } while (ui_EOC != 1); - - /***********************************/ - /*Read the digital value of the CJC */ - /***********************************/ - - /* data[0] = inl(devpriv->iobase+i_Offset + 28); */ - data[0] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - } - return 0; -} - -static int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_EOC = 0; - int ui_CommandRegister = 0; - - /*******************************************/ - /*Read calibration offset value for the CJC */ - /*******************************************/ - /*******************************/ - /* Set the convert timing unit */ - /*******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); - /**************************/ - /* Set the convert timing */ - /**************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); - /******************************/ - /*Configure the CJC Conversion */ - /******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(0x00000400 , devpriv->iobase+i_Offset + 4); */ - outl(0x00000400, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); - /*********************************/ - /*Configure the Offset Conversion */ - /*********************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(0x00020000, devpriv->iobase+i_Offset + 12); */ - outl(0x00020000, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /*******************************/ - /*Initialise ui_CommandRegister */ - /*******************************/ - ui_CommandRegister = 0; - /*Test if the interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { - /*Enable the interrupt */ - ui_CommandRegister = ui_CommandRegister | 0x00100000; - } - - /**********************/ - /*Start the conversion */ - /**********************/ - ui_CommandRegister = ui_CommandRegister | 0x00080000; - /***************************/ - /*Write the command regiter */ - /***************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_CommandRegister,devpriv->iobase+i_Offset + 8); */ - outl(ui_CommandRegister, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - do { - /*******************/ - /*Read the EOC flag */ - /*******************/ - /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ - ui_EOC = inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 20) & 1; - } while (ui_EOC != 1); - - /**************************************************/ - /*Read the digital value of the calibration Offset */ - /**************************************************/ - /* data[0] = inl(devpriv->iobase+i_Offset + 28); */ - data[0] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - } - return 0; -} - -static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, - unsigned int *data) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_EOC = 0; - int ui_CommandRegister = 0; - - /*******************************/ - /* Set the convert timing unit */ - /*******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); - /**************************/ - /* Set the convert timing */ - /**************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ - outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); - /******************************/ - /*Configure the CJC Conversion */ - /******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(0x00000400,devpriv->iobase+i_Offset + 4); */ - outl(0x00000400, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); - /*******************************/ - /*Configure the Gain Conversion */ - /*******************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(0x00040000,devpriv->iobase+i_Offset + 12); */ - outl(0x00040000, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - - /*******************************/ - /*Initialise dw_CommandRegister */ - /*******************************/ - ui_CommandRegister = 0; - /*Test if the interrupt is enable */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { - /*Enable the interrupt */ - ui_CommandRegister = ui_CommandRegister | 0x00100000; - } - /**********************/ - /*Start the conversion */ - /**********************/ - ui_CommandRegister = ui_CommandRegister | 0x00080000; - /***************************/ - /*Write the command regiter */ - /***************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_CommandRegister ,devpriv->iobase+i_Offset + 8); */ - outl(ui_CommandRegister, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - do { - /*******************/ - /*Read the EOC flag */ - /*******************/ - /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ - ui_EOC = inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 20) & 1; - } while (ui_EOC != 1); - /************************************************/ - /*Read the digital value of the calibration Gain */ - /************************************************/ - /* data[0] = inl (devpriv->iobase+i_Offset + 28); */ - data[0] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - } - return 0; -} - -static int apci3200_reset(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - int i_Temp; - unsigned int dw_Dummy; - - /* i_InterruptFlag=0; */ - /* i_Initialised==0; */ - /* i_Count=0; */ - /* i_Sum=0; */ - - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - s_BoardInfos[dev->minor].i_Initialised = 0; - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - s_BoardInfos[dev->minor].b_StructInitialized = 0; - - outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); - - /* Enable the interrupt for the controller */ - dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); - outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); - outl(0, devpriv->i_IobaseAddon); /* Resets the output */ - /***************/ - /*Empty the buffer */ - /**************/ - for (i_Temp = 0; i_Temp <= 95; i_Temp++) { - /* ui_InterruptChannelValue[i_Temp]=0; */ - s_BoardInfos[dev->minor].ui_InterruptChannelValue[i_Temp] = 0; - } /* for(i_Temp=0;i_Temp<=95;i_Temp++) */ - /*****************************/ - /*Reset the START and IRQ bit */ - /*****************************/ - for (i_Temp = 0; i_Temp <= 192;) { - while (((inl(devpriv->iobase + i_Temp + 12) >> 19) & 1) != 1) ; - outl(0, devpriv->iobase + i_Temp + 8); - i_Temp = i_Temp + 64; - } /* for(i_Temp=0;i_Temp<=192;i_Temp+64) */ - return 0; -} - -/* - * Read value of the selected channel - * - * data[0] : Digital Value Of Input - * data[1] : Calibration Offset Value - * data[2] : Calibration Gain Value - * data[3] : CJC value - * data[4] : CJC offset value - * data[5] : CJC gain value - * data[6] : CJC current source from eeprom - * data[7] : Channel current source from eeprom - * data[8] : Channle gain factor from eeprom - */ -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; - int i = 0; - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_Initialised==0) */ - if (s_BoardInfos[dev->minor].i_Initialised == 0) - /* END JK 06.07.04: Management of sevrals boards */ - { - apci3200_reset(dev); - return -EINVAL; - } /* if(i_Initialised==0); */ - - switch (insn->unused[0]) { - case 0: - - i_APCI3200_Read1AnalogInputChannel(dev, s, insn, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+0]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 0] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - - /* Begin JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - i_APCI3200_GetChannelCalibrationValue(dev, - s_BoardInfos[dev->minor].ui_Channel_num, - &s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 6], - &s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 7], - &s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 8]); - /* End JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ - if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) - && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) - && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_APCI3200_ReadCJCValue(dev, &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 3]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 3] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 3]=0; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 3] = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* elseif((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ - if ((s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) - && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE)) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_APCI3200_ReadCalibrationOffsetValue(dev, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 1]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 1] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - i_APCI3200_ReadCalibrationGainValue(dev, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 2]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 2] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)&& (i_CJCAvailable==1)) */ - if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) - && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) - && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) - /* END JK 06.07.04: Management of sevrals boards */ - { - /**********************************************************/ - /*Test if the Calibration channel must be read for the CJC */ - /**********************************************************/ - /**********************************/ - /*Test if the polarity is the same */ - /**********************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ - if (s_BoardInfos[dev->minor].i_CJCPolarity != - s_BoardInfos[dev->minor].i_ADDIDATAPolarity) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_ConvertCJCCalibration = 1; - } /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_CJCGain==i_ADDIDATAGain) */ - if (s_BoardInfos[dev->minor].i_CJCGain == - s_BoardInfos[dev->minor].i_ADDIDATAGain) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_ConvertCJCCalibration = 0; - } /* if(i_CJCGain==i_ADDIDATAGain) */ - else { - i_ConvertCJCCalibration = 1; - } /* elseif(i_CJCGain==i_ADDIDATAGain) */ - } /* elseif(i_CJCPolarity!=i_ADDIDATAPolarity) */ - if (i_ConvertCJCCalibration == 1) { - i_APCI3200_ReadCJCCalOffset(dev, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+4]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 4] = - ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - - i_APCI3200_ReadCJCCalGain(dev, &ui_DummyValue); - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+5]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 5] = - ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(i_ConvertCJCCalibration==1) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+4]=0; */ - /* ui_InterruptChannelValue[i_Count+5]=0; */ - - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 4] = 0; - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 5] = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* elseif(i_ConvertCJCCalibration==1) */ - } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_ScanType!=1) */ - if (s_BoardInfos[dev->minor].i_ScanType != 1) { - /* i_Count=0; */ - s_BoardInfos[dev->minor].i_Count = 0; - } /* if(i_ScanType!=1) */ - else { - /* i_Count=i_Count +6; */ - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count +6; */ - s_BoardInfos[dev->minor].i_Count = - s_BoardInfos[dev->minor].i_Count + 9; - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } /* else if(i_ScanType!=1) */ - - /* if((i_ScanType==1) &&(i_InterruptFlag==1)) */ - if ((s_BoardInfos[dev->minor].i_ScanType == 1) - && (s_BoardInfos[dev->minor].i_InterruptFlag == 1)) { - /* i_Count=i_Count-6; */ - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count-6; */ - s_BoardInfos[dev->minor].i_Count = - s_BoardInfos[dev->minor].i_Count - 9; - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } - /* if(i_ScanType==0) */ - if (s_BoardInfos[dev->minor].i_ScanType == 0) { - /* - data[0]= ui_InterruptChannelValue[0]; - data[1]= ui_InterruptChannelValue[1]; - data[2]= ui_InterruptChannelValue[2]; - data[3]= ui_InterruptChannelValue[3]; - data[4]= ui_InterruptChannelValue[4]; - data[5]= ui_InterruptChannelValue[5]; - */ - data[0] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[0]; - data[1] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[1]; - data[2] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[2]; - data[3] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[3]; - data[4] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[4]; - data[5] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[5]; - - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - i_APCI3200_GetChannelCalibrationValue(dev, - s_BoardInfos[dev->minor].ui_Channel_num, - &data[6], &data[7], &data[8]); - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } - break; - case 1: - - for (i = 0; i < insn->n; i++) { - /* data[i]=ui_InterruptChannelValue[i]; */ - data[i] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[i]; - } - - /* i_Count=0; */ - /* i_Sum=0; */ - /* if(i_ScanType==1) */ - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - if (s_BoardInfos[dev->minor].i_ScanType == 1) { - /* i_Initialised=0; */ - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor].i_Initialised = 0; - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } - break; - default: - printk("\nThe parameters passed are in error\n"); - apci3200_reset(dev); - return -EINVAL; - } /* switch(insn->unused[0]) */ - - return insn->n; -} - -/* - * Configures The Analog Input Subdevice - * - * data[0] = 0 Normal AI - * = 1 RTD - * = 2 THERMOCOUPLE - * data[1] = Gain To Use - * data[2] = 0 Bipolar - * = 1 Unipolar - * data[3] = Offset Range - * data[4] = 0 DC Coupling - * = 1 AC Coupling - * data[5] = 0 Single - * = 1 Differential - * data[6] = TimerReloadValue - * data[7] = ConvertingTimeUnit - * data[8] = 0 Analog voltage measurement - * = 1 Resistance measurement - * = 2 Temperature measurement - * data[9] = 0 Interrupt Disable - * = 1 INterrupt Enable - * data[10] = Type of Thermocouple - * data[11] = single channel Module Number - * data[12] = 0 Single Read - * = 1 Read more channel - * = 2 Single scan - * = 3 Continuous Scan - * data[13] = Number of channels to read - * data[14] = 0 RTD not used - * = 1 RTD 2 wire connection - * = 2 RTD 3 wire connection - * = 3 RTD 4 wire connection - */ -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; - unsigned int ui_ChannelNo = 0; - unsigned int ui_Dummy = 0; - int i_err = 0; - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* Initialize the structure */ - if (s_BoardInfos[dev->minor].b_StructInitialized != 1) { - s_BoardInfos[dev->minor].i_CJCAvailable = 1; - s_BoardInfos[dev->minor].i_CJCPolarity = 0; - s_BoardInfos[dev->minor].i_CJCGain = 2; /* changed from 0 to 2 */ - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - s_BoardInfos[dev->minor].i_AutoCalibration = 0; /* : auto calibration */ - s_BoardInfos[dev->minor].i_ChannelCount = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - s_BoardInfos[dev->minor].ui_Channel_num = 0; - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Initialised = 0; - s_BoardInfos[dev->minor].b_StructInitialized = 1; - - /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - s_BoardInfos[dev->minor].i_ConnectionType = 0; - /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - memset(s_BoardInfos[dev->minor].s_Module, 0, - sizeof(s_BoardInfos[dev->minor].s_Module[MAX_MODULE])); - - v_GetAPCI3200EepromCalibrationValue(devpriv->i_IobaseAmcc, - &s_BoardInfos[dev->minor]); - /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } - - if (data[0] != 0 && data[0] != 1 && data[0] != 2) { - printk("\nThe selection of acquisition type is in error\n"); - i_err++; - } /* if(data[0]!=0 && data[0]!=1 && data[0]!=2) */ - if (data[0] == 1) { - if (data[14] != 0 && data[14] != 1 && data[14] != 2 - && data[14] != 4) { - printk("\n Error in selection of RTD connection type\n"); - i_err++; - } /* if(data[14]!=0 && data[14]!=1 && data[14]!=2 && data[14]!=4) */ - } /* if(data[0]==1 ) */ - if (data[1] < 0 || data[1] > 7) { - printk("\nThe selection of gain is in error\n"); - i_err++; - } /* if(data[1]<0 || data[1]>7) */ - if (data[2] != 0 && data[2] != 1) { - printk("\nThe selection of polarity is in error\n"); - i_err++; - } /* if(data[2]!=0 && data[2]!=1) */ - if (data[3] != 0) { - printk("\nThe selection of offset range is in error\n"); - i_err++; - } /* if(data[3]!=0) */ - if (data[4] != 0 && data[4] != 1) { - printk("\nThe selection of coupling is in error\n"); - i_err++; - } /* if(data[4]!=0 && data[4]!=1) */ - if (data[5] != 0 && data[5] != 1) { - printk("\nThe selection of single/differential mode is in error\n"); - i_err++; - } /* if(data[5]!=0 && data[5]!=1) */ - if (data[8] != 0 && data[8] != 1 && data[2] != 2) { - printk("\nError in selection of functionality\n"); - } /* if(data[8]!=0 && data[8]!=1 && data[2]!=2) */ - if (data[12] == 0 || data[12] == 1) { - if (data[6] != 20 && data[6] != 40 && data[6] != 80 - && data[6] != 160) { - printk("\nThe selection of conversion time reload value is in error\n"); - i_err++; - } /* if (data[6]!=20 && data[6]!=40 && data[6]!=80 && data[6]!=160 ) */ - if (data[7] != 2) { - printk("\nThe selection of conversion time unit is in error\n"); - i_err++; - } /* if(data[7]!=2) */ - } - if (data[9] != 0 && data[9] != 1) { - printk("\nThe selection of interrupt enable is in error\n"); - i_err++; - } /* if(data[9]!=0 && data[9]!=1) */ - if (data[11] < 0 || data[11] > 4) { - printk("\nThe selection of module is in error\n"); - i_err++; - } /* if(data[11] <0 || data[11]>1) */ - if (data[12] < 0 || data[12] > 3) { - printk("\nThe selection of singlechannel/scan selection is in error\n"); - i_err++; - } /* if(data[12] < 0 || data[12]> 3) */ - if (data[13] < 0 || data[13] > 16) { - printk("\nThe selection of number of channels is in error\n"); - i_err++; - } /* if(data[13] <0 ||data[13] >15) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* - i_ChannelCount=data[13]; - i_ScanType=data[12]; - i_ADDIDATAPolarity = data[2]; - i_ADDIDATAGain=data[1]; - i_ADDIDATAConversionTime=data[6]; - i_ADDIDATAConversionTimeUnit=data[7]; - i_ADDIDATAType=data[0]; - */ - - /* Save acquisition configuration for the actual board */ - s_BoardInfos[dev->minor].i_ChannelCount = data[13]; - s_BoardInfos[dev->minor].i_ScanType = data[12]; - s_BoardInfos[dev->minor].i_ADDIDATAPolarity = data[2]; - s_BoardInfos[dev->minor].i_ADDIDATAGain = data[1]; - s_BoardInfos[dev->minor].i_ADDIDATAConversionTime = data[6]; - s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit = data[7]; - s_BoardInfos[dev->minor].i_ADDIDATAType = data[0]; - /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - s_BoardInfos[dev->minor].i_ConnectionType = data[5]; - /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* END JK 06.07.04: Management of sevrals boards */ - - /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - memset(s_BoardInfos[dev->minor].ui_ScanValueArray, 0, (7 + 12) * sizeof(unsigned int)); /* 7 is the maximal number of channels */ - /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /* BEGIN JK 02.07.04 : This while can't be do, it block the process when using severals boards */ - /* while(i_InterruptFlag==1) */ - while (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { -#ifndef MSXBOX - udelay(1); -#else - /* In the case where the driver is compiled for the MSX-Box */ - /* we used a printk to have a little delay because udelay */ - /* seems to be broken under the MSX-Box. */ - /* This solution hat to be studied. */ - printk(""); -#endif - } - /* END JK 02.07.04 : This while can't be do, it block the process when using severals boards */ - - ui_ChannelNo = CR_CHAN(insn->chanspec); /* get the channel */ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=ui_ChannelNo; */ - /* ui_Channel_num =ui_ChannelNo; */ - - s_BoardInfos[dev->minor].i_ChannelNo = ui_ChannelNo; - s_BoardInfos[dev->minor].ui_Channel_num = ui_ChannelNo; - - /* END JK 06.07.04: Management of sevrals boards */ - - if (data[5] == 0) { - if (ui_ChannelNo > 15) { - printk("\nThe Selection of the channel is in error\n"); - i_err++; - } /* if(ui_ChannelNo>15) */ - } /* if(data[5]==0) */ - else { - if (data[14] == 2) { - if (ui_ChannelNo > 3) { - printk("\nThe Selection of the channel is in error\n"); - i_err++; - } /* if(ui_ChannelNo>3) */ - } /* if(data[14]==2) */ - else { - if (ui_ChannelNo > 7) { - printk("\nThe Selection of the channel is in error\n"); - i_err++; - } /* if(ui_ChannelNo>7) */ - } /* elseif(data[14]==2) */ - } /* elseif(data[5]==0) */ - if (data[12] == 0 || data[12] == 1) { - switch (data[5]) { - case 0: - if (ui_ChannelNo <= 3) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo <=3) */ - if (ui_ChannelNo >= 4 && ui_ChannelNo <= 7) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=64; */ - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=7) */ - if (ui_ChannelNo >= 8 && ui_ChannelNo <= 11) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=8 && ui_ChannelNo <=11) */ - if (ui_ChannelNo >= 12 && ui_ChannelNo <= 15) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=12 && ui_ChannelNo <=15) */ - break; - case 1: - if (data[14] == 2) { - if (ui_ChannelNo == 0) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==0 ) */ - if (ui_ChannelNo == 1) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==1) */ - if (ui_ChannelNo == 2) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==2 ) */ - if (ui_ChannelNo == 3) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==3) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=0; */ - s_BoardInfos[dev->minor].i_ChannelNo = 0; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = 0; - break; - } /* if(data[14]==2) */ - if (ui_ChannelNo <= 1) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo <=1) */ - if (ui_ChannelNo >= 2 && ui_ChannelNo <= 3) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=i_ChannelNo-2; */ - /* i_Offset=64; */ - s_BoardInfos[dev->minor].i_ChannelNo = - s_BoardInfos[dev->minor].i_ChannelNo - - 2; - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = ui_ChannelNo - 2; - } /* if(ui_ChannelNo >=2 && ui_ChannelNo <=3) */ - if (ui_ChannelNo >= 4 && ui_ChannelNo <= 5) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=i_ChannelNo-4; */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_ChannelNo = - s_BoardInfos[dev->minor].i_ChannelNo - - 4; - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = ui_ChannelNo - 4; - } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=5) */ - if (ui_ChannelNo >= 6 && ui_ChannelNo <= 7) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=i_ChannelNo-6; */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_ChannelNo = - s_BoardInfos[dev->minor].i_ChannelNo - - 6; - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = ui_ChannelNo - 6; - } /* if(ui_ChannelNo >=6 && ui_ChannelNo <=7) */ - break; - - default: - printk("\n This selection of polarity does not exist\n"); - i_err++; - } /* switch(data[2]) */ - } /* if(data[12]==0 || data[12]==1) */ - else { - switch (data[11]) { - case 1: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - break; - case 2: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=64; */ - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - break; - case 3: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - break; - case 4: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - break; - default: - printk("\nError in module selection\n"); - i_err++; - } /* switch(data[11]) */ - } /* elseif(data[12]==0 || data[12]==1) */ - if (i_err) { - apci3200_reset(dev); - return -EINVAL; - } - /* if(i_ScanType!=1) */ - if (s_BoardInfos[dev->minor].i_ScanType != 1) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Count=0; */ - /* i_Sum=0; */ - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(i_ScanType!=1) */ - - ul_Config = - data[1] | (data[2] << 6) | (data[5] << 7) | (data[3] << 8) | - (data[4] << 9); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - /*********************************/ - /* Write the channel to configure */ - /*********************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl(0 | ui_ChannelNo , devpriv->iobase+i_Offset + 0x4); */ - outl(0 | ui_ChannelNo, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4); - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - /**************************/ - /* Reset the configuration */ - /**************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl(0 , devpriv->iobase+i_Offset + 0x0); */ - outl(0, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - - /***************************/ - /* Write the configuration */ - /***************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl(ul_Config , devpriv->iobase+i_Offset + 0x0); */ - outl(ul_Config, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); - /* END JK 06.07.04: Management of sevrals boards */ - - /***************************/ - /*Reset the calibration bit */ - /***************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ul_Temp = inl(devpriv->iobase+i_Offset + 12); */ - ul_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl((ul_Temp & 0xFFF9FFFF) , devpriv->iobase+.i_Offset + 12); */ - outl((ul_Temp & 0xFFF9FFFF), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /* END JK 06.07.04: Management of sevrals boards */ - - if (data[9] == 1) { - devpriv->tsk_Current = current; - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_InterruptFlag=1; */ - s_BoardInfos[dev->minor].i_InterruptFlag = 1; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(data[9]==1) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* else if(data[9]==1) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Initialised=1; */ - s_BoardInfos[dev->minor].i_Initialised = 1; - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_ScanType==1) */ - if (s_BoardInfos[dev->minor].i_ScanType == 1) - /* END JK 06.07.04: Management of sevrals boards */ - { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Sum=i_Sum+1; */ - s_BoardInfos[dev->minor].i_Sum = - s_BoardInfos[dev->minor].i_Sum + 1; - /* END JK 06.07.04: Management of sevrals boards */ - - insn->unused[0] = 0; - apci3200_ai_read(dev, s, insn, &ui_Dummy); - } - - return insn->n; -} - -/* - * Tests the Selected Anlog Input Channel - * - * data[0] = 0 TestAnalogInputShortCircuit - * = 1 TestAnalogInputConnection - * - * data[0] : Digital value obtained - * data[1] : calibration offset - * data[2] : calibration gain - */ -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; - int i_Temp; /* ,i_TimeUnit; */ - - /* if(i_Initialised==0) */ - - if (s_BoardInfos[dev->minor].i_Initialised == 0) { - apci3200_reset(dev); - return -EINVAL; - } /* if(i_Initialised==0); */ - if (data[0] != 0 && data[0] != 1) { - printk("\nError in selection of functionality\n"); - apci3200_reset(dev); - return -EINVAL; - } /* if(data[0]!=0 && data[0]!=1) */ - - if (data[0] == 1) /* Perform Short Circuit TEST */ - { - /**************************/ - /*Set the short-cicuit bit */ - /**************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. - i_Offset + 12) >> 19) & 1) != - 1) ; - /* outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ - outl((0x00001000 | s_BoardInfos[dev->minor].i_ChannelNo), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 4); - /*************************/ - /*Set the time unit to ns */ - /*************************/ - /* i_TimeUnit= i_ADDIDATAConversionTimeUnit; - i_ADDIDATAConversionTimeUnit= 1; */ - /* i_Temp= i_InterruptFlag ; */ - i_Temp = s_BoardInfos[dev->minor].i_InterruptFlag; - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - i_APCI3200_Read1AnalogInputChannel(dev, s, insn, data); - /* if(i_AutoCalibration == FALSE) */ - if (s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) { - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. - i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ - outl((0x00001000 | s_BoardInfos[dev->minor]. - i_ChannelNo), - devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 4); - data++; - i_APCI3200_ReadCalibrationOffsetValue(dev, data); - data++; - i_APCI3200_ReadCalibrationGainValue(dev, data); - } - } else { - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. - i_Offset + 12) >> 19) & 1) != - 1) ; - /* outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ - outl((0x00000800 | s_BoardInfos[dev->minor].i_ChannelNo), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 4); - /* ui_Configuration = inl(devpriv->iobase+i_Offset + 0); */ - ui_Configuration = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 0); - /*************************/ - /*Set the time unit to ns */ - /*************************/ - /* i_TimeUnit= i_ADDIDATAConversionTimeUnit; - i_ADDIDATAConversionTimeUnit= 1; */ - /* i_Temp= i_InterruptFlag ; */ - i_Temp = s_BoardInfos[dev->minor].i_InterruptFlag; - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - i_APCI3200_Read1AnalogInputChannel(dev, s, insn, data); - /* if(i_AutoCalibration == FALSE) */ - if (s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) { - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. - i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ - outl((0x00000800 | s_BoardInfos[dev->minor]. - i_ChannelNo), - devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 4); - data++; - i_APCI3200_ReadCalibrationOffsetValue(dev, data); - data++; - i_APCI3200_ReadCalibrationGainValue(dev, data); - } - } - /* i_InterruptFlag=i_Temp ; */ - s_BoardInfos[dev->minor].i_InterruptFlag = i_Temp; - return insn->n; -} - -static int apci3200_ai_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - apci3200_reset(dev); - return insn->n; -} - -static int apci3200_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - - int err = 0; - unsigned int ui_ConvertTime = 0; - unsigned int ui_ConvertTimeBase = 0; - unsigned int ui_DelayTime = 0; - unsigned int ui_DelayTimeBase = 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 */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) - err |= -EINVAL; - - if (err) { - apci3200_reset(dev); - return 1; - } - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(&cmd->start_src); - err |= cfc_check_trigger_is_unique(&cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(&cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - 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; - } - /* 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; - } - - 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]; */ - s_BoardInfos[dev->minor].i_LastChannel = cmd->chanlist[1]; - - if (cmd->convert_src == TRIG_TIMER) { - ui_ConvertTime = cmd->convert_arg & 0xFFFF; - ui_ConvertTimeBase = cmd->convert_arg >> 16; - if (ui_ConvertTime != 20 && ui_ConvertTime != 40 - && ui_ConvertTime != 80 && ui_ConvertTime != 160) - { - printk("\nThe selection of conversion time reload value is in error\n"); - err++; - } /* if (ui_ConvertTime!=20 && ui_ConvertTime!=40 && ui_ConvertTime!=80 && ui_ConvertTime!=160 ) */ - if (ui_ConvertTimeBase != 2) { - printk("\nThe selection of conversion time unit is in error\n"); - err++; - } /* if(ui_ConvertTimeBase!=2) */ - } else { - ui_ConvertTime = 0; - ui_ConvertTimeBase = 0; - } - if (cmd->scan_begin_src == TRIG_FOLLOW) { - ui_DelayTime = 0; - ui_DelayTimeBase = 0; - } /* if(cmd->scan_begin_src==TRIG_FOLLOW) */ - else { - ui_DelayTime = cmd->scan_begin_arg & 0xFFFF; - ui_DelayTimeBase = cmd->scan_begin_arg >> 16; - if (ui_DelayTimeBase != 2 && ui_DelayTimeBase != 3) { - err++; - printk("\nThe Delay time base selection is in error\n"); - } - if (ui_DelayTime < 1 || ui_DelayTime > 1023) { - err++; - printk("\nThe Delay time value is in error\n"); - } - if (err) { - apci3200_reset(dev); - return 3; - } - fpu_begin(); - d_SCANTimeNewUnit = (double)ui_DelayTime; - /* i_NbrOfChannel= i_LastChannel-i_FirstChannel + 4; */ - i_NbrOfChannel = - s_BoardInfos[dev->minor].i_LastChannel - - s_BoardInfos[dev->minor].i_FirstChannel + 4; - /**********************************************************/ - /*calculate the total conversion time for all the channels */ - /**********************************************************/ - d_ConversionTimeForAllChannels = - (double)((double)ui_ConvertTime / - (double)i_NbrOfChannel); - - /*******************************/ - /*Convert the frequence in time */ - /*******************************/ - d_ConversionTimeForAllChannels = - (double)1.0 / d_ConversionTimeForAllChannels; - ui_ConvertTimeBase = 3; - /***********************************/ - /*Test if the time unit is the same */ - /***********************************/ - - if (ui_DelayTimeBase <= ui_ConvertTimeBase) { - - for (i_Cpt = 0; - i_Cpt < (ui_ConvertTimeBase - ui_DelayTimeBase); - i_Cpt++) { - - d_ConversionTimeForAllChannels = - d_ConversionTimeForAllChannels * 1000; - d_ConversionTimeForAllChannels = - d_ConversionTimeForAllChannels + 1; - } - } else { - for (i_Cpt = 0; - i_Cpt < (ui_DelayTimeBase - ui_ConvertTimeBase); - i_Cpt++) { - d_SCANTimeNewUnit = d_SCANTimeNewUnit * 1000; - - } - } - - if (d_ConversionTimeForAllChannels >= d_SCANTimeNewUnit) { - - printk("\nSCAN Delay value cannot be used\n"); - /*********************************/ - /*SCAN Delay value cannot be used */ - /*********************************/ - err++; - } - fpu_end(); - } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ - - if (err) { - apci3200_reset(dev); - return 4; - } - - return 0; -} - -static int apci3200_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct addi_private *devpriv = dev->private; - unsigned int ui_Configuration = 0; - - /* i_InterruptFlag=0; */ - /* i_Initialised=0; */ - /* i_Count=0; */ - /* i_Sum=0; */ - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - s_BoardInfos[dev->minor].i_Initialised = 0; - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - - /*******************/ - /*Read the register */ - /*******************/ - /* ui_Configuration = inl(devpriv->iobase+i_Offset + 8); */ - ui_Configuration = - inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - /*****************************/ - /*Reset the START and IRQ bit */ - /*****************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl((ui_Configuration & 0xFFE7FFFF),devpriv->iobase+i_Offset + 8); */ - outl((ui_Configuration & 0xFFE7FFFF), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - return 0; -} - -/* - * Does asynchronous acquisition - * Determines the mode 1 or 2. - */ -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; - unsigned int ui_Configuration = 0; - /* INT i_CurrentSource = 0; */ - unsigned int ui_Trigger = 0; - unsigned int ui_TriggerEdge = 0; - unsigned int ui_Triggermode = 0; - unsigned int ui_ScanMode = 0; - unsigned int ui_ConvertTime = 0; - unsigned int ui_ConvertTimeBase = 0; - unsigned int ui_DelayTime = 0; - unsigned int ui_DelayTimeBase = 0; - unsigned int ui_DelayMode = 0; - - /* i_FirstChannel=cmd->chanlist[0]; */ - /* i_LastChannel=cmd->chanlist[1]; */ - s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0]; - s_BoardInfos[dev->minor].i_LastChannel = cmd->chanlist[1]; - if (cmd->start_src == TRIG_EXT) { - ui_Trigger = 1; - ui_TriggerEdge = cmd->start_arg & 0xFFFF; - ui_Triggermode = cmd->start_arg >> 16; - } /* if(cmd->start_src==TRIG_EXT) */ - else { - ui_Trigger = 0; - } /* elseif(cmd->start_src==TRIG_EXT) */ - - if (cmd->stop_src == TRIG_COUNT) { - ui_ScanMode = 0; - } /* if (cmd->stop_src==TRIG_COUNT) */ - else { - ui_ScanMode = 2; - } /* else if (cmd->stop_src==TRIG_COUNT) */ - - if (cmd->scan_begin_src == TRIG_FOLLOW) { - ui_DelayTime = 0; - ui_DelayTimeBase = 0; - ui_DelayMode = 0; - } /* if(cmd->scan_begin_src==TRIG_FOLLOW) */ - else { - ui_DelayTime = cmd->scan_begin_arg & 0xFFFF; - ui_DelayTimeBase = cmd->scan_begin_arg >> 16; - ui_DelayMode = 1; - } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ - if (cmd->convert_src == TRIG_TIMER) { - ui_ConvertTime = cmd->convert_arg & 0xFFFF; - ui_ConvertTimeBase = cmd->convert_arg >> 16; - } else { - ui_ConvertTime = 0; - ui_ConvertTimeBase = 0; - } - - /* if(i_ADDIDATAType ==1 || ((i_ADDIDATAType==2))) */ - /* { */ - /**************************************************/ - /*Read the old configuration of the current source */ - /**************************************************/ - /* ui_Configuration = inl(devpriv->iobase+i_Offset + 12); */ - ui_Configuration = - inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /***********************************************/ - /*Write the configuration of the current source */ - /***********************************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl((ui_Configuration & 0xFFC00000 ), devpriv->iobase+i_Offset +12); */ - outl((ui_Configuration & 0xFFC00000), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /* } */ - ui_Configuration = 0; - - /* ui_Configuration = i_FirstChannel |(i_LastChannel << 8)| 0x00100000 | */ - ui_Configuration = - s_BoardInfos[dev->minor].i_FirstChannel | (s_BoardInfos[dev-> - minor]. - i_LastChannel << 8) | 0x00100000 | (ui_Trigger << 24) | - (ui_TriggerEdge << 25) | (ui_Triggermode << 27) | (ui_DelayMode - << 18) | (ui_ScanMode << 16); - - /*************************/ - /*Write the Configuration */ - /*************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl( ui_Configuration, devpriv->iobase+i_Offset + 0x8); */ - outl(ui_Configuration, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x8); - /***********************/ - /*Write the Delay Value */ - /***********************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_DelayTime,devpriv->iobase+i_Offset + 40); */ - outl(ui_DelayTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 40); - /***************************/ - /*Write the Delay time base */ - /***************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_DelayTimeBase,devpriv->iobase+i_Offset + 44); */ - outl(ui_DelayTimeBase, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 44); - /*********************************/ - /*Write the conversion time value */ - /*********************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_ConvertTime,devpriv->iobase+i_Offset + 32); */ - outl(ui_ConvertTime, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); - - /********************************/ - /*Write the conversion time base */ - /********************************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl(ui_ConvertTimeBase,devpriv->iobase+i_Offset + 36); */ - outl(ui_ConvertTimeBase, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); - /*******************/ - /*Read the register */ - /*******************/ - /* ui_Configuration = inl(devpriv->iobase+i_Offset + 4); */ - ui_Configuration = - inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); - /******************/ - /*Set the SCAN bit */ - /******************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - - /* outl(((ui_Configuration & 0x1E0FF) | 0x00002000),devpriv->iobase+i_Offset + 4); */ - outl(((ui_Configuration & 0x1E0FF) | 0x00002000), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); - /*******************/ - /*Read the register */ - /*******************/ - ui_Configuration = 0; - /* ui_Configuration = inl(devpriv->iobase+i_Offset + 8); */ - ui_Configuration = - inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - - /*******************/ - /*Set the START bit */ - /*******************/ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* outl((ui_Configuration | 0x00080000),devpriv->iobase+i_Offset + 8); */ - outl((ui_Configuration | 0x00080000), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - return 0; -} - -/* - * This function copies the acquired data(from FIFO) to Comedi buffer. - */ -static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) -{ - struct addi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned int ui_StatusRegister = 0; - - /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* comedi_async *async = s->async; */ - /* UINT *data; */ - /* data=async->data+async->buf_int_ptr;//new samples added from here onwards */ - int n = 0, i = 0; - /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /************************************/ - /*Read the interrupt status register */ - /************************************/ - /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ - ui_StatusRegister = - inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 16); - - /*************************/ - /*Test if interrupt occur */ - /*************************/ - - if ((ui_StatusRegister & 0x2) == 0x2) { - /*************************/ - /*Read the channel number */ - /*************************/ - /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ - /* 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); */ - /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /*************************************/ - /*Read the digital Analog Input value */ - /*************************************/ - - /* data[i_Count] = inl(devpriv->iobase+i_Offset + 28); */ - /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* data[s_BoardInfos [dev->minor].i_Count] = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 28); */ - s_BoardInfos[dev->minor].ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /* if((i_Count == (i_LastChannel-i_FirstChannel+3))) */ - if ((s_BoardInfos[dev->minor].i_Count == - (s_BoardInfos[dev->minor].i_LastChannel - - s_BoardInfos[dev->minor]. - i_FirstChannel + 3))) { - - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - s_BoardInfos[dev->minor].i_Count++; - - for (i = s_BoardInfos[dev->minor].i_FirstChannel; - i <= s_BoardInfos[dev->minor].i_LastChannel; - i++) { - i_APCI3200_GetChannelCalibrationValue(dev, i, - &s_BoardInfos[dev->minor]. - ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count + ((i - - s_BoardInfos - [dev->minor]. - i_FirstChannel) - * 3)], - &s_BoardInfos[dev->minor]. - ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count + ((i - - s_BoardInfos - [dev->minor]. - i_FirstChannel) - * 3) + 1], - &s_BoardInfos[dev->minor]. - ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count + ((i - - s_BoardInfos - [dev->minor]. - i_FirstChannel) - * 3) + 2]); - } - - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /* i_Count=-1; */ - - s_BoardInfos[dev->minor].i_Count = -1; - - /* async->buf_int_count+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ - /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* async->buf_int_count+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* async->buf_int_ptr+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ - /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* async->buf_int_ptr+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ - /* comedi_eos(dev,s); */ - - /* Set the event type (Comedi Buffer End Of Scan) */ - s->async->events |= COMEDI_CB_EOS; - - /* Test if enougth memory is available and allocate it for 7 values */ - n = comedi_buf_write_alloc(s, - (7 + 12) * sizeof(unsigned int)); - - /* If not enough memory available, event is set to Comedi Buffer Error */ - if (n > ((7 + 12) * sizeof(unsigned int))) { - printk("\ncomedi_buf_write_alloc n = %i", n); - s->async->events |= COMEDI_CB_ERROR; - } - /* Write all 7 scan values in the comedi buffer */ - 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, - (7 + 12) * sizeof(unsigned int)); - - /* Send events */ - comedi_event(dev, s); - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* */ - /* if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over */ - /* { */ - /* /* buffer rollover */ */ - /* s->async->buf_int_ptr=0; */ - /* comedi_eobuf(dev,s); */ - /* } */ - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - } - /* i_Count++; */ - s_BoardInfos[dev->minor].i_Count++; - } - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - return 0; -} - -static void apci3200_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct addi_private *devpriv = dev->private; - unsigned int ui_StatusRegister = 0; - unsigned int ui_ChannelNumber = 0; - int i_CalibrationFlag = 0; - int i_CJCFlag = 0; - unsigned int ui_DummyValue = 0; - unsigned int ui_DigitalTemperature = 0; - unsigned int ui_DigitalInput = 0; - int i_ConvertCJCCalibration; - /* BEGIN JK TEST */ - int i_ReturnValue = 0; - /* END JK TEST */ - - /* switch(i_ScanType) */ - switch (s_BoardInfos[dev->minor].i_ScanType) { - case 0: - case 1: - /* switch(i_ADDIDATAType) */ - switch (s_BoardInfos[dev->minor].i_ADDIDATAType) { - case 0: - case 1: - - /************************************/ - /*Read the interrupt status register */ - /************************************/ - /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ - ui_StatusRegister = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 16); - if ((ui_StatusRegister & 0x2) == 0x2) { - /* i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17); */ - i_CalibrationFlag = - ((inl(devpriv->iobase + - s_BoardInfos[dev-> - minor]. - i_Offset + - 12) & 0x00060000) >> - 17); - /*************************/ - /*Read the channel number */ - /*************************/ - /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ - - /*************************************/ - /*Read the digital analog input value */ - /*************************************/ - /* ui_DigitalInput = inl(devpriv->iobase+i_Offset + 28); */ - ui_DigitalInput = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - - /***********************************************/ - /* Test if the value read is the channel value */ - /***********************************************/ - if (i_CalibrationFlag == 0) { - /* ui_InterruptChannelValue[i_Count + 0] = ui_DigitalInput; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 0] = ui_DigitalInput; - - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* - i_APCI3200_GetChannelCalibrationValue (dev, s_BoardInfos [dev->minor].ui_Channel_num, - &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 6], - &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 7], - &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 8]); - */ - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /******************************************************/ - /*Start the conversion of the calibration offset value */ - /******************************************************/ - i_APCI3200_ReadCalibrationOffsetValue - (dev, &ui_DummyValue); - } /* if (i_CalibrationFlag == 0) */ - /**********************************************************/ - /* Test if the value read is the calibration offset value */ - /**********************************************************/ - - if (i_CalibrationFlag == 1) { - - /******************/ - /* Save the value */ - /******************/ - - /* ui_InterruptChannelValue[i_Count + 1] = ui_DigitalInput; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 1] = ui_DigitalInput; - - /******************************************************/ - /* Start the conversion of the calibration gain value */ - /******************************************************/ - i_APCI3200_ReadCalibrationGainValue(dev, - &ui_DummyValue); - } /* if (i_CalibrationFlag == 1) */ - /******************************************************/ - /*Test if the value read is the calibration gain value */ - /******************************************************/ - - if (i_CalibrationFlag == 2) { - - /****************/ - /*Save the value */ - /****************/ - /* ui_InterruptChannelValue[i_Count + 2] = ui_DigitalInput; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 2] = ui_DigitalInput; - /* if(i_ScanType==1) */ - if (s_BoardInfos[dev->minor]. - i_ScanType == 1) { - - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor]. - i_InterruptFlag = 0; - /* i_Count=i_Count + 6; */ - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6; */ - s_BoardInfos[dev->minor]. - i_Count = - s_BoardInfos[dev-> - minor].i_Count + 9; - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } /* if(i_ScanType==1) */ - else { - /* i_Count=0; */ - s_BoardInfos[dev->minor]. - i_Count = 0; - } /* elseif(i_ScanType==1) */ - /* if(i_ScanType!=1) */ - if (s_BoardInfos[dev->minor]. - i_ScanType != 1) { - i_ReturnValue = send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* if(i_ScanType!=1) */ - else { - /* if(i_ChannelCount==i_Sum) */ - if (s_BoardInfos[dev->minor]. - i_ChannelCount == - s_BoardInfos[dev-> - minor].i_Sum) { - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } - } /* if(i_ScanType!=1) */ - } /* if (i_CalibrationFlag == 2) */ - } /* if ((ui_StatusRegister & 0x2) == 0x2) */ - - break; - - case 2: - /************************************/ - /*Read the interrupt status register */ - /************************************/ - - /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ - ui_StatusRegister = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 16); - /*************************/ - /*Test if interrupt occur */ - /*************************/ - - if ((ui_StatusRegister & 0x2) == 0x2) { - - /* i_CJCFlag = ((inl(devpriv->iobase+i_Offset + 4) & 0x00000400) >> 10); */ - i_CJCFlag = - ((inl(devpriv->iobase + - s_BoardInfos[dev-> - minor]. - i_Offset + - 4) & 0x00000400) >> 10); - - /* i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17); */ - i_CalibrationFlag = - ((inl(devpriv->iobase + - s_BoardInfos[dev-> - minor]. - i_Offset + - 12) & 0x00060000) >> - 17); - - /*************************/ - /*Read the channel number */ - /*************************/ - - /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ - ui_ChannelNumber = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 24); - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - s_BoardInfos[dev->minor].ui_Channel_num = - ui_ChannelNumber; - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /************************************/ - /*Read the digital temperature value */ - /************************************/ - /* ui_DigitalTemperature = inl(devpriv->iobase+i_Offset + 28); */ - ui_DigitalTemperature = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - - /*********************************************/ - /*Test if the value read is the channel value */ - /*********************************************/ - - if ((i_CalibrationFlag == 0) - && (i_CJCFlag == 0)) { - /* ui_InterruptChannelValue[i_Count + 0]=ui_DigitalTemperature; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 0] = - ui_DigitalTemperature; - - /*********************************/ - /*Start the conversion of the CJC */ - /*********************************/ - i_APCI3200_ReadCJCValue(dev, - &ui_DummyValue); - - } /* if ((i_CalibrationFlag == 0) && (i_CJCFlag == 0)) */ - - /*****************************************/ - /*Test if the value read is the CJC value */ - /*****************************************/ - - if ((i_CJCFlag == 1) - && (i_CalibrationFlag == 0)) { - /* ui_InterruptChannelValue[i_Count + 3]=ui_DigitalTemperature; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 3] = - ui_DigitalTemperature; - - /******************************************************/ - /*Start the conversion of the calibration offset value */ - /******************************************************/ - i_APCI3200_ReadCalibrationOffsetValue - (dev, &ui_DummyValue); - } /* if ((i_CJCFlag == 1) && (i_CalibrationFlag == 0)) */ - - /********************************************************/ - /*Test if the value read is the calibration offset value */ - /********************************************************/ - - if ((i_CalibrationFlag == 1) - && (i_CJCFlag == 0)) { - /* ui_InterruptChannelValue[i_Count + 1]=ui_DigitalTemperature; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 1] = - ui_DigitalTemperature; - - /****************************************************/ - /*Start the conversion of the calibration gain value */ - /****************************************************/ - i_APCI3200_ReadCalibrationGainValue(dev, - &ui_DummyValue); - - } /* if ((i_CalibrationFlag == 1) && (i_CJCFlag == 0)) */ - - /******************************************************/ - /*Test if the value read is the calibration gain value */ - /******************************************************/ - - if ((i_CalibrationFlag == 2) - && (i_CJCFlag == 0)) { - /* ui_InterruptChannelValue[i_Count + 2]=ui_DigitalTemperature; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 2] = - ui_DigitalTemperature; - - /**********************************************************/ - /*Test if the Calibration channel must be read for the CJC */ - /**********************************************************/ - - /*Test if the polarity is the same */ - /**********************************/ - /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ - if (s_BoardInfos[dev->minor]. - i_CJCPolarity != - s_BoardInfos[dev->minor]. - i_ADDIDATAPolarity) { - i_ConvertCJCCalibration = 1; - } /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ - else { - /* if(i_CJCGain==i_ADDIDATAGain) */ - if (s_BoardInfos[dev->minor]. - i_CJCGain == - s_BoardInfos[dev-> - minor]. - i_ADDIDATAGain) { - i_ConvertCJCCalibration - = 0; - } /* if(i_CJCGain==i_ADDIDATAGain) */ - else { - i_ConvertCJCCalibration - = 1; - } /* elseif(i_CJCGain==i_ADDIDATAGain) */ - } /* elseif(i_CJCPolarity!=i_ADDIDATAPolarity) */ - if (i_ConvertCJCCalibration == 1) { - /****************************************************************/ - /*Start the conversion of the calibration gain value for the CJC */ - /****************************************************************/ - i_APCI3200_ReadCJCCalOffset(dev, - &ui_DummyValue); - - } /* if(i_ConvertCJCCalibration==1) */ - else { - /* ui_InterruptChannelValue[i_Count + 4]=0; */ - /* ui_InterruptChannelValue[i_Count + 5]=0; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev-> - minor].i_Count + - 4] = 0; - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev-> - minor].i_Count + - 5] = 0; - } /* elseif(i_ConvertCJCCalibration==1) */ - } /* else if ((i_CalibrationFlag == 2) && (i_CJCFlag == 0)) */ - - /********************************************************************/ - /*Test if the value read is the calibration offset value for the CJC */ - /********************************************************************/ - - if ((i_CalibrationFlag == 1) - && (i_CJCFlag == 1)) { - /* ui_InterruptChannelValue[i_Count + 4]=ui_DigitalTemperature; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 4] = - ui_DigitalTemperature; - - /****************************************************************/ - /*Start the conversion of the calibration gain value for the CJC */ - /****************************************************************/ - i_APCI3200_ReadCJCCalGain(dev, - &ui_DummyValue); - - } /* if ((i_CalibrationFlag == 1) && (i_CJCFlag == 1)) */ - - /******************************************************************/ - /*Test if the value read is the calibration gain value for the CJC */ - /******************************************************************/ - - if ((i_CalibrationFlag == 2) - && (i_CJCFlag == 1)) { - /* ui_InterruptChannelValue[i_Count + 5]=ui_DigitalTemperature; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue - [s_BoardInfos[dev->minor]. - i_Count + 5] = - ui_DigitalTemperature; - - /* if(i_ScanType==1) */ - if (s_BoardInfos[dev->minor]. - i_ScanType == 1) { - - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor]. - i_InterruptFlag = 0; - /* i_Count=i_Count + 6; */ - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6; */ - s_BoardInfos[dev->minor]. - i_Count = - s_BoardInfos[dev-> - minor].i_Count + 9; - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } /* if(i_ScanType==1) */ - else { - /* i_Count=0; */ - s_BoardInfos[dev->minor]. - i_Count = 0; - } /* elseif(i_ScanType==1) */ - - /* if(i_ScanType!=1) */ - if (s_BoardInfos[dev->minor]. - i_ScanType != 1) { - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* if(i_ScanType!=1) */ - else { - /* if(i_ChannelCount==i_Sum) */ - if (s_BoardInfos[dev->minor]. - i_ChannelCount == - s_BoardInfos[dev-> - minor].i_Sum) { - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - - } /* if(i_ChannelCount==i_Sum) */ - } /* else if(i_ScanType!=1) */ - } /* if ((i_CalibrationFlag == 2) && (i_CJCFlag == 1)) */ - - } /* else if ((ui_StatusRegister & 0x2) == 0x2) */ - break; - } /* switch(i_ADDIDATAType) */ - break; - case 2: - case 3: - i_APCI3200_InterruptHandleEos(dev); - break; - } /* switch(i_ScanType) */ - return; -} diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c deleted file mode 100644 index af70c8401880..000000000000 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ /dev/null @@ -1,77 +0,0 @@ -#include <linux/module.h> -#include <linux/pci.h> - -#include "../comedidev.h" -#include "comedi_fc.h" -#include "amcc_s5933.h" - -#include "addi-data/addi_common.h" - -#define ADDIDATA_WATCHDOG 2 /* Or shold it be something else */ - -#include "addi-data/addi_eeprom.c" -#include "addi-data/hwdrv_apci035.c" -#include "addi-data/addi_common.c" - -static const struct addi_board apci035_boardtypes[] = { - { - .pc_DriverName = "apci035", - .i_IorangeBase1 = APCI035_ADDRESS_RANGE, - .i_PCIEeprom = 1, - .pc_EepromChip = "S5920", - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_AiMaxdata = 0xff, - .pr_AiRangelist = &range_apci035_ai, - .i_Timer = 1, - .ui_MinAcquisitiontimeNs = 10000, - .ui_MinDelaytimeNs = 100000, - .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, - }, -}; - -static int apci035_auto_attach(struct comedi_device *dev, - unsigned long context) -{ - dev->board_ptr = &apci035_boardtypes[0]; - - return addi_auto_attach(dev, context); -} - -static struct comedi_driver apci035_driver = { - .driver_name = "addi_apci_035", - .module = THIS_MODULE, - .auto_attach = apci035_auto_attach, - .detach = i_ADDI_Detach, -}; - -static int apci035_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return comedi_pci_auto_config(dev, &apci035_driver, id->driver_data); -} - -static const struct pci_device_id apci035_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x0300) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, apci035_pci_table); - -static struct pci_driver apci035_pci_driver = { - .name = "addi_apci_035", - .id_table = apci035_pci_table, - .probe = apci035_pci_probe, - .remove = comedi_pci_auto_unconfig, -}; -module_comedi_pci_driver(apci035_driver, apci035_pci_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 840cb289507a..bf14165297b7 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -258,9 +258,8 @@ 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, s->state); - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(dev, s); + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); /* enable the interrupt */ outl(ctrl, dev->iobase + APCI1032_CTRL_REG); diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index b7a284ac6649..30b132c3d092 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -1,54 +1,109 @@ #include <linux/module.h> #include <linux/pci.h> +#include <linux/sched.h> +#include <linux/interrupt.h> #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" -#include "addi-data/addi_common.h" +struct apci1500_private { + int iobase; + int i_IobaseAmcc; + int i_IobaseAddon; + int i_IobaseReserved; + unsigned char b_OutputMemoryStatus; + struct task_struct *tsk_Current; +}; -#include "addi-data/addi_eeprom.c" #include "addi-data/hwdrv_apci1500.c" -#include "addi-data/addi_common.c" - -static const struct addi_board apci1500_boardtypes[] = { - { - .pc_DriverName = "apci1500", - .i_IorangeBase1 = APCI1500_ADDRESS_RANGE, - .i_PCIEeprom = 0, - .i_NbrDiChannel = 16, - .i_NbrDoChannel = 16, - .i_DoMaxdata = 0xffff, - .i_Timer = 1, - .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 = 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, - }, -}; static int apci1500_auto_attach(struct comedi_device *dev, unsigned long context) { - dev->board_ptr = &apci1500_boardtypes[0]; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct apci1500_private *devpriv; + struct comedi_subdevice *s; + int ret; + + 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->iobase = dev->iobase; + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); + devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, apci1500_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; - return addi_auto_attach(dev, context); + /* Allocate and Initialise DI Subdevice Structures */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = apci1500_di_config; + s->insn_read = apci1500_di_read; + s->insn_write = apci1500_di_write; + s->insn_bits = apci1500_di_insn_bits; + + /* Allocate and Initialise DO Subdevice Structures */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = apci1500_do_config; + s->insn_write = apci1500_do_write; + s->insn_bits = apci1500_do_bits; + + /* Allocate and Initialise Timer Subdevice Structures */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_write = apci1500_timer_write; + s->insn_read = apci1500_timer_read; + s->insn_config = apci1500_timer_config; + s->insn_bits = apci1500_timer_bits; + + apci1500_reset(dev); + + return 0; +} + +static void apci1500_detach(struct comedi_device *dev) +{ + if (dev->iobase) + apci1500_reset(dev); + comedi_pci_detach(dev); } static struct comedi_driver apci1500_driver = { .driver_name = "addi_apci_1500", .module = THIS_MODULE, .auto_attach = apci1500_auto_attach, - .detach = i_ADDI_Detach, + .detach = apci1500_detach, }; static int apci1500_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index 55d00fd94c91..d8410415cc90 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -163,7 +163,7 @@ static int apci1516_auto_attach(struct comedi_device *dev, s = &dev->subdevices[1]; if (this_board->do_nchan) { s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = this_board->do_nchan; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 688b015a834e..6872b69da5db 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -28,16 +28,91 @@ #include "../comedidev.h" #include "comedi_fc.h" -#include "amcc_s5933.h" +#include "addi_tcw.h" #include "addi_watchdog.h" +/* + * PCI BAR 0 + * + * PLD Revision 1.0 I/O Mapping + * 0x00 93C76 EEPROM + * 0x04 - 0x18 Timer 12-Bit + * + * PLD Revision 2.x I/O Mapping + * 0x00 93C76 EEPROM + * 0x04 - 0x14 Digital Input + * 0x18 - 0x25 Digital Output + * 0x28 - 0x44 Watchdog 8-Bit + * 0x48 - 0x64 Timer 12-Bit + */ +#define APCI1564_EEPROM_REG 0x00 +#define APCI1564_EEPROM_VCC_STATUS (1 << 8) +#define APCI1564_EEPROM_TO_REV(x) (((x) >> 4) & 0xf) +#define APCI1564_EEPROM_DI (1 << 3) +#define APCI1564_EEPROM_DO (1 << 2) +#define APCI1564_EEPROM_CS (1 << 1) +#define APCI1564_EEPROM_CLK (1 << 0) +#define APCI1564_REV1_TIMER_IOBASE 0x04 +#define APCI1564_REV2_MAIN_IOBASE 0x04 +#define APCI1564_REV2_TIMER_IOBASE 0x48 + +/* + * PCI BAR 1 + * + * PLD Revision 1.0 I/O Mapping + * 0x00 - 0x10 Digital Input + * 0x14 - 0x20 Digital Output + * 0x24 - 0x3c Watchdog 8-Bit + * + * PLD Revision 2.x I/O Mapping + * 0x00 Counter_0 + * 0x20 Counter_1 + * 0x30 Counter_3 + */ +#define APCI1564_REV1_MAIN_IOBASE 0x00 + +/* + * dev->iobase Register Map + * PLD Revision 1.0 - PCI BAR 1 + 0x00 + * PLD Revision 2.x - PCI BAR 0 + 0x04 + */ +#define APCI1564_DI_REG 0x00 +#define APCI1564_DI_INT_MODE1_REG 0x04 +#define APCI1564_DI_INT_MODE2_REG 0x08 +#define APCI1564_DI_INT_STATUS_REG 0x0c +#define APCI1564_DI_IRQ_REG 0x10 +#define APCI1564_DO_REG 0x14 +#define APCI1564_DO_INT_CTRL_REG 0x18 +#define APCI1564_DO_INT_STATUS_REG 0x1c +#define APCI1564_DO_IRQ_REG 0x20 +#define APCI1564_WDOG_REG 0x24 +#define APCI1564_WDOG_RELOAD_REG 0x28 +#define APCI1564_WDOG_TIMEBASE_REG 0x2c +#define APCI1564_WDOG_CTRL_REG 0x30 +#define APCI1564_WDOG_STATUS_REG 0x34 +#define APCI1564_WDOG_IRQ_REG 0x38 +#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x3c +#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x40 + +/* + * devpriv->timer Register Map (see addi_tcw.h for register/bit defines) + * PLD Revision 1.0 - PCI BAR 0 + 0x04 + * PLD Revision 2.x - PCI BAR 0 + 0x48 + */ + +/* + * devpriv->counters Register Map (see addi_tcw.h for register/bit defines) + * PLD Revision 2.x - PCI BAR 1 + 0x00 + */ +#define APCI1564_COUNTER(x) ((x) * 0x20) + struct apci1564_private { - unsigned int amcc_iobase; /* base of AMCC I/O registers */ + unsigned long eeprom; /* base address of EEPROM register */ + unsigned long timer; /* base address of 12-bit timer */ + unsigned long counters; /* base address of 32-bit counters */ unsigned int mode1; /* riding-edge/high level channels */ unsigned int mode2; /* falling-edge/low level channels */ unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ - unsigned char timer_select_mode; - unsigned char mode_select_register; struct task_struct *tsk_current; }; @@ -48,27 +123,30 @@ static int apci1564_reset(struct comedi_device *dev) struct apci1564_private *devpriv = dev->private; /* Disable the input interrupts and reset status register */ - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); - inl(devpriv->amcc_iobase + APCI1564_DI_INT_STATUS_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + inl(dev->iobase + APCI1564_DI_INT_STATUS_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG); /* Reset the output channels and disable interrupts */ - outl(0x0, devpriv->amcc_iobase + APCI1564_DO_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DO_INT_CTRL_REG); + outl(0x0, dev->iobase + APCI1564_DO_REG); + outl(0x0, dev->iobase + APCI1564_DO_INT_CTRL_REG); /* Reset the watchdog registers */ - addi_watchdog_reset(devpriv->amcc_iobase + APCI1564_WDOG_REG); + addi_watchdog_reset(dev->iobase + APCI1564_WDOG_REG); /* Reset the timer registers */ - outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_RELOAD_REG); + outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); + outl(0x0, devpriv->timer + ADDI_TCW_RELOAD_REG); + + if (devpriv->counters) { + unsigned long iobase = devpriv->counters + ADDI_TCW_CTRL_REG; - /* Reset the counter registers */ - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER1)); - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER2)); - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER3)); - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER4)); + /* Reset the counter registers */ + outl(0x0, iobase + APCI1564_COUNTER(0)); + outl(0x0, iobase + APCI1564_COUNTER(1)); + outl(0x0, iobase + APCI1564_COUNTER(2)); + } return 0; } @@ -82,55 +160,52 @@ static irqreturn_t apci1564_interrupt(int irq, void *d) unsigned int ctrl; unsigned int chan; - /* check interrupt is from this device */ - if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) & - INTCSR_INTR_ASSERTED) == 0) - return IRQ_NONE; - - status = inl(devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + status = inl(dev->iobase + APCI1564_DI_IRQ_REG); if (status & APCI1564_DI_INT_ENABLE) { /* disable the interrupt */ outl(status & APCI1564_DI_INT_DISABLE, - devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + dev->iobase + APCI1564_DI_IRQ_REG); - s->state = inl(dev->iobase + APCI1564_DI_INT_STATUS_REG) - & 0xffff; - comedi_buf_put(s, s->state); - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(dev, s); + s->state = inl(dev->iobase + APCI1564_DI_INT_STATUS_REG) & + 0xffff; + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); /* enable the interrupt */ - outl(status, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + outl(status, dev->iobase + APCI1564_DI_IRQ_REG); } - status = inl(devpriv->amcc_iobase + APCI1564_TIMER_IRQ_REG); + status = inl(devpriv->timer + ADDI_TCW_IRQ_REG); if (status & 0x01) { /* Disable Timer Interrupt */ - ctrl = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); + ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); + outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_current, 0); /* Enable Timer Interrupt */ - outl(ctrl, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); + outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); } - for (chan = 0; chan < 4; chan++) { - status = inl(dev->iobase + APCI1564_COUNTER_IRQ_REG(chan)); - if (status & 0x01) { - /* Disable Counter Interrupt */ - ctrl = inl(dev->iobase + - APCI1564_COUNTER_CTRL_REG(chan)); - outl(0x0, dev->iobase + - APCI1564_COUNTER_CTRL_REG(chan)); - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_current, 0); - - /* Enable Counter Interrupt */ - outl(ctrl, dev->iobase + - APCI1564_COUNTER_CTRL_REG(chan)); + if (devpriv->counters) { + for (chan = 0; chan < 4; chan++) { + unsigned long iobase; + + iobase = devpriv->counters + APCI1564_COUNTER(chan); + + status = inl(iobase + ADDI_TCW_IRQ_REG); + if (status & 0x01) { + /* Disable Counter Interrupt */ + ctrl = inl(iobase + ADDI_TCW_CTRL_REG); + outl(0x0, iobase + ADDI_TCW_CTRL_REG); + + /* Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_current, 0); + + /* Enable Counter Interrupt */ + outl(ctrl, iobase + ADDI_TCW_CTRL_REG); + } } } @@ -142,9 +217,7 @@ static int apci1564_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct apci1564_private *devpriv = dev->private; - - data[1] = inl(devpriv->amcc_iobase + APCI1564_DI_REG); + data[1] = inl(dev->iobase + APCI1564_DI_REG); return insn->n; } @@ -154,12 +227,10 @@ static int apci1564_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct apci1564_private *devpriv = dev->private; - - s->state = inl(devpriv->amcc_iobase + APCI1564_DO_REG); + s->state = inl(dev->iobase + APCI1564_DO_REG); if (comedi_dio_update_state(s, data)) - outl(s->state, devpriv->amcc_iobase + APCI1564_DO_REG); + outl(s->state, dev->iobase + APCI1564_DO_REG); data[1] = s->state; @@ -171,9 +242,7 @@ static int apci1564_diag_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct apci1564_private *devpriv = dev->private; - - data[1] = inl(devpriv->amcc_iobase + APCI1564_DO_INT_STATUS_REG) & 3; + data[1] = inl(dev->iobase + APCI1564_DO_INT_STATUS_REG) & 3; return insn->n; } @@ -227,10 +296,10 @@ static int apci1564_cos_insn_config(struct comedi_device *dev, devpriv->ctrl = 0; devpriv->mode1 = 0; devpriv->mode2 = 0; - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); - inl(devpriv->amcc_iobase + APCI1564_DI_INT_STATUS_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + inl(dev->iobase + APCI1564_DI_INT_STATUS_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG); break; case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: if (devpriv->ctrl != (APCI1564_DI_INT_ENABLE | @@ -342,9 +411,9 @@ static int apci1564_cos_cmd(struct comedi_device *dev, return -EINVAL; } - outl(devpriv->mode1, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(devpriv->mode2, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); - outl(devpriv->ctrl, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + outl(devpriv->mode1, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(devpriv->mode2, dev->iobase + APCI1564_DI_INT_MODE2_REG); + outl(devpriv->ctrl, dev->iobase + APCI1564_DI_IRQ_REG); return 0; } @@ -352,12 +421,10 @@ static int apci1564_cos_cmd(struct comedi_device *dev, static int apci1564_cos_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct apci1564_private *devpriv = dev->private; - - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); - inl(devpriv->amcc_iobase + APCI1564_DI_INT_STATUS_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + inl(dev->iobase + APCI1564_DI_INT_STATUS_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG); return 0; } @@ -368,6 +435,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct apci1564_private *devpriv; struct comedi_subdevice *s; + unsigned int val; int ret; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); @@ -378,8 +446,20 @@ static int apci1564_auto_attach(struct comedi_device *dev, if (ret) return ret; - dev->iobase = pci_resource_start(pcidev, 1); - devpriv->amcc_iobase = pci_resource_start(pcidev, 0); + /* read the EEPROM register and check the I/O map revision */ + devpriv->eeprom = pci_resource_start(pcidev, 0); + val = inl(devpriv->eeprom + APCI1564_EEPROM_REG); + if (APCI1564_EEPROM_TO_REV(val) == 0) { + /* PLD Revision 1.0 I/O Mapping */ + dev->iobase = pci_resource_start(pcidev, 1) + + APCI1564_REV1_MAIN_IOBASE; + devpriv->timer = devpriv->eeprom + APCI1564_REV1_TIMER_IOBASE; + } else { + /* PLD Revision 2.x I/O Mapping */ + dev->iobase = devpriv->eeprom + APCI1564_REV2_MAIN_IOBASE; + devpriv->timer = devpriv->eeprom + APCI1564_REV2_TIMER_IOBASE; + devpriv->counters = pci_resource_start(pcidev, 1); + } apci1564_reset(dev); @@ -390,7 +470,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, dev->irq = pcidev->irq; } - ret = comedi_alloc_subdevices(dev, 6); + ret = comedi_alloc_subdevices(dev, 7); if (ret) return ret; @@ -406,7 +486,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, /* Allocate and Initialise DO Subdevice Structures */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 32; s->maxdata = 1; s->range_table = &range_digital; @@ -431,26 +511,40 @@ static int apci1564_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - /* Allocate and Initialise Timer Subdevice Structures */ + /* Timer subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; + s->maxdata = 0x0fff; s->range_table = &range_digital; - s->insn_write = apci1564_timer_write; - s->insn_read = apci1564_timer_read; - s->insn_config = apci1564_timer_config; + s->insn_config = apci1564_timer_insn_config; + s->insn_write = apci1564_timer_insn_write; + s->insn_read = apci1564_timer_insn_read; - /* Initialize the watchdog subdevice */ + /* Counter subdevice */ s = &dev->subdevices[4]; - ret = addi_watchdog_init(s, devpriv->amcc_iobase + APCI1564_WDOG_REG); + if (devpriv->counters) { + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; + s->n_chan = 3; + s->maxdata = 0xffffffff; + s->range_table = &range_digital; + s->insn_config = apci1564_counter_insn_config; + s->insn_write = apci1564_counter_insn_write; + s->insn_read = apci1564_counter_insn_read; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Initialize the watchdog subdevice */ + s = &dev->subdevices[5]; + ret = addi_watchdog_init(s, dev->iobase + APCI1564_WDOG_REG); if (ret) return ret; /* Initialize the diagnostic status subdevice */ - s = &dev->subdevices[5]; + s = &dev->subdevices[6]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 2; diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index 4162e2dc2860..a1248dab369f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -140,7 +140,7 @@ static int apci16xx_auto_attach(struct comedi_device *dev, for (i = 0; i < n_subdevs; i++) { s = &dev->subdevices[i]; s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_WRITEABLE | SDF_READABLE; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = ((i * 32) < board->n_chan) ? 32 : last; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index aea3da325359..eebf4f151b39 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -47,7 +47,6 @@ struct apci2032_int_private { spinlock_t spinlock; - unsigned int stop_count; bool active; unsigned char enabled_isns; }; @@ -148,7 +147,6 @@ static int apci2032_int_cmd(struct comedi_device *dev, spin_lock_irqsave(&subpriv->spinlock, flags); subpriv->enabled_isns = enabled_isns; - subpriv->stop_count = cmd->stop_arg; subpriv->active = true; outl(enabled_isns, dev->iobase + APCI2032_INT_CTRL_REG); @@ -178,7 +176,6 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) struct comedi_cmd *cmd = &s->async->cmd; struct apci2032_int_private *subpriv; unsigned int val; - bool do_event = false; if (!dev->attached) return IRQ_NONE; @@ -212,27 +209,16 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) bits |= (1 << i); } - if (comedi_buf_put(s, bits)) { - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (cmd->stop_src == TRIG_COUNT && - subpriv->stop_count > 0) { - subpriv->stop_count--; - if (subpriv->stop_count == 0) { - /* end of acquisition */ - s->async->events |= COMEDI_CB_EOA; - apci2032_int_stop(dev, s); - } - } - } else { - apci2032_int_stop(dev, s); - s->async->events |= COMEDI_CB_OVERFLOW; - } - do_event = true; + comedi_buf_write_samples(s, &bits, 1); + + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) + s->async->events |= COMEDI_CB_EOA; } spin_unlock(&subpriv->spinlock); - if (do_event) - comedi_event(dev, s); + + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -274,7 +260,7 @@ static int apci2032_auto_attach(struct comedi_device *dev, /* Initialize the digital output subdevice */ s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 32; s->maxdata = 1; s->range_table = &range_digital; @@ -303,7 +289,7 @@ static int apci2032_auto_attach(struct comedi_device *dev, return -ENOMEM; spin_lock_init(&subpriv->spinlock); s->private = subpriv; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_PACKED; s->len_chanlist = 2; s->do_cmdtest = apci2032_int_cmdtest; s->do_cmd = apci2032_int_cmd; diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index 51ab1f937bae..1f9d13661ac9 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -98,7 +98,7 @@ static int apci2200_auto_attach(struct comedi_device *dev, /* Initialize the digital output subdevice */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index ba71e24a56fd..c65f9407fd06 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -1,70 +1,993 @@ +/* + * addi_apci_3120.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + #include <linux/module.h> #include <linux/pci.h> +#include <linux/interrupt.h> #include "../comedidev.h" #include "comedi_fc.h" #include "amcc_s5933.h" -#include "addi-data/addi_common.h" +/* + * PCI BAR 0 register map (devpriv->amcc) + * see amcc_s5933.h for register and bit defines + */ +#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 (1 << 29) + +/* + * PCI BAR 1 register map (dev->iobase) + */ +#define APCI3120_AI_FIFO_REG 0x00 +#define APCI3120_CTRL_REG 0x00 +#define APCI3120_CTRL_EXT_TRIG (1 << 15) +#define APCI3120_CTRL_GATE(x) (1 << (12 + (x))) +#define APCI3120_CTRL_PR(x) (((x) & 0xf) << 8) +#define APCI3120_CTRL_PA(x) (((x) & 0xf) << 0) +#define APCI3120_AI_SOFTTRIG_REG 0x02 +#define APCI3120_STATUS_REG 0x02 +#define APCI3120_STATUS_EOC_INT (1 << 15) +#define APCI3120_STATUS_AMCC_INT (1 << 14) +#define APCI3120_STATUS_EOS_INT (1 << 13) +#define APCI3120_STATUS_TIMER2_INT (1 << 12) +#define APCI3120_STATUS_INT_MASK (0xf << 12) +#define APCI3120_STATUS_TO_DI_BITS(x) (((x) >> 8) & 0xf) +#define APCI3120_STATUS_TO_VERSION(x) (((x) >> 4) & 0xf) +#define APCI3120_STATUS_FIFO_FULL (1 << 2) +#define APCI3120_STATUS_FIFO_EMPTY (1 << 1) +#define APCI3120_STATUS_DA_READY (1 << 0) +#define APCI3120_TIMER_REG 0x04 +#define APCI3120_CHANLIST_REG 0x06 +#define APCI3120_CHANLIST_INDEX(x) (((x) & 0xf) << 8) +#define APCI3120_CHANLIST_UNIPOLAR (1 << 7) +#define APCI3120_CHANLIST_GAIN(x) (((x) & 0x3) << 4) +#define APCI3120_CHANLIST_MUX(x) (((x) & 0xf) << 0) +#define APCI3120_AO_REG(x) (0x08 + (((x) / 4) * 2)) +#define APCI3120_AO_MUX(x) (((x) & 0x3) << 14) +#define APCI3120_AO_DATA(x) ((x) << 0) +#define APCI3120_TIMER_MODE_REG 0x0c +#define APCI3120_TIMER_MODE(_t, _m) ((_m) << ((_t) * 2)) +#define APCI3120_TIMER_MODE0 0 /* I8254_MODE0 */ +#define APCI3120_TIMER_MODE2 1 /* I8254_MODE2 */ +#define APCI3120_TIMER_MODE4 2 /* I8254_MODE4 */ +#define APCI3120_TIMER_MODE5 3 /* I8254_MODE5 */ +#define APCI3120_TIMER_MODE_MASK(_t) (3 << ((_t) * 2)) +#define APCI3120_CTR0_REG 0x0d +#define APCI3120_CTR0_DO_BITS(x) ((x) << 4) +#define APCI3120_CTR0_TIMER_SEL(x) ((x) << 0) +#define APCI3120_MODE_REG 0x0e +#define APCI3120_MODE_TIMER2_CLK_OSC (0 << 6) +#define APCI3120_MODE_TIMER2_CLK_OUT1 (1 << 6) +#define APCI3120_MODE_TIMER2_CLK_EOC (2 << 6) +#define APCI3120_MODE_TIMER2_CLK_EOS (3 << 6) +#define APCI3120_MODE_TIMER2_CLK_MASK (3 << 6) +#define APCI3120_MODE_TIMER2_AS_TIMER (0 << 4) +#define APCI3120_MODE_TIMER2_AS_COUNTER (1 << 4) +#define APCI3120_MODE_TIMER2_AS_WDOG (2 << 4) +#define APCI3120_MODE_TIMER2_AS_MASK (3 << 4) /* sets AS_TIMER */ +#define APCI3120_MODE_SCAN_ENA (1 << 3) +#define APCI3120_MODE_TIMER2_IRQ_ENA (1 << 2) +#define APCI3120_MODE_EOS_IRQ_ENA (1 << 1) +#define APCI3120_MODE_EOC_IRQ_ENA (1 << 0) + +/* + * PCI BAR 2 register map (devpriv->addon) + */ +#define APCI3120_ADDON_ADDR_REG 0x00 +#define APCI3120_ADDON_DATA_REG 0x02 +#define APCI3120_ADDON_CTRL_REG 0x04 +#define APCI3120_ADDON_CTRL_AMWEN_ENA (1 << 1) +#define APCI3120_ADDON_CTRL_A2P_FIFO_ENA (1 << 0) -#include "addi-data/hwdrv_apci3120.c" +/* + * Board revisions + */ +#define APCI3120_REVA 0xa +#define APCI3120_REVB 0xb +#define APCI3120_REVA_OSC_BASE 70 /* 70ns = 14.29MHz */ +#define APCI3120_REVB_OSC_BASE 50 /* 50ns = 20MHz */ + +static const struct comedi_lrange apci3120_ai_range = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1) + } +}; enum apci3120_boardid { BOARD_APCI3120, BOARD_APCI3001, }; -static const struct addi_board apci3120_boardtypes[] = { +struct apci3120_board { + const char *name; + unsigned int ai_is_16bit:1; + unsigned int has_ao:1; +}; + +static const struct apci3120_board apci3120_boardtypes[] = { [BOARD_APCI3120] = { - .pc_DriverName = "apci3120", - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_NbrAoChannel = 8, - .i_AiMaxdata = 0xffff, - .i_AoMaxdata = 0x3fff, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 0x0f, - .interrupt = apci3120_interrupt, + .name = "apci3120", + .ai_is_16bit = 1, + .has_ao = 1, }, [BOARD_APCI3001] = { - .pc_DriverName = "apci3001", - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_AiMaxdata = 0xfff, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .i_DoMaxdata = 0x0f, - .interrupt = apci3120_interrupt, + .name = "apci3001", }, }; -static irqreturn_t v_ADDI_Interrupt(int irq, void *d) +struct apci3120_dmabuf { + unsigned short *virt; + dma_addr_t hw; + unsigned int size; + unsigned int use_size; +}; + +struct apci3120_private { + unsigned long amcc; + unsigned long addon; + unsigned int osc_base; + unsigned int use_dma:1; + unsigned int use_double_buffer:1; + unsigned int cur_dmabuf:1; + struct apci3120_dmabuf dmabuf[2]; + unsigned char do_bits; + unsigned char timer_mode; + unsigned char mode; + unsigned short ctrl; +}; + +static void apci3120_addon_write(struct comedi_device *dev, + unsigned int val, unsigned int reg) +{ + struct apci3120_private *devpriv = dev->private; + + /* 16-bit interface for AMCC add-on registers */ + + outw(reg, devpriv->addon + APCI3120_ADDON_ADDR_REG); + outw(val & 0xffff, devpriv->addon + APCI3120_ADDON_DATA_REG); + + outw(reg + 2, devpriv->addon + APCI3120_ADDON_ADDR_REG); + outw((val >> 16) & 0xffff, devpriv->addon + APCI3120_ADDON_DATA_REG); +} + +static void apci3120_init_dma(struct comedi_device *dev, + struct apci3120_dmabuf *dmabuf) +{ + struct apci3120_private *devpriv = dev->private; + + /* AMCC - enable transfer count and reset A2P FIFO */ + outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO, + devpriv->amcc + AMCC_OP_REG_AGCSTS); + + /* Add-On - enable transfer count and reset A2P FIFO */ + apci3120_addon_write(dev, AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO, + AMCC_OP_REG_AGCSTS); + + /* AMCC - enable transfers and reset A2P flags */ + outl(RESET_A2P_FLAGS | EN_A2P_TRANSFERS, + devpriv->amcc + AMCC_OP_REG_MCSR); + + /* Add-On - DMA start address */ + apci3120_addon_write(dev, dmabuf->hw, AMCC_OP_REG_AMWAR); + + /* Add-On - Number of acquisitions */ + apci3120_addon_write(dev, dmabuf->use_size, AMCC_OP_REG_AMWTC); + + /* AMCC - enable write complete (DMA) and set FIFO advance */ + outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 | AINT_WRITE_COMPL, + devpriv->amcc + AMCC_OP_REG_INTCSR); + + /* Add-On - enable DMA */ + outw(APCI3120_ADDON_CTRL_AMWEN_ENA | APCI3120_ADDON_CTRL_A2P_FIFO_ENA, + devpriv->addon + APCI3120_ADDON_CTRL_REG); +} + +static void apci3120_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci3120_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + struct apci3120_dmabuf *dmabuf0 = &devpriv->dmabuf[0]; + struct apci3120_dmabuf *dmabuf1 = &devpriv->dmabuf[1]; + unsigned int dmalen0 = dmabuf0->size; + unsigned int dmalen1 = dmabuf1->size; + unsigned int scan_bytes; + + scan_bytes = comedi_samples_to_bytes(s, cmd->scan_end_arg); + + 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 (cmd->flags & CMDF_WAKE_EOS) { + /* don't we want wake up every scan? */ + if (dmalen0 > scan_bytes) { + dmalen0 = scan_bytes; + if (cmd->scan_end_arg & 1) + dmalen0 += 2; + } + 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 > s->async->prealloc_bufsz) + dmalen0 = s->async->prealloc_bufsz; + if (dmalen1 > s->async->prealloc_bufsz) + dmalen1 = s->async->prealloc_bufsz; + } + dmabuf0->use_size = dmalen0; + dmabuf1->use_size = dmalen1; + + apci3120_init_dma(dev, dmabuf0); +} + +/* + * There are three timers on the board. They all use the same base + * clock with a fixed prescaler for each timer. The base clock used + * depends on the board version and type. + * + * APCI-3120 Rev A boards OSC = 14.29MHz base clock (~70ns) + * APCI-3120 Rev B boards OSC = 20MHz base clock (50ns) + * APCI-3001 boards OSC = 20MHz base clock (50ns) + * + * The prescalers for each timer are: + * Timer 0 CLK = OSC/10 + * Timer 1 CLK = OSC/1000 + * Timer 2 CLK = OSC/1000 + */ +static unsigned int apci3120_ns_to_timer(struct comedi_device *dev, + unsigned int timer, + unsigned int ns, + unsigned int flags) +{ + struct apci3120_private *devpriv = dev->private; + unsigned int prescale = (timer == 0) ? 10 : 1000; + unsigned int timer_base = devpriv->osc_base * prescale; + unsigned int divisor; + + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_UP: + divisor = DIV_ROUND_UP(ns, timer_base); + break; + case CMDF_ROUND_DOWN: + divisor = ns / timer_base; + break; + case CMDF_ROUND_NEAREST: + default: + divisor = DIV_ROUND_CLOSEST(ns, timer_base); + break; + } + + if (timer == 2) { + /* timer 2 is 24-bits */ + if (divisor > 0x00ffffff) + divisor = 0x00ffffff; + } else { + /* timers 0 and 1 are 16-bits */ + if (divisor > 0xffff) + divisor = 0xffff; + } + /* the timers require a minimum divisor of 2 */ + if (divisor < 2) + divisor = 2; + + return divisor; +} + +static void apci3120_clr_timer2_interrupt(struct comedi_device *dev) +{ + /* a dummy read of APCI3120_CTR0_REG clears the timer 2 interrupt */ + inb(dev->iobase + APCI3120_CTR0_REG); +} + +static void apci3120_timer_write(struct comedi_device *dev, + unsigned int timer, unsigned int val) +{ + struct apci3120_private *devpriv = dev->private; + + /* write 16-bit value to timer (lower 16-bits of timer 2) */ + outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) | + APCI3120_CTR0_TIMER_SEL(timer), + dev->iobase + APCI3120_CTR0_REG); + outw(val & 0xffff, dev->iobase + APCI3120_TIMER_REG); + + if (timer == 2) { + /* write upper 16-bits to timer 2 */ + outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) | + APCI3120_CTR0_TIMER_SEL(timer + 1), + dev->iobase + APCI3120_CTR0_REG); + outw((val >> 16) & 0xffff, dev->iobase + APCI3120_TIMER_REG); + } +} + +static unsigned int apci3120_timer_read(struct comedi_device *dev, + unsigned int timer) +{ + struct apci3120_private *devpriv = dev->private; + unsigned int val; + + /* read 16-bit value from timer (lower 16-bits of timer 2) */ + outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) | + APCI3120_CTR0_TIMER_SEL(timer), + dev->iobase + APCI3120_CTR0_REG); + val = inw(dev->iobase + APCI3120_TIMER_REG); + + if (timer == 2) { + /* read upper 16-bits from timer 2 */ + outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) | + APCI3120_CTR0_TIMER_SEL(timer + 1), + dev->iobase + APCI3120_CTR0_REG); + val |= (inw(dev->iobase + APCI3120_TIMER_REG) << 16); + } + + return val; +} + +static void apci3120_timer_set_mode(struct comedi_device *dev, + unsigned int timer, unsigned int mode) +{ + struct apci3120_private *devpriv = dev->private; + + devpriv->timer_mode &= ~APCI3120_TIMER_MODE_MASK(timer); + devpriv->timer_mode |= APCI3120_TIMER_MODE(timer, mode); + outb(devpriv->timer_mode, dev->iobase + APCI3120_TIMER_MODE_REG); +} + +static void apci3120_timer_enable(struct comedi_device *dev, + unsigned int timer, bool enable) +{ + struct apci3120_private *devpriv = dev->private; + + if (enable) + devpriv->ctrl |= APCI3120_CTRL_GATE(timer); + else + devpriv->ctrl &= ~APCI3120_CTRL_GATE(timer); + outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG); +} + +static void apci3120_exttrig_enable(struct comedi_device *dev, bool enable) +{ + struct apci3120_private *devpriv = dev->private; + + if (enable) + devpriv->ctrl |= APCI3120_CTRL_EXT_TRIG; + else + devpriv->ctrl &= ~APCI3120_CTRL_EXT_TRIG; + outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG); +} + +static void apci3120_set_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + int n_chan, unsigned int *chanlist) +{ + struct apci3120_private *devpriv = dev->private; + int i; + + /* set chanlist for scan */ + for (i = 0; i < n_chan; i++) { + unsigned int chan = CR_CHAN(chanlist[i]); + unsigned int range = CR_RANGE(chanlist[i]); + unsigned int val; + + val = APCI3120_CHANLIST_MUX(chan) | + APCI3120_CHANLIST_GAIN(range) | + APCI3120_CHANLIST_INDEX(i); + + if (comedi_range_is_unipolar(s, range)) + val |= APCI3120_CHANLIST_UNIPOLAR; + + outw(val, dev->iobase + APCI3120_CHANLIST_REG); + } + + /* a dummy read of APCI3120_TIMER_MODE_REG resets the ai FIFO */ + inw(dev->iobase + APCI3120_TIMER_MODE_REG); + + /* set scan length (PR) and scan start (PA) */ + devpriv->ctrl = APCI3120_CTRL_PR(n_chan - 1) | APCI3120_CTRL_PA(0); + outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG); + + /* enable chanlist scanning if necessary */ + if (n_chan > 1) + devpriv->mode |= APCI3120_MODE_SCAN_ENA; +} + +static void apci3120_interrupt_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci3120_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + struct apci3120_dmabuf *dmabuf; + unsigned int nbytes; + unsigned int nsamples; + + dmabuf = &devpriv->dmabuf[devpriv->cur_dmabuf]; + + nbytes = dmabuf->use_size - inl(devpriv->amcc + AMCC_OP_REG_MWTC); + + if (nbytes < dmabuf->use_size) + dev_err(dev->class_dev, "Interrupted DMA transfer!\n"); + if (nbytes & 1) { + dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n"); + async->events |= COMEDI_CB_ERROR; + return; + } + + nsamples = comedi_bytes_to_samples(s, nbytes); + if (nsamples) { + comedi_buf_write_samples(s, dmabuf->virt, nsamples); + + if (!(cmd->flags & CMDF_WAKE_EOS)) + async->events |= COMEDI_CB_EOS; + } + + if ((async->events & COMEDI_CB_CANCEL_MASK) || + (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)) + return; + + if (devpriv->use_double_buffer) { + /* switch DMA buffers for next interrupt */ + devpriv->cur_dmabuf = !devpriv->cur_dmabuf; + dmabuf = &devpriv->dmabuf[devpriv->cur_dmabuf]; + apci3120_init_dma(dev, dmabuf); + } else { + /* restart DMA if not using double buffering */ + apci3120_init_dma(dev, dmabuf); + } +} + +static irqreturn_t apci3120_interrupt(int irq, void *d) { struct comedi_device *dev = d; - const struct addi_board *this_board = dev->board_ptr; + struct apci3120_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int status; + unsigned int int_amcc; + + status = inw(dev->iobase + APCI3120_STATUS_REG); + int_amcc = inl(devpriv->amcc + AMCC_OP_REG_INTCSR); + + if (!(status & APCI3120_STATUS_INT_MASK) && + !(int_amcc & ANY_S593X_INT)) { + dev_err(dev->class_dev, "IRQ from unknown source\n"); + return IRQ_NONE; + } + + outl(int_amcc | AINT_INT_MASK, devpriv->amcc + AMCC_OP_REG_INTCSR); - this_board->interrupt(irq, d); - return IRQ_RETVAL(1); + if (devpriv->ctrl & APCI3120_CTRL_EXT_TRIG) + apci3120_exttrig_enable(dev, false); + + if (int_amcc & MASTER_ABORT_INT) + dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n"); + if (int_amcc & TARGET_ABORT_INT) + dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n"); + + if ((status & APCI3120_STATUS_EOC_INT) == 0 && + (devpriv->mode & APCI3120_MODE_EOC_IRQ_ENA)) { + /* nothing to do... EOC mode is not currently used */ + } + + if ((status & APCI3120_STATUS_EOS_INT) && + (devpriv->mode & APCI3120_MODE_EOS_IRQ_ENA)) { + unsigned short val; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + val = inw(dev->iobase + APCI3120_AI_FIFO_REG); + comedi_buf_write_samples(s, &val, 1); + } + + devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA; + outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG); + } + + if (status & APCI3120_STATUS_TIMER2_INT) { + /* + * for safety... + * timer2 interrupts are not enabled in the driver + */ + apci3120_clr_timer2_interrupt(dev); + } + + if (status & APCI3120_STATUS_AMCC_INT) { + /* AMCC- Clear write complete interrupt (DMA) */ + outl(AINT_WT_COMPLETE, devpriv->amcc + AMCC_OP_REG_INTCSR); + + /* do some data transfer */ + apci3120_interrupt_dma(dev, s); + } + + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; + + comedi_handle_events(dev, s); + + return IRQ_HANDLED; +} + +static int apci3120_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci3120_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int divisor; + + /* set default mode bits */ + devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC | + APCI3120_MODE_TIMER2_AS_TIMER; + + /* AMCC- Clear write complete interrupt (DMA) */ + outl(AINT_WT_COMPLETE, devpriv->amcc + AMCC_OP_REG_INTCSR); + + devpriv->cur_dmabuf = 0; + + /* load chanlist for command scan */ + apci3120_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist); + + if (cmd->start_src == TRIG_EXT) + apci3120_exttrig_enable(dev, true); + + if (cmd->scan_begin_src == TRIG_TIMER) { + /* + * Timer 1 is used in MODE2 (rate generator) to set the + * start time for each scan. + */ + divisor = apci3120_ns_to_timer(dev, 1, cmd->scan_begin_arg, + cmd->flags); + apci3120_timer_set_mode(dev, 1, APCI3120_TIMER_MODE2); + apci3120_timer_write(dev, 1, divisor); + } + + /* + * Timer 0 is used in MODE2 (rate generator) to set the conversion + * time for each acquisition. + */ + divisor = apci3120_ns_to_timer(dev, 0, cmd->convert_arg, cmd->flags); + apci3120_timer_set_mode(dev, 0, APCI3120_TIMER_MODE2); + apci3120_timer_write(dev, 0, divisor); + + if (devpriv->use_dma) + apci3120_setup_dma(dev, s); + else + devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA; + + /* set mode to enable acquisition */ + outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG); + + if (cmd->scan_begin_src == TRIG_TIMER) + apci3120_timer_enable(dev, 1, true); + apci3120_timer_enable(dev, 0, true); + + return 0; +} + +static int apci3120_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int arg; + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_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); + + if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */ + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000); + + /* minimum conversion time per sample is 10us */ + 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_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 (cmd->scan_begin_src == TRIG_TIMER) { + /* scan begin must be larger than the scan time */ + 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 channel list if it exists */ + + return 0; +} + +static int apci3120_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci3120_private *devpriv = dev->private; + + /* Add-On - disable DMA */ + outw(0, devpriv->addon + 4); + + /* Add-On - disable bus master */ + apci3120_addon_write(dev, 0, AMCC_OP_REG_AGCSTS); + + /* AMCC - disable bus master */ + outl(0, devpriv->amcc + AMCC_OP_REG_MCSR); + + /* disable all counters, ext trigger, and reset scan */ + devpriv->ctrl = 0; + outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG); + + /* DISABLE_ALL_INTERRUPT */ + devpriv->mode = 0; + outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG); + + inw(dev->iobase + APCI3120_STATUS_REG); + devpriv->cur_dmabuf = 0; + + return 0; +} + +static int apci3120_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + APCI3120_STATUS_REG); + if ((status & APCI3120_STATUS_EOC_INT) == 0) + return 0; + return -EBUSY; +} + +static int apci3120_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3120_private *devpriv = dev->private; + unsigned int divisor; + int ret; + int i; + + /* set mode for A/D conversions by software trigger with timer 0 */ + devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC | + APCI3120_MODE_TIMER2_AS_TIMER; + outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG); + + /* load chanlist for single channel scan */ + apci3120_set_chanlist(dev, s, 1, &insn->chanspec); + + /* + * Timer 0 is used in MODE4 (software triggered strobe) to set the + * conversion time for each acquisition. Each conversion is triggered + * when the divisor is written to the timer, The conversion is done + * when the EOC bit in the status register is '0'. + */ + apci3120_timer_set_mode(dev, 0, APCI3120_TIMER_MODE4); + apci3120_timer_enable(dev, 0, true); + + /* fixed conversion time of 10 us */ + divisor = apci3120_ns_to_timer(dev, 0, 10000, CMDF_ROUND_NEAREST); + + for (i = 0; i < insn->n; i++) { + /* trigger conversion */ + apci3120_timer_write(dev, 0, divisor); + + ret = comedi_timeout(dev, s, insn, apci3120_ai_eoc, 0); + if (ret) + return ret; + + data[i] = inw(dev->iobase + APCI3120_AI_FIFO_REG); + } + + return insn->n; +} + +static int apci3120_ao_ready(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + APCI3120_STATUS_REG); + if (status & APCI3120_STATUS_DA_READY) + return 0; + return -EBUSY; +} + +static int apci3120_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) { + unsigned int val = data[i]; + int ret; + + ret = comedi_timeout(dev, s, insn, apci3120_ao_ready, 0); + if (ret) + return ret; + + outw(APCI3120_AO_MUX(chan) | APCI3120_AO_DATA(val), + dev->iobase + APCI3120_AO_REG(chan)); + + s->readback[chan] = val; + } + + return insn->n; +} + +static int apci3120_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int status; + + status = inw(dev->iobase + APCI3120_STATUS_REG); + data[1] = APCI3120_STATUS_TO_DI_BITS(status); + + return insn->n; +} + +static int apci3120_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3120_private *devpriv = dev->private; + + if (comedi_dio_update_state(s, data)) { + devpriv->do_bits = s->state; + outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits), + dev->iobase + APCI3120_CTR0_REG); + } + + data[1] = s->state; + + return insn->n; +} + +static int apci3120_timer_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3120_private *devpriv = dev->private; + unsigned int divisor; + unsigned int status; + unsigned int mode; + unsigned int timer_mode; + + switch (data[0]) { + case INSN_CONFIG_ARM: + apci3120_clr_timer2_interrupt(dev); + divisor = apci3120_ns_to_timer(dev, 2, data[1], + CMDF_ROUND_DOWN); + apci3120_timer_write(dev, 2, divisor); + apci3120_timer_enable(dev, 2, true); + break; + + case INSN_CONFIG_DISARM: + apci3120_timer_enable(dev, 2, false); + apci3120_clr_timer2_interrupt(dev); + break; + + case INSN_CONFIG_GET_COUNTER_STATUS: + data[1] = 0; + data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING | + COMEDI_COUNTER_TERMINAL_COUNT; + + if (devpriv->ctrl & APCI3120_CTRL_GATE(2)) { + data[1] |= COMEDI_COUNTER_ARMED; + data[1] |= COMEDI_COUNTER_COUNTING; + } + status = inw(dev->iobase + APCI3120_STATUS_REG); + if (status & APCI3120_STATUS_TIMER2_INT) { + data[1] &= ~COMEDI_COUNTER_COUNTING; + data[1] |= COMEDI_COUNTER_TERMINAL_COUNT; + } + break; + + case INSN_CONFIG_SET_COUNTER_MODE: + switch (data[1]) { + case I8254_MODE0: + mode = APCI3120_MODE_TIMER2_AS_COUNTER; + timer_mode = APCI3120_TIMER_MODE0; + break; + case I8254_MODE2: + mode = APCI3120_MODE_TIMER2_AS_TIMER; + timer_mode = APCI3120_TIMER_MODE2; + break; + case I8254_MODE4: + mode = APCI3120_MODE_TIMER2_AS_TIMER; + timer_mode = APCI3120_TIMER_MODE4; + break; + case I8254_MODE5: + mode = APCI3120_MODE_TIMER2_AS_WDOG; + timer_mode = APCI3120_TIMER_MODE5; + break; + default: + return -EINVAL; + } + apci3120_timer_enable(dev, 2, false); + apci3120_clr_timer2_interrupt(dev); + apci3120_timer_set_mode(dev, 2, timer_mode); + devpriv->mode &= ~APCI3120_MODE_TIMER2_AS_MASK; + devpriv->mode |= mode; + outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG); + break; + + default: + return -EINVAL; + } + + return insn->n; +} + +static int apci3120_timer_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int i; + + for (i = 0; i < insn->n; i++) + data[i] = apci3120_timer_read(dev, 2); + + return insn->n; +} + +static void apci3120_dma_alloc(struct comedi_device *dev) +{ + struct apci3120_private *devpriv = dev->private; + struct apci3120_dmabuf *dmabuf; + int order; + int i; + + for (i = 0; i < 2; i++) { + dmabuf = &devpriv->dmabuf[i]; + for (order = 2; order >= 0; order--) { + dmabuf->virt = dma_alloc_coherent(dev->hw_dev, + PAGE_SIZE << order, + &dmabuf->hw, + GFP_KERNEL); + if (dmabuf->virt) + break; + } + if (!dmabuf->virt) + break; + dmabuf->size = PAGE_SIZE << order; + + if (i == 0) + devpriv->use_dma = 1; + if (i == 1) + devpriv->use_double_buffer = 1; + } +} + +static void apci3120_dma_free(struct comedi_device *dev) +{ + struct apci3120_private *devpriv = dev->private; + struct apci3120_dmabuf *dmabuf; + int i; + + if (!devpriv) + return; + + for (i = 0; i < 2; i++) { + dmabuf = &devpriv->dmabuf[i]; + if (dmabuf->virt) { + dma_free_coherent(dev->hw_dev, dmabuf->size, + dmabuf->virt, dmabuf->hw); + } + } +} + +static void apci3120_reset(struct comedi_device *dev) +{ + /* disable all interrupt sources */ + outb(0, dev->iobase + APCI3120_MODE_REG); + + /* disable all counters, ext trigger, and reset scan */ + outw(0, dev->iobase + APCI3120_CTRL_REG); + + /* clear interrupt status */ + inw(dev->iobase + APCI3120_STATUS_REG); } static int apci3120_auto_attach(struct comedi_device *dev, unsigned long context) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct addi_board *this_board = NULL; - struct addi_private *devpriv; + const struct apci3120_board *this_board = NULL; + struct apci3120_private *devpriv; struct comedi_subdevice *s; - int ret, order, i; + unsigned int status; + int ret; if (context < ARRAY_SIZE(apci3120_boardtypes)) this_board = &apci3120_boardtypes[context]; if (!this_board) return -ENODEV; dev->board_ptr = this_board; - dev->board_name = this_board->pc_DriverName; + dev->board_name = this_board->name; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -76,136 +999,100 @@ static int apci3120_auto_attach(struct comedi_device *dev, pci_set_master(pcidev); dev->iobase = pci_resource_start(pcidev, 1); - devpriv->iobase = dev->iobase; - devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); - devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); - devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); + devpriv->amcc = pci_resource_start(pcidev, 0); + devpriv->addon = pci_resource_start(pcidev, 2); + + apci3120_reset(dev); if (pcidev->irq > 0) { - ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, + ret = request_irq(pcidev->irq, apci3120_interrupt, IRQF_SHARED, dev->board_name, dev); - if (ret == 0) + if (ret == 0) { dev->irq = pcidev->irq; - } - /* Allocate DMA buffers */ - for (i = 0; i < 2; i++) { - for (order = 2; order >= 0; order--) { - devpriv->ul_DmaBufferVirtual[i] = - dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order, - &devpriv->ul_DmaBufferHw[i], - GFP_KERNEL); - - if (devpriv->ul_DmaBufferVirtual[i]) - break; + apci3120_dma_alloc(dev); } - if (!devpriv->ul_DmaBufferVirtual[i]) - break; - devpriv->ui_DmaBufferSize[i] = PAGE_SIZE << order; } - if (devpriv->ul_DmaBufferVirtual[0]) - devpriv->us_UseDma = 1; - if (devpriv->ul_DmaBufferVirtual[1]) - devpriv->b_DmaDoubleBuffer = 1; + status = inw(dev->iobase + APCI3120_STATUS_REG); + if (APCI3120_STATUS_TO_VERSION(status) == APCI3120_REVB || + context == BOARD_APCI3001) + devpriv->osc_base = APCI3120_REVB_OSC_BASE; + else + devpriv->osc_base = APCI3120_REVA_OSC_BASE; ret = comedi_alloc_subdevices(dev, 5); if (ret) return ret; - /* Allocate and Initialise AI Subdevice Structures */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_COMMON | SDF_GROUND - | SDF_DIFF; - if (this_board->i_NbrAiChannel) - s->n_chan = this_board->i_NbrAiChannel; - else - s->n_chan = this_board->i_NbrAiChannelDiff; - s->maxdata = this_board->i_AiMaxdata; - s->len_chanlist = this_board->i_AiChannelList; - s->range_table = &range_apci3120_ai; - - 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->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = this_board->ai_is_16bit ? 0xffff : 0x0fff; + s->range_table = &apci3120_ai_range; + s->insn_read = apci3120_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 = apci3120_ai_cmdtest; + s->do_cmd = apci3120_ai_cmd; + s->cancel = apci3120_cancel; + } + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (this_board->i_NbrAoChannel) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->i_NbrAoChannel; - s->maxdata = this_board->i_AoMaxdata; - s->len_chanlist = this_board->i_NbrAoChannel; - s->range_table = &range_apci3120_ao; - s->insn_write = apci3120_ao_insn_write; + if (this_board->has_ao) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 8; + s->maxdata = 0x3fff; + s->range_table = &range_bipolar10; + s->insn_write = apci3120_ao_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } - /* Allocate and Initialise DI Subdevice Structures */ + /* Digital Input subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->i_NbrDiChannel; - s->maxdata = 1; - s->len_chanlist = this_board->i_NbrDiChannel; - s->range_table = &range_digital; - s->insn_bits = apci3120_di_insn_bits; - - /* Allocate and Initialise DO Subdevice Structures */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3120_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->i_NbrDoChannel; - s->maxdata = this_board->i_DoMaxdata; - s->len_chanlist = this_board->i_NbrDoChannel; - s->range_table = &range_digital; - s->insn_bits = apci3120_do_insn_bits; - - /* Allocate and Initialise Timer Subdevice Structures */ - s = &dev->subdevices[4]; - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; - s->range_table = &range_digital; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3120_do_insn_bits; - s->insn_write = apci3120_write_insn_timer; - s->insn_read = apci3120_read_insn_timer; - s->insn_config = apci3120_config_insn_timer; + /* Timer subdevice */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 1; + s->maxdata = 0x00ffffff; + s->insn_config = apci3120_timer_insn_config; + s->insn_read = apci3120_timer_insn_read; - apci3120_reset(dev); return 0; } static void apci3120_detach(struct comedi_device *dev) { - struct addi_private *devpriv = dev->private; - - if (dev->iobase) - apci3120_reset(dev); comedi_pci_detach(dev); - if (devpriv) { - unsigned int i; - - for (i = 0; i < 2; i++) { - if (devpriv->ul_DmaBufferVirtual[i]) { - dma_free_coherent(dev->hw_dev, - devpriv->ui_DmaBufferSize[i], - devpriv-> - ul_DmaBufferVirtual[i], - devpriv->ul_DmaBufferHw[i]); - } - } - } + apci3120_dma_free(dev); } static struct comedi_driver apci3120_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c deleted file mode 100644 index fe6897eff3db..000000000000 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ /dev/null @@ -1,125 +0,0 @@ -#include <linux/module.h> -#include <linux/pci.h> - -#include <asm/i387.h> - -#include "../comedidev.h" -#include "comedi_fc.h" -#include "amcc_s5933.h" - -#include "addi-data/addi_common.h" - -static void fpu_begin(void) -{ - kernel_fpu_begin(); -} - -static void fpu_end(void) -{ - kernel_fpu_end(); -} - -#include "addi-data/addi_eeprom.c" -#include "addi-data/hwdrv_apci3200.c" -#include "addi-data/addi_common.c" - -enum apci3200_boardid { - BOARD_APCI3200, - BOARD_APCI3300, -}; - -static const struct addi_board apci3200_boardtypes[] = { - [BOARD_APCI3200] = { - .pc_DriverName = "apci3200", - .i_IorangeBase1 = 256, - .i_PCIEeprom = 1, - .pc_EepromChip = "S5920", - .i_NbrAiChannel = 16, - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 16, - .i_AiMaxdata = 0x3ffff, - .pr_AiRangelist = &range_apci3200_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .ui_MinAcquisitiontimeNs = 10000, - .ui_MinDelaytimeNs = 100000, - .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, - }, - [BOARD_APCI3300] = { - .pc_DriverName = "apci3300", - .i_IorangeBase1 = 256, - .i_PCIEeprom = 1, - .pc_EepromChip = "S5920", - .i_NbrAiChannelDiff = 8, - .i_AiChannelList = 8, - .i_AiMaxdata = 0x3ffff, - .pr_AiRangelist = &range_apci3300_ai, - .i_NbrDiChannel = 4, - .i_NbrDoChannel = 4, - .ui_MinAcquisitiontimeNs = 10000, - .ui_MinDelaytimeNs = 100000, - .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, - }, -}; - -static int apci3200_auto_attach(struct comedi_device *dev, - unsigned long context) -{ - const struct addi_board *board = NULL; - - if (context < ARRAY_SIZE(apci3200_boardtypes)) - board = &apci3200_boardtypes[context]; - if (!board) - return -ENODEV; - dev->board_ptr = board; - - return addi_auto_attach(dev, context); -} - -static struct comedi_driver apci3200_driver = { - .driver_name = "addi_apci_3200", - .module = THIS_MODULE, - .auto_attach = apci3200_auto_attach, - .detach = i_ADDI_Detach, -}; - -static int apci3200_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return comedi_pci_auto_config(dev, &apci3200_driver, id->driver_data); -} - -static const struct pci_device_id apci3200_pci_table[] = { - { PCI_VDEVICE(ADDIDATA, 0x3000), BOARD_APCI3200 }, - { PCI_VDEVICE(ADDIDATA, 0x3007), BOARD_APCI3300 }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, apci3200_pci_table); - -static struct pci_driver apci3200_pci_driver = { - .name = "addi_apci_3200", - .id_table = apci3200_pci_table, - .probe = apci3200_pci_probe, - .remove = comedi_pci_auto_unconfig, -}; -module_comedi_pci_driver(apci3200_driver, apci3200_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index 010efa3fed6c..a726efcea6a5 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -357,12 +357,11 @@ static int apci3501_auto_attach(struct comedi_device *dev, s = &dev->subdevices[0]; if (ao_n_chan) { s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = ao_n_chan; s->maxdata = 0x3fff; s->range_table = &apci3501_ao_range; s->insn_write = apci3501_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -383,7 +382,7 @@ static int apci3501_auto_attach(struct comedi_device *dev, /* Initialize the digital output subdevice */ s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = 1; s->range_table = &range_digital; @@ -392,7 +391,7 @@ static int apci3501_auto_attach(struct comedi_device *dev, /* Initialize the timer/watchdog subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 1; s->maxdata = 0; s->len_chanlist = 1; diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index a296bd5b2c0c..c173810a3b5b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -371,10 +371,10 @@ static irqreturn_t apci3xxx_irq_handler(int irq, void *d) writel(status, dev->mmio + 16); val = readl(dev->mmio + 28); - comedi_buf_put(s, val); + comedi_buf_write_samples(s, &val, 1); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -849,12 +849,11 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, if (board->has_ao) { s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 4; s->maxdata = 0x0fff; s->range_table = &apci3xxx_ao_range; s->insn_write = apci3xxx_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -880,7 +879,7 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, if (board->has_dig_out) { s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; @@ -893,7 +892,7 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, if (board->has_ttl_io) { s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 24; s->maxdata = 1; s->io_bits = 0xff; /* channels 0-7 are always outputs */ diff --git a/drivers/staging/comedi/drivers/addi_tcw.h b/drivers/staging/comedi/drivers/addi_tcw.h new file mode 100644 index 000000000000..8794d4cbbfb0 --- /dev/null +++ b/drivers/staging/comedi/drivers/addi_tcw.h @@ -0,0 +1,56 @@ +#ifndef _ADDI_TCW_H +#define _ADDI_TCW_H + +/* + * Following are the generic definitions for the ADDI-DATA timer/counter/ + * watchdog (TCW) registers and bits. Some of the registers are not used + * depending on the use of the TCW. + */ + +#define ADDI_TCW_VAL_REG 0x00 + +#define ADDI_TCW_SYNC_REG 0x00 +#define ADDI_TCW_SYNC_CTR_TRIG (1 << 8) +#define ADDI_TCW_SYNC_CTR_DIS (1 << 7) +#define ADDI_TCW_SYNC_CTR_ENA (1 << 6) +#define ADDI_TCW_SYNC_TIMER_TRIG (1 << 5) +#define ADDI_TCW_SYNC_TIMER_DIS (1 << 4) +#define ADDI_TCW_SYNC_TIMER_ENA (1 << 3) +#define ADDI_TCW_SYNC_WDOG_TRIG (1 << 2) +#define ADDI_TCW_SYNC_WDOG_DIS (1 << 1) +#define ADDI_TCW_SYNC_WDOG_ENA (1 << 0) + +#define ADDI_TCW_RELOAD_REG 0x04 + +#define ADDI_TCW_TIMEBASE_REG 0x08 + +#define ADDI_TCW_CTRL_REG 0x0c +#define ADDI_TCW_CTRL_EXT_CLK_STATUS (1 << 21) +#define ADDI_TCW_CTRL_CASCADE (1 << 20) +#define ADDI_TCW_CTRL_CNTR_ENA (1 << 19) +#define ADDI_TCW_CTRL_CNT_UP (1 << 18) +#define ADDI_TCW_CTRL_EXT_CLK(x) ((x) << 16) +#define ADDI_TCW_CTRL_OUT(x) ((x) << 11) +#define ADDI_TCW_CTRL_GATE (1 << 10) +#define ADDI_TCW_CTRL_TRIG (1 << 9) +#define ADDI_TCW_CTRL_EXT_GATE(x) ((x) << 7) +#define ADDI_TCW_CTRL_EXT_TRIG(x) ((x) << 5) +#define ADDI_TCW_CTRL_TIMER_ENA (1 << 4) +#define ADDI_TCW_CTRL_RESET_ENA (1 << 3) +#define ADDI_TCW_CTRL_WARN_ENA (1 << 2) +#define ADDI_TCW_CTRL_IRQ_ENA (1 << 1) +#define ADDI_TCW_CTRL_ENA (1 << 0) + +#define ADDI_TCW_STATUS_REG 0x10 +#define ADDI_TCW_STATUS_SOFT_CLR (1 << 3) +#define ADDI_TCW_STATUS_SOFT_TRIG (1 << 1) +#define ADDI_TCW_STATUS_OVERFLOW (1 << 0) + +#define ADDI_TCW_IRQ_REG 0x14 +#define ADDI_TCW_IRQ (1 << 0) + +#define ADDI_TCW_WARN_TIMEVAL_REG 0x18 + +#define ADDI_TCW_WARN_TIMEBASE_REG 0x1c + +#endif diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c index 23031feaa095..c5b082d4e51e 100644 --- a/drivers/staging/comedi/drivers/addi_watchdog.c +++ b/drivers/staging/comedi/drivers/addi_watchdog.c @@ -20,21 +20,9 @@ #include <linux/module.h> #include "../comedidev.h" +#include "addi_tcw.h" #include "addi_watchdog.h" -/* - * Register offsets/defines for the addi-data watchdog - */ -#define ADDI_WDOG_REG 0x00 -#define ADDI_WDOG_RELOAD_REG 0x04 -#define ADDI_WDOG_TIMEBASE 0x08 -#define ADDI_WDOG_CTRL_REG 0x0c -#define ADDI_WDOG_CTRL_ENABLE (1 << 0) -#define ADDI_WDOG_CTRL_SW_TRIG (1 << 9) -#define ADDI_WDOG_STATUS_REG 0x10 -#define ADDI_WDOG_STATUS_ENABLED (1 << 0) -#define ADDI_WDOG_STATUS_SW_TRIG (1 << 1) - struct addi_watchdog_private { unsigned long iobase; unsigned int wdog_ctrl; @@ -60,9 +48,9 @@ static int addi_watchdog_insn_config(struct comedi_device *dev, switch (data[0]) { case INSN_CONFIG_ARM: - spriv->wdog_ctrl = ADDI_WDOG_CTRL_ENABLE; + spriv->wdog_ctrl = ADDI_TCW_CTRL_ENA; reload = data[1] & s->maxdata; - outl(reload, spriv->iobase + ADDI_WDOG_RELOAD_REG); + outl(reload, spriv->iobase + ADDI_TCW_RELOAD_REG); /* Time base is 20ms, let the user know the timeout */ dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n", @@ -75,7 +63,7 @@ static int addi_watchdog_insn_config(struct comedi_device *dev, return -EINVAL; } - outl(spriv->wdog_ctrl, spriv->iobase + ADDI_WDOG_CTRL_REG); + outl(spriv->wdog_ctrl, spriv->iobase + ADDI_TCW_CTRL_REG); return insn->n; } @@ -89,7 +77,7 @@ static int addi_watchdog_insn_read(struct comedi_device *dev, int i; for (i = 0; i < insn->n; i++) - data[i] = inl(spriv->iobase + ADDI_WDOG_STATUS_REG); + data[i] = inl(spriv->iobase + ADDI_TCW_STATUS_REG); return insn->n; } @@ -109,8 +97,8 @@ static int addi_watchdog_insn_write(struct comedi_device *dev, /* "ping" the watchdog */ for (i = 0; i < insn->n; i++) { - outl(spriv->wdog_ctrl | ADDI_WDOG_CTRL_SW_TRIG, - spriv->iobase + ADDI_WDOG_CTRL_REG); + outl(spriv->wdog_ctrl | ADDI_TCW_CTRL_TRIG, + spriv->iobase + ADDI_TCW_CTRL_REG); } return insn->n; @@ -118,8 +106,8 @@ static int addi_watchdog_insn_write(struct comedi_device *dev, void addi_watchdog_reset(unsigned long iobase) { - outl(0x0, iobase + ADDI_WDOG_CTRL_REG); - outl(0x0, iobase + ADDI_WDOG_RELOAD_REG); + outl(0x0, iobase + ADDI_TCW_CTRL_REG); + outl(0x0, iobase + ADDI_TCW_RELOAD_REG); } EXPORT_SYMBOL_GPL(addi_watchdog_reset); @@ -134,7 +122,7 @@ int addi_watchdog_init(struct comedi_subdevice *s, unsigned long iobase) spriv->iobase = iobase; s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 1; s->maxdata = 0xff; s->insn_config = addi_watchdog_insn_config; diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 0ad46fe492c9..528f15c25dae 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -169,7 +169,6 @@ static int pci6208_auto_attach(struct comedi_device *dev, s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = pci6208_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index d18d8f21af23..47f6c0e9f014 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -133,8 +133,6 @@ static const struct comedi_lrange pci9111_ai_range = { struct pci9111_private_data { unsigned long lcr_io_base; - int stop_counter; - unsigned int scan_delay; unsigned int chunk_counter; unsigned int chunk_num_samples; @@ -404,12 +402,6 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, outb(CR_RANGE(cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, dev->iobase + PCI9111_AI_RANGE_STAT_REG); - /* Set counter */ - if (cmd->stop_src == TRIG_COUNT) - dev_private->stop_counter = cmd->stop_arg * cmd->chanlist_len; - else /* TRIG_NONE */ - dev_private->stop_counter = 0; - /* Set timer pacer */ dev_private->scan_delay = 0; if (cmd->convert_src == TRIG_TIMER) { @@ -435,7 +427,6 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, } outb(trig, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); - dev_private->stop_counter *= (1 + dev_private->scan_delay); dev_private->chunk_counter = 0; dev_private->chunk_num_samples = cmd->chanlist_len * (1 + dev_private->scan_delay); @@ -452,7 +443,7 @@ static void pci9111_ai_munge(struct comedi_device *dev, unsigned int maxdata = s->maxdata; unsigned int invert = (maxdata + 1) >> 1; unsigned int shift = (maxdata == 0xffff) ? 0 : 4; - unsigned int num_samples = num_bytes / sizeof(short); + unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes); unsigned int i; for (i = 0; i < num_samples; i++) @@ -464,22 +455,14 @@ static void pci9111_handle_fifo_half_full(struct comedi_device *dev, { 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; - + samples = comedi_nsamples_left(s, 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)); + comedi_buf_write_samples(s, devpriv->ai_bounce_buffer, samples); } else { unsigned int pos = 0; unsigned int to_read; @@ -492,17 +475,15 @@ static void pci9111_handle_fifo_half_full(struct comedi_device *dev, if (to_read > samples - pos) to_read = samples - pos; - total += cfc_write_array_to_buffer(s, + comedi_buf_write_samples(s, devpriv->ai_bounce_buffer + pos, - to_read * sizeof(short)); + to_read); } 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; @@ -513,8 +494,6 @@ static void pci9111_handle_fifo_half_full(struct comedi_device *dev, devpriv->chunk_counter = 0; } } - - devpriv->stop_counter -= total / sizeof(short); } static irqreturn_t pci9111_interrupt(int irq, void *p_device) @@ -561,7 +540,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) dev_dbg(dev->class_dev, "fifo overflow\n"); outb(0, dev->iobase + PCI9111_INT_CLR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -571,14 +550,14 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) pci9111_handle_fifo_half_full(dev, s); } - if (cmd->stop_src == TRIG_COUNT && dev_private->stop_counter == 0) + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) async->events |= COMEDI_CB_EOA; outb(0, dev->iobase + PCI9111_INT_CLR_REG); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -752,7 +731,6 @@ static int pci9111_auto_attach(struct comedi_device *dev, s->len_chanlist = 1; s->range_table = &range_bipolar10; s->insn_write = pci9111_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -768,7 +746,7 @@ static int pci9111_auto_attach(struct comedi_device *dev, s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index e18fd9569a2b..26603582e71a 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -221,7 +221,6 @@ struct pci9118_private { unsigned char int_ctrl; unsigned char ai_cfg; 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_n_realscanlen; /* * what we must transfer for one * outgoing scan include front/back adds @@ -447,51 +446,112 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev, outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); } -static unsigned int defragment_dma_buffer(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned short *dma_buffer, - unsigned int num_samples) +static unsigned int valid_samples_in_act_dma_buf(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int n_raw_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 + cmd->chanlist_len; - unsigned int raw_scanlen = devpriv->ai_add_front + cmd->chanlist_len + - devpriv->ai_add_back; + unsigned int start_pos = devpriv->ai_add_front; + unsigned int stop_pos = start_pos + cmd->chanlist_len; + unsigned int span_len = stop_pos + devpriv->ai_add_back; + unsigned int dma_pos = devpriv->ai_act_dmapos; + unsigned int whole_spans, n_samples, x; - for (i = 0; i < num_samples; i++) { - if (devpriv->ai_act_dmapos >= start_pos && - devpriv->ai_act_dmapos < stop_pos) { - dma_buffer[j++] = dma_buffer[i]; + if (span_len == cmd->chanlist_len) + return n_raw_samples; /* use all samples */ + + /* + * Not all samples are to be used. Buffer contents consist of a + * possibly non-whole number of spans and a region of each span + * is to be used. + * + * Account for samples in whole number of spans. + */ + whole_spans = n_raw_samples / span_len; + n_samples = whole_spans * cmd->chanlist_len; + n_raw_samples -= whole_spans * span_len; + + /* + * Deal with remaining samples which could overlap up to two spans. + */ + while (n_raw_samples) { + if (dma_pos < start_pos) { + /* Skip samples before start position. */ + x = start_pos - dma_pos; + if (x > n_raw_samples) + x = n_raw_samples; + dma_pos += x; + n_raw_samples -= x; + if (!n_raw_samples) + break; } - devpriv->ai_act_dmapos++; - devpriv->ai_act_dmapos %= raw_scanlen; + if (dma_pos < stop_pos) { + /* Include samples before stop position. */ + x = stop_pos - dma_pos; + if (x > n_raw_samples) + x = n_raw_samples; + n_samples += x; + dma_pos += x; + n_raw_samples -= x; + } + /* Advance to next span. */ + start_pos += span_len; + stop_pos += span_len; } - - return j; + return n_samples; } -static int move_block_from_dma(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned short *dma_buffer, - unsigned int num_samples) +static void move_block_from_dma(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned short *dma_buffer, + unsigned int n_raw_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) / cmd->scan_end_arg; - s->async->cur_chan += num_samples; - s->async->cur_chan %= cmd->scan_end_arg; - num_bytes = - cfc_write_array_to_buffer(s, dma_buffer, - num_samples * sizeof(short)); - if (num_bytes < num_samples * sizeof(short)) - return -1; - return 0; + unsigned int start_pos = devpriv->ai_add_front; + unsigned int stop_pos = start_pos + cmd->chanlist_len; + unsigned int span_len = stop_pos + devpriv->ai_add_back; + unsigned int dma_pos = devpriv->ai_act_dmapos; + unsigned int x; + + if (span_len == cmd->chanlist_len) { + /* All samples are to be copied. */ + comedi_buf_write_samples(s, dma_buffer, n_raw_samples); + dma_pos += n_raw_samples; + } else { + /* + * Not all samples are to be copied. Buffer contents consist + * of a possibly non-whole number of spans and a region of + * each span is to be copied. + */ + while (n_raw_samples) { + if (dma_pos < start_pos) { + /* Skip samples before start position. */ + x = start_pos - dma_pos; + if (x > n_raw_samples) + x = n_raw_samples; + dma_pos += x; + n_raw_samples -= x; + if (!n_raw_samples) + break; + } + if (dma_pos < stop_pos) { + /* Copy samples before stop position. */ + x = stop_pos - dma_pos; + if (x > n_raw_samples) + x = n_raw_samples; + comedi_buf_write_samples(s, dma_buffer, x); + dma_pos += x; + n_raw_samples -= x; + } + /* Advance to next span. */ + start_pos += span_len; + stop_pos += span_len; + } + } + /* Update position in span for next time. */ + devpriv->ai_act_dmapos = dma_pos % span_len; } static void pci9118_exttrg_enable(struct comedi_device *dev, bool enable) @@ -578,9 +638,7 @@ static int pci9118_ai_cancel(struct comedi_device *dev, devpriv->ai_do = 0; devpriv->usedma = 0; - devpriv->ai_act_scan = 0; devpriv->ai_act_dmapos = 0; - s->async->cur_chan = 0; s->async->inttrig = NULL; devpriv->ai_neverending = 0; devpriv->dma_actbuf = 0; @@ -594,8 +652,9 @@ static void pci9118_ai_munge(struct comedi_device *dev, unsigned int start_chan_index) { struct pci9118_private *devpriv = dev->private; - unsigned int i, num_samples = num_bytes / sizeof(short); unsigned short *array = data; + unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes); + unsigned int i; for (i = 0; i < num_samples; i++) { if (devpriv->usedma) @@ -617,17 +676,11 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, sampl = inl(dev->iobase + PCI9118_AI_FIFO_REG); - cfc_write_to_buffer(s, sampl); - s->async->cur_chan++; - if (s->async->cur_chan >= cmd->scan_end_arg) { - /* one scan done */ - s->async->cur_chan %= cmd->scan_end_arg; - devpriv->ai_act_scan++; - if (!devpriv->ai_neverending) { - /* all data sampled? */ - if (devpriv->ai_act_scan >= cmd->stop_arg) - s->async->events |= COMEDI_CB_EOA; - } + comedi_buf_write_samples(s, &sampl, 1); + + if (!devpriv->ai_neverending) { + if (s->async->scans_done >= cmd->stop_arg) + s->async->events |= COMEDI_CB_EOA; } } @@ -637,39 +690,37 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[devpriv->dma_actbuf]; - unsigned int next_dma_buf, samplesinbuf, sampls, m; + unsigned int n_all = comedi_bytes_to_samples(s, dmabuf->use_size); + unsigned int n_valid; + bool more_dma; - samplesinbuf = dmabuf->use_size >> 1; /* number of received samples */ + /* determine whether more DMA buffers to do after this one */ + n_valid = valid_samples_in_act_dma_buf(dev, s, n_all); + more_dma = n_valid < comedi_nsamples_left(s, n_valid + 1); - if (devpriv->dma_doublebuf) { /* - * switch DMA buffers if is used - * double buffering - */ - next_dma_buf = 1 - devpriv->dma_actbuf; - pci9118_amcc_setup_dma(dev, next_dma_buf); - if (devpriv->ai_do == 4) - interrupt_pci9118_ai_mode4_switch(dev, next_dma_buf); + /* switch DMA buffers and restart DMA if double buffering */ + if (more_dma && devpriv->dma_doublebuf) { + devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; + pci9118_amcc_setup_dma(dev, devpriv->dma_actbuf); + if (devpriv->ai_do == 4) { + interrupt_pci9118_ai_mode4_switch(dev, + devpriv->dma_actbuf); + } } - if (samplesinbuf) { - /* how many samples is to end of buffer */ - m = s->async->prealloc_bufsz >> 1; - sampls = m; - move_block_from_dma(dev, s, dmabuf->virt, samplesinbuf); - m = m - sampls; /* m=how many samples was transferred */ - } + if (n_all) + move_block_from_dma(dev, s, dmabuf->virt, n_all); if (!devpriv->ai_neverending) { - /* all data sampled? */ - if (devpriv->ai_act_scan >= cmd->stop_arg) + if (s->async->scans_done >= cmd->stop_arg) s->async->events |= COMEDI_CB_EOA; } - if (devpriv->dma_doublebuf) { - /* switch dma buffers */ - devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; - } else { - /* restart DMA if is not used double buffering */ + if (s->async->events & COMEDI_CB_CANCEL_MASK) + more_dma = false; + + /* restart DMA if not double buffering */ + if (more_dma && !devpriv->dma_doublebuf) { pci9118_amcc_setup_dma(dev, 0); if (devpriv->ai_do == 4) interrupt_pci9118_ai_mode4_switch(dev, 0); @@ -766,7 +817,7 @@ static irqreturn_t pci9118_interrupt(int irq, void *d) interrupt_pci9118_ai_onesample(dev, s); interrupt_exit: - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -1123,9 +1174,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) inl(dev->iobase + PCI9118_AI_STATUS_REG); inl(dev->iobase + PCI9118_INT_CTRL_REG); - devpriv->ai_act_scan = 0; devpriv->ai_act_dmapos = 0; - s->async->cur_chan = 0; if (devpriv->usedma) { Compute_and_setup_dma(dev, s); @@ -1624,7 +1673,6 @@ static int pci9118_common_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table = &range_bipolar10; s->insn_write = pci9118_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 5539bd294862..d02df7d0c629 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -298,7 +298,6 @@ static const struct boardtype boardtypes[] = { struct pci1710_private { unsigned int CntrlReg; /* Control register */ - unsigned int ai_act_scan; /* how many scans we finished */ unsigned char ai_et; unsigned int ai_et_CntrlReg; unsigned int ai_et_MuxVal; @@ -730,16 +729,12 @@ static int pci171x_ai_cancel(struct comedi_device *dev, break; } - devpriv->ai_act_scan = 0; - s->async->cur_chan = 0; - return 0; } static void pci1710_handle_every_sample(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pci1710_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int status; unsigned int val; @@ -749,14 +744,14 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, 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; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } if (status & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } @@ -770,27 +765,19 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, break; } - comedi_buf_put(s, val & s->maxdata); - - s->async->cur_chan++; - if (s->async->cur_chan >= cmd->chanlist_len) - s->async->cur_chan = 0; + val &= s->maxdata; + comedi_buf_write_samples(s, &val, 1); - - if (s->async->cur_chan == 0) { /* one scan done */ - devpriv->ai_act_scan++; - if (cmd->stop_src == TRIG_COUNT && - devpriv->ai_act_scan >= cmd->stop_arg) { - /* all data sampled */ - s->async->events |= COMEDI_CB_EOA; - break; - } + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) { + s->async->events |= COMEDI_CB_EOA; + break; } } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } /* @@ -799,8 +786,6 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, static int move_block_from_fifo(struct comedi_device *dev, struct comedi_subdevice *s, int n, int turn) { - struct pci1710_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; unsigned int val; int ret; int i; @@ -814,13 +799,8 @@ static int move_block_from_fifo(struct comedi_device *dev, 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++; - } + val &= s->maxdata; + comedi_buf_write_samples(s, &val, 1); } return 0; } @@ -829,48 +809,47 @@ static void pci1710_handle_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { const struct boardtype *this_board = dev->board_ptr; - struct pci1710_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int m, samplesinbuf; + unsigned int nsamples; + unsigned int m; m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } if (m & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } - samplesinbuf = this_board->fifo_half_size; - if (samplesinbuf * sizeof(short) >= s->async->prealloc_bufsz) { - m = s->async->prealloc_bufsz / sizeof(short); + nsamples = this_board->fifo_half_size; + if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) { + m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz); if (move_block_from_fifo(dev, s, m, 0)) return; - samplesinbuf -= m; + nsamples -= m; } - if (samplesinbuf) { - if (move_block_from_fifo(dev, s, samplesinbuf, 1)) + if (nsamples) { + if (move_block_from_fifo(dev, s, nsamples, 1)) return; } if (cmd->stop_src == TRIG_COUNT && - devpriv->ai_act_scan >= cmd->stop_arg) { - /* all data sampled */ + s->async->scans_done >= cmd->stop_arg) { s->async->events |= COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } /* @@ -928,9 +907,6 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - devpriv->ai_act_scan = 0; - s->async->cur_chan = 0; - devpriv->CntrlReg &= Control_CNT0; if ((cmd->flags & CMDF_WAKE_EOS) == 0) devpriv->CntrlReg |= Control_ONEFH; @@ -1208,7 +1184,7 @@ static int pci1710_auto_attach(struct comedi_device *dev, if (this_board->n_dichan) { s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_READABLE; s->n_chan = this_board->n_dichan; s->maxdata = 1; s->len_chanlist = this_board->n_dichan; @@ -1220,7 +1196,7 @@ static int pci1710_auto_attach(struct comedi_device *dev, if (this_board->n_dochan) { s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE; s->n_chan = this_board->n_dochan; s->maxdata = 1; s->len_chanlist = this_board->n_dochan; diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 1610e2b406f3..65f854e1eb66 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -1,205 +1,124 @@ /* - comedi/drivers/pci1723.c - - 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. + * adv_pci1723.c + * Comedi driver for the Advantech PCI-1723 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 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: adv_pci1723 -Description: Advantech PCI-1723 -Author: yonggang <rsmgnu@gmail.com>, Ian Abbott <abbotti@mev.co.uk> -Devices: [Advantech] PCI-1723 (adv_pci1723) -Updated: Mon, 14 Apr 2008 15:12:56 +0100 -Status: works - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - - If bus/slot is not specified, the first supported - PCI device found will be used. - -Subdevice 0 is 8-channel AO, 16-bit, range +/- 10 V. - -Subdevice 1 is 16-channel DIO. The channels are configurable as input or -output in 2 groups (0 to 7, 8 to 15). Configuring any channel implicitly -configures all channels in the same group. - -TODO: - -1. Add the two milliamp ranges to the AO subdevice (0 to 20 mA, 4 to 20 mA). -2. Read the initial ranges and values of the AO subdevice at start-up instead - of reinitializing them. -3. Implement calibration. -*/ + * Driver: adv_pci1723 + * Description: Advantech PCI-1723 + * Author: yonggang <rsmgnu@gmail.com>, Ian Abbott <abbotti@mev.co.uk> + * Devices: (Advantech) PCI-1723 [adv_pci1723] + * Updated: Mon, 14 Apr 2008 15:12:56 +0100 + * Status: works + * + * Configuration Options: not applicable, uses comedi PCI auto config + * + * Subdevice 0 is 8-channel AO, 16-bit, range +/- 10 V. + * + * Subdevice 1 is 16-channel DIO. The channels are configurable as + * input or output in 2 groups (0 to 7, 8 to 15). Configuring any + * channel implicitly configures all channels in the same group. + * + * TODO: + * 1. Add the two milliamp ranges to the AO subdevice (0 to 20 mA, + * 4 to 20 mA). + * 2. Read the initial ranges and values of the AO subdevice at + * start-up instead of reinitializing them. + * 3. Implement calibration. + */ #include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" -/* all the registers for the pci1723 board */ -#define PCI1723_DA(N) ((N)<<1) /* W: D/A register N (0 to 7) */ - -#define PCI1723_SYN_SET 0x12 /* synchronized set register */ -#define PCI1723_ALL_CHNNELE_SYN_STROBE 0x12 - /* synchronized status register */ - -#define PCI1723_RANGE_CALIBRATION_MODE 0x14 - /* range and calibration mode */ -#define PCI1723_RANGE_CALIBRATION_STATUS 0x14 - /* range and calibration status */ - -#define PCI1723_CONTROL_CMD_CALIBRATION_FUN 0x16 - /* - * SADC control command for - * calibration function - */ -#define PCI1723_STATUS_CMD_CALIBRATION_FUN 0x16 - /* - * SADC control status for - * calibration function - */ - -#define PCI1723_CALIBRATION_PARA_STROBE 0x18 - /* Calibration parameter strobe */ - -#define PCI1723_DIGITAL_IO_PORT_SET 0x1A /* Digital I/O port setting */ -#define PCI1723_DIGITAL_IO_PORT_MODE 0x1A /* Digital I/O port mode */ - -#define PCI1723_WRITE_DIGITAL_OUTPUT_CMD 0x1C - /* Write digital output command */ -#define PCI1723_READ_DIGITAL_INPUT_DATA 0x1C /* Read digital input data */ - -#define PCI1723_WRITE_CAL_CMD 0x1E /* Write calibration command */ -#define PCI1723_READ_CAL_STATUS 0x1E /* Read calibration status */ - -#define PCI1723_SYN_STROBE 0x20 /* Synchronized strobe */ - -#define PCI1723_RESET_ALL_CHN_STROBE 0x22 - /* Reset all D/A channels strobe */ - -#define PCI1723_RESET_CAL_CONTROL_STROBE 0x24 - /* - * Reset the calibration - * controller strobe - */ - -#define PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE 0x26 - /* - * Change D/A channels output - * type strobe - */ - -#define PCI1723_SELECT_CALIBRATION 0x28 /* Select the calibration Ref_V */ - -struct pci1723_private { - unsigned char da_range[8]; /* D/A output range for each channel */ - unsigned short ao_data[8]; /* data output buffer */ -}; - /* - * The pci1723 card reset; + * PCI Bar 2 I/O Register map (dev->iobase) */ -static int pci1723_reset(struct comedi_device *dev) +#define PCI1723_AO_REG(x) (0x00 + ((x) * 2)) +#define PCI1723_BOARD_ID_REG 0x10 +#define PCI1723_BOARD_ID_MASK (0xf << 0) +#define PCI1723_SYNC_CTRL_REG 0x12 +#define PCI1723_SYNC_CTRL_ASYNC (0 << 0) +#define PCI1723_SYNC_CTRL_SYNC (1 << 0) +#define PCI1723_CTRL_REG 0x14 +#define PCI1723_CTRL_BUSY (1 << 15) +#define PCI1723_CTRL_INIT (1 << 14) +#define PCI1723_CTRL_SELF (1 << 8) +#define PCI1723_CTRL_IDX(x) (((x) & 0x3) << 6) +#define PCI1723_CTRL_RANGE(x) (((x) & 0x3) << 4) +#define PCI1723_CTRL_GAIN (0 << 3) +#define PCI1723_CTRL_OFFSET (1 << 3) +#define PCI1723_CTRL_CHAN(x) (((x) & 0x7) << 0) +#define PCI1723_CALIB_CTRL_REG 0x16 +#define PCI1723_CALIB_CTRL_CS (1 << 2) +#define PCI1723_CALIB_CTRL_DAT (1 << 1) +#define PCI1723_CALIB_CTRL_CLK (1 << 0) +#define PCI1723_CALIB_STROBE_REG 0x18 +#define PCI1723_DIO_CTRL_REG 0x1a +#define PCI1723_DIO_CTRL_HDIO (1 << 1) +#define PCI1723_DIO_CTRL_LDIO (1 << 0) +#define PCI1723_DIO_DATA_REG 0x1c +#define PCI1723_CALIB_DATA_REG 0x1e +#define PCI1723_SYNC_STROBE_REG 0x20 +#define PCI1723_RESET_AO_STROBE_REG 0x22 +#define PCI1723_RESET_CALIB_STROBE_REG 0x24 +#define PCI1723_RANGE_STROBE_REG 0x26 +#define PCI1723_VREF_REG 0x28 +#define PCI1723_VREF_NEG10V (0 << 0) +#define PCI1723_VREF_0V (1 << 0) +#define PCI1723_VREF_POS10V (3 << 0) + +static int pci1723_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pci1723_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - outw(0x01, dev->iobase + PCI1723_SYN_SET); - /* set synchronous output mode */ - - for (i = 0; i < 8; i++) { - /* set all outputs to 0V */ - devpriv->ao_data[i] = 0x8000; - outw(devpriv->ao_data[i], dev->iobase + PCI1723_DA(i)); - /* set all ranges to +/- 10V */ - devpriv->da_range[i] = 0; - outw(((devpriv->da_range[i] << 4) | i), - PCI1723_RANGE_CALIBRATION_MODE); - } - - outw(0, dev->iobase + PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE); - /* update ranges */ - outw(0, dev->iobase + PCI1723_SYN_STROBE); /* update outputs */ - - /* set asynchronous output mode */ - outw(0, dev->iobase + PCI1723_SYN_SET); - - return 0; -} - -static int pci1723_insn_read_ao(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pci1723_private *devpriv = dev->private; - int n, chan; - - chan = CR_CHAN(insn->chanspec); - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_data[chan]; + for (i = 0; i < insn->n; i++) { + unsigned int val = data[i]; - return n; -} - -/* - analog data output; -*/ -static int pci1723_ao_write_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pci1723_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int n; - - for (n = 0; n < insn->n; n++) { - devpriv->ao_data[chan] = data[n]; - outw(data[n], dev->iobase + PCI1723_DA(chan)); + outw(val, dev->iobase + PCI1723_AO_REG(chan)); + s->readback[chan] = val; } - return n; + return insn->n; } -/* - digital i/o config/query -*/ static int pci1723_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask; - unsigned short mode; + unsigned int mask = (chan < 8) ? 0x00ff : 0xff00; + unsigned short mode = 0x0000; /* assume output */ int ret; - if (chan < 8) - mask = 0x00ff; - else - mask = 0xff00; - ret = comedi_dio_insn_config(dev, s, insn, data, mask); if (ret) return ret; - /* update hardware DIO mode */ - mode = 0x0000; /* assume output */ if (!(s->io_bits & 0x00ff)) - mode |= 0x0001; /* low byte input */ + mode |= PCI1723_DIO_CTRL_LDIO; /* low byte input */ if (!(s->io_bits & 0xff00)) - mode |= 0x0002; /* high byte input */ - outw(mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET); + mode |= PCI1723_DIO_CTRL_HDIO; /* high byte input */ + outw(mode, dev->iobase + PCI1723_DIO_CTRL_REG); return insn->n; } @@ -210,24 +129,21 @@ static int pci1723_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outw(s->state, dev->iobase + PCI1723_WRITE_DIGITAL_OUTPUT_CMD); + outw(s->state, dev->iobase + PCI1723_DIO_DATA_REG); - data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); + data[1] = inw(dev->iobase + PCI1723_DIO_DATA_REG); return insn->n; } static int pci1723_auto_attach(struct comedi_device *dev, - unsigned long context_unused) + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct pci1723_private *devpriv; struct comedi_subdevice *s; + unsigned int val; int ret; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; + int i; ret = comedi_pci_enable(dev); if (ret) @@ -239,61 +155,57 @@ static int pci1723_auto_attach(struct comedi_device *dev, return ret; s = &dev->subdevices[0]; - dev->write_subdev = s; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 8; s->maxdata = 0xffff; - s->len_chanlist = 8; s->range_table = &range_bipolar10; - s->insn_write = pci1723_ao_write_winsn; - s->insn_read = pci1723_insn_read_ao; + s->insn_write = pci1723_ao_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + /* synchronously reset all analog outputs to 0V, +/-10V range */ + outw(PCI1723_SYNC_CTRL_SYNC, dev->iobase + PCI1723_SYNC_CTRL_REG); + for (i = 0; i < s->n_chan; i++) { + outw(PCI1723_CTRL_RANGE(0) | PCI1723_CTRL_CHAN(i), + PCI1723_CTRL_REG); + outw(0, dev->iobase + PCI1723_RANGE_STROBE_REG); + + outw(0x8000, dev->iobase + PCI1723_AO_REG(i)); + s->readback[i] = 0x8000; + } + outw(0, dev->iobase + PCI1723_SYNC_STROBE_REG); + + /* disable syncronous control */ + outw(PCI1723_SYNC_CTRL_ASYNC, dev->iobase + PCI1723_SYNC_CTRL_REG); s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; - s->len_chanlist = 16; s->range_table = &range_digital; s->insn_config = pci1723_dio_insn_config; s->insn_bits = pci1723_dio_insn_bits; - /* read DIO config */ - switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) { - case 0x00: /* low byte output, high byte output */ - s->io_bits = 0xFFFF; - break; - case 0x01: /* low byte input, high byte output */ - s->io_bits = 0xFF00; - break; - case 0x02: /* low byte output, high byte input */ - s->io_bits = 0x00FF; - break; - case 0x03: /* low byte input, high byte input */ - s->io_bits = 0x0000; - break; - } - /* read DIO port state */ - s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); - - pci1723_reset(dev); + /* get initial DIO direction and state */ + val = inw(dev->iobase + PCI1723_DIO_CTRL_REG); + if (!(val & PCI1723_DIO_CTRL_LDIO)) + s->io_bits |= 0x00ff; /* low byte output */ + if (!(val & PCI1723_DIO_CTRL_HDIO)) + s->io_bits |= 0xff00; /* high byte output */ + s->state = inw(dev->iobase + PCI1723_DIO_DATA_REG); return 0; } -static void pci1723_detach(struct comedi_device *dev) -{ - if (dev->iobase) - pci1723_reset(dev); - comedi_pci_detach(dev); -} - static struct comedi_driver adv_pci1723_driver = { .driver_name = "adv_pci1723", .module = THIS_MODULE, .auto_attach = pci1723_auto_attach, - .detach = pci1723_detach, + .detach = comedi_pci_detach, }; static int adv_pci1723_pci_probe(struct pci_dev *dev, @@ -318,5 +230,5 @@ static struct pci_driver adv_pci1723_pci_driver = { module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Advantech PCI-1723 Comedi driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c index 2697758b1ed9..a8d28403262e 100644 --- a/drivers/staging/comedi/drivers/adv_pci1724.c +++ b/drivers/staging/comedi/drivers/adv_pci1724.c @@ -1,122 +1,76 @@ /* - comedi/drivers/adv_pci1724.c - This is a driver for the Advantech PCI-1724U card. - - Author: Frank Mori Hess <fmh6jj@gmail.com> - Copyright (C) 2013 GnuBIO Inc - - 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. -*/ + * adv_pci1724.c + * Comedi driver for the Advantech PCI-1724U card. + * + * Author: Frank Mori Hess <fmh6jj@gmail.com> + * Copyright (C) 2013 GnuBIO Inc + * + * 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: adv_1724 -Description: Advantech PCI-1724U -Author: Frank Mori Hess <fmh6jj@gmail.com> -Status: works -Updated: 2013-02-09 -Devices: [Advantech] PCI-1724U (adv_pci1724) - -Subdevice 0 is the analog output. -Subdevice 1 is the offset calibration for the analog output. -Subdevice 2 is the gain calibration for the analog output. - -The calibration offset and gains have quite a large effect -on the analog output, so it is possible to adjust the analog output to -have an output range significantly different from the board's -nominal output ranges. For a calibrated +/- 10V range, the analog -output's offset will be set somewhere near mid-range (0x2000) and its -gain will be near maximum (0x3fff). - -There is really no difference between the board's documented 0-20mA -versus 4-20mA output ranges. To pick one or the other is simply a matter -of adjusting the offset and gain calibration until the board outputs in -the desired range. - -Configuration options: - None - -Manual configuration of comedi devices is not supported by this driver; -supported PCI devices are configured as comedi devices automatically. - -*/ + * Driver: adv_pci1724 + * Description: Advantech PCI-1724U + * Devices: (Advantech) PCI-1724U [adv_pci1724] + * Author: Frank Mori Hess <fmh6jj@gmail.com> + * Updated: 2013-02-09 + * Status: works + * + * Configuration Options: not applicable, uses comedi PCI auto config + * + * Subdevice 0 is the analog output. + * Subdevice 1 is the offset calibration for the analog output. + * Subdevice 2 is the gain calibration for the analog output. + * + * The calibration offset and gains have quite a large effect on the + * analog output, so it is possible to adjust the analog output to + * have an output range significantly different from the board's + * nominal output ranges. For a calibrated +/-10V range, the analog + * output's offset will be set somewhere near mid-range (0x2000) and + * its gain will be near maximum (0x3fff). + * + * There is really no difference between the board's documented 0-20mA + * versus 4-20mA output ranges. To pick one or the other is simply a + * matter of adjusting the offset and gain calibration until the board + * outputs in the desired range. + */ #include <linux/module.h> -#include <linux/delay.h> #include <linux/pci.h> #include "../comedidev.h" -#define PCI_VENDOR_ID_ADVANTECH 0x13fe - -#define NUM_AO_CHANNELS 32 - -/* register offsets */ -enum board_registers { - DAC_CONTROL_REG = 0x0, - SYNC_OUTPUT_REG = 0x4, - EEPROM_CONTROL_REG = 0x8, - SYNC_OUTPUT_TRIGGER_REG = 0xc, - BOARD_ID_REG = 0x10 -}; - -/* bit definitions for registers */ -enum dac_control_contents { - DAC_DATA_MASK = 0x3fff, - DAC_DESTINATION_MASK = 0xc000, - DAC_NORMAL_MODE = 0xc000, - DAC_OFFSET_MODE = 0x8000, - DAC_GAIN_MODE = 0x4000, - DAC_CHANNEL_SELECT_MASK = 0xf0000, - DAC_GROUP_SELECT_MASK = 0xf00000 -}; - -static uint32_t dac_data_bits(uint16_t dac_data) -{ - return dac_data & DAC_DATA_MASK; -} - -static uint32_t dac_channel_select_bits(unsigned channel) -{ - return (channel << 16) & DAC_CHANNEL_SELECT_MASK; -} - -static uint32_t dac_group_select_bits(unsigned group) -{ - return (1 << (20 + group)) & DAC_GROUP_SELECT_MASK; -} - -static uint32_t dac_channel_and_group_select_bits(unsigned comedi_channel) -{ - return dac_channel_select_bits(comedi_channel % 8) | - dac_group_select_bits(comedi_channel / 8); -} - -enum sync_output_contents { - SYNC_MODE = 0x1, - DAC_BUSY = 0x2, /* dac state machine is not ready */ -}; - -enum sync_output_trigger_contents { - SYNC_TRIGGER_BITS = 0x0 /* any value works */ -}; - -enum board_id_contents { - BOARD_ID_MASK = 0xf -}; - -static const struct comedi_lrange ao_ranges_1724 = { +/* + * PCI bar 2 Register I/O map (dev->iobase) + */ +#define PCI1724_DAC_CTRL_REG 0x00 +#define PCI1724_DAC_CTRL_GX(x) (1 << (20 + ((x) / 8))) +#define PCI1724_DAC_CTRL_CX(x) (((x) % 8) << 16) +#define PCI1724_DAC_CTRL_MODE_GAIN (1 << 14) +#define PCI1724_DAC_CTRL_MODE_OFFSET (2 << 14) +#define PCI1724_DAC_CTRL_MODE_NORMAL (3 << 14) +#define PCI1724_DAC_CTRL_MODE_MASK (3 << 14) +#define PCI1724_DAC_CTRL_DATA(x) (((x) & 0x3fff) << 0) +#define PCI1724_SYNC_CTRL_REG 0x04 +#define PCI1724_SYNC_CTRL_DACSTAT (1 << 1) +#define PCI1724_SYNC_CTRL_SYN (1 << 0) +#define PCI1724_EEPROM_CTRL_REG 0x08 +#define PCI1724_SYNC_TRIG_REG 0x0c /* any value works */ +#define PCI1724_BOARD_ID_REG 0x10 +#define PCI1724_BOARD_ID_MASK (0xf << 0) + +static const struct comedi_lrange adv_pci1724_ao_ranges = { 4, { BIP_RANGE(10), RANGE_mA(0, 20), @@ -125,254 +79,120 @@ static const struct comedi_lrange ao_ranges_1724 = { } }; -/* this structure is for data unique to this hardware driver. */ -struct adv_pci1724_private { - int ao_value[NUM_AO_CHANNELS]; - int offset_value[NUM_AO_CHANNELS]; - int gain_value[NUM_AO_CHANNELS]; -}; - -static int wait_for_dac_idle(struct comedi_device *dev) -{ - static const int timeout = 10000; - int i; - - for (i = 0; i < timeout; ++i) { - if ((inl(dev->iobase + SYNC_OUTPUT_REG) & DAC_BUSY) == 0) - break; - udelay(1); - } - if (i == timeout) { - dev_err(dev->class_dev, - "Timed out waiting for dac to become idle\n"); - return -EIO; - } - return 0; -} - -static int set_dac(struct comedi_device *dev, unsigned mode, unsigned channel, - unsigned data) -{ - int retval; - unsigned control_bits; - - retval = wait_for_dac_idle(dev); - if (retval < 0) - return retval; - - control_bits = mode; - control_bits |= dac_channel_and_group_select_bits(channel); - control_bits |= dac_data_bits(data); - outl(control_bits, dev->iobase + DAC_CONTROL_REG); - return 0; -} - -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int adv_pci1724_dac_idle(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct adv_pci1724_private *devpriv = dev->private; - int channel = CR_CHAN(insn->chanspec); - int retval; - int i; + unsigned int status; - /* turn off synchronous mode */ - outl(0, dev->iobase + SYNC_OUTPUT_REG); - - for (i = 0; i < insn->n; ++i) { - retval = set_dac(dev, DAC_NORMAL_MODE, channel, data[i]); - if (retval < 0) - return retval; - devpriv->ao_value[channel] = data[i]; - } - return insn->n; + status = inl(dev->iobase + PCI1724_SYNC_CTRL_REG); + if ((status & PCI1724_SYNC_CTRL_DACSTAT) == 0) + return 0; + return -EBUSY; } -static int ao_readback_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int adv_pci1724_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct adv_pci1724_private *devpriv = dev->private; - int channel = CR_CHAN(insn->chanspec); - int i; - - if (devpriv->ao_value[channel] < 0) { - dev_err(dev->class_dev, - "Cannot read back channels which have not yet been written to\n"); - return -EIO; - } - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_value[channel]; - - return insn->n; -} - -static int offset_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct adv_pci1724_private *devpriv = dev->private; - int channel = CR_CHAN(insn->chanspec); - int retval; - int i; - - /* turn off synchronous mode */ - outl(0, dev->iobase + SYNC_OUTPUT_REG); - - for (i = 0; i < insn->n; ++i) { - retval = set_dac(dev, DAC_OFFSET_MODE, channel, data[i]); - if (retval < 0) - return retval; - devpriv->offset_value[channel] = data[i]; - } - - return insn->n; -} - -static int offset_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct adv_pci1724_private *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); + unsigned long mode = (unsigned long)s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int ctrl; + int ret; int i; - if (devpriv->offset_value[channel] < 0) { - dev_err(dev->class_dev, - "Cannot read back channels which have not yet been written to\n"); - return -EIO; - } - for (i = 0; i < insn->n; i++) - data[i] = devpriv->offset_value[channel]; - - return insn->n; -} - -static int gain_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct adv_pci1724_private *devpriv = dev->private; - int channel = CR_CHAN(insn->chanspec); - int retval; - int i; + ctrl = PCI1724_DAC_CTRL_GX(chan) | PCI1724_DAC_CTRL_CX(chan) | mode; /* turn off synchronous mode */ - outl(0, dev->iobase + SYNC_OUTPUT_REG); + outl(0, dev->iobase + PCI1724_SYNC_CTRL_REG); for (i = 0; i < insn->n; ++i) { - retval = set_dac(dev, DAC_GAIN_MODE, channel, data[i]); - if (retval < 0) - return retval; - devpriv->gain_value[channel] = data[i]; - } + unsigned int val = data[i]; - return insn->n; -} + ret = comedi_timeout(dev, s, insn, adv_pci1724_dac_idle, 0); + if (ret) + return ret; -static int gain_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct adv_pci1724_private *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); - int i; + outl(ctrl | PCI1724_DAC_CTRL_DATA(val), + dev->iobase + PCI1724_DAC_CTRL_REG); - if (devpriv->gain_value[channel] < 0) { - dev_err(dev->class_dev, - "Cannot read back channels which have not yet been written to\n"); - return -EIO; + s->readback[chan] = val; } - for (i = 0; i < insn->n; i++) - data[i] = devpriv->gain_value[channel]; return insn->n; } -/* Allocate and initialize the subdevice structures. - */ -static int setup_subdevices(struct comedi_device *dev) +static int adv_pci1724_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct comedi_subdevice *s; + unsigned int board_id; int ret; + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 2); + board_id = inl(dev->iobase + PCI1724_BOARD_ID_REG); + dev_info(dev->class_dev, "board id: %d\n", + board_id & PCI1724_BOARD_ID_MASK); + ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; - /* analog output subdevice */ + /* Analog Output subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; - s->n_chan = NUM_AO_CHANNELS; - s->maxdata = 0x3fff; - s->range_table = &ao_ranges_1724; - s->insn_read = ao_readback_insn; - s->insn_write = ao_winsn; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; + s->n_chan = 32; + s->maxdata = 0x3fff; + s->range_table = &adv_pci1724_ao_ranges; + s->insn_write = adv_pci1724_insn_write; + s->private = (void *)PCI1724_DAC_CTRL_MODE_NORMAL; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; - /* offset calibration */ + /* Offset Calibration subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = NUM_AO_CHANNELS; - s->insn_read = offset_read_insn; - s->insn_write = offset_write_insn; - s->maxdata = 0x3fff; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 32; + s->maxdata = 0x3fff; + s->insn_write = adv_pci1724_insn_write; + s->private = (void *)PCI1724_DAC_CTRL_MODE_OFFSET; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; - /* gain calibration */ + /* Gain Calibration subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = NUM_AO_CHANNELS; - s->insn_read = gain_read_insn; - s->insn_write = gain_write_insn; - s->maxdata = 0x3fff; - - return 0; -} - -static int adv_pci1724_auto_attach(struct comedi_device *dev, - unsigned long context_unused) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct adv_pci1724_private *devpriv; - int i; - int retval; - unsigned int board_id; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - /* init software copies of output values to indicate we don't know - * what the output value is since it has never been written. */ - for (i = 0; i < NUM_AO_CHANNELS; ++i) { - devpriv->ao_value[i] = -1; - devpriv->offset_value[i] = -1; - devpriv->gain_value[i] = -1; - } - - retval = comedi_pci_enable(dev); - if (retval) - return retval; - - dev->iobase = pci_resource_start(pcidev, 2); - board_id = inl(dev->iobase + BOARD_ID_REG) & BOARD_ID_MASK; - dev_info(dev->class_dev, "board id: %d\n", board_id); - - retval = setup_subdevices(dev); - if (retval < 0) - return retval; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 32; + s->maxdata = 0x3fff; + s->insn_write = adv_pci1724_insn_write; + s->private = (void *)PCI1724_DAC_CTRL_MODE_GAIN; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; - dev_info(dev->class_dev, "%s (pci %s) attached, board id: %u\n", - dev->board_name, pci_name(pcidev), board_id); return 0; } static struct comedi_driver adv_pci1724_driver = { - .driver_name = "adv_pci1724", - .module = THIS_MODULE, - .auto_attach = adv_pci1724_auto_attach, - .detach = comedi_pci_detach, + .driver_name = "adv_pci1724", + .module = THIS_MODULE, + .auto_attach = adv_pci1724_auto_attach, + .detach = comedi_pci_detach, }; static int adv_pci1724_pci_probe(struct pci_dev *dev, @@ -389,12 +209,11 @@ static const struct pci_device_id adv_pci1724_pci_table[] = { MODULE_DEVICE_TABLE(pci, adv_pci1724_pci_table); static struct pci_driver adv_pci1724_pci_driver = { - .name = "adv_pci1724", - .id_table = adv_pci1724_pci_table, - .probe = adv_pci1724_pci_probe, - .remove = comedi_pci_auto_unconfig, + .name = "adv_pci1724", + .id_table = adv_pci1724_pci_table, + .probe = adv_pci1724_pci_probe, + .remove = comedi_pci_auto_unconfig, }; - module_comedi_pci_driver(adv_pci1724_driver, adv_pci1724_pci_driver); MODULE_AUTHOR("Frank Mori Hess <fmh6jj@gmail.com>"); diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index f2e2d7e163bf..09609d6d02da 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -930,7 +930,7 @@ static int pci1760_attach(struct comedi_device *dev) s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_READABLE; s->n_chan = 8; s->maxdata = 1; s->len_chanlist = 8; @@ -939,7 +939,7 @@ static int pci1760_attach(struct comedi_device *dev) s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 8; s->maxdata = 1; s->len_chanlist = 8; @@ -978,7 +978,7 @@ static int pci_dio_add_di(struct comedi_device *dev, const struct dio_boardtype *this_board = dev->board_ptr; s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags; + s->subdev_flags = SDF_READABLE | d->specflags; if (d->chans > 16) s->subdev_flags |= SDF_LSAMPL; s->n_chan = d->chans; @@ -1008,7 +1008,7 @@ static int pci_dio_add_do(struct comedi_device *dev, const struct dio_boardtype *this_board = dev->board_ptr; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE; if (d->chans > 16) s->subdev_flags |= SDF_LSAMPL; s->n_chan = d->chans; diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index 538277a691b2..fbc3e5aa94cb 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -212,7 +212,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table = &range_aio_aio12_8; s->insn_write = aio_aio12_8_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/amcc_s5933.h b/drivers/staging/comedi/drivers/amcc_s5933.h index cf6a497b092c..d4b8c0195bd3 100644 --- a/drivers/staging/comedi/drivers/amcc_s5933.h +++ b/drivers/staging/comedi/drivers/amcc_s5933.h @@ -110,6 +110,8 @@ #define AGCSTS_TCZERO_MASK 0x000000c0 #define AGCSTS_FIFO_ST_MASK 0x0000003f +#define AGCSTS_TC_ENABLE 0x10000000 + #define AGCSTS_RESET_MBFLAGS 0x08000000 #define AGCSTS_RESET_P2A_FIFO 0x04000000 #define AGCSTS_RESET_A2P_FIFO 0x02000000 diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index 2c1bfb09601d..26aad705aad3 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -120,7 +120,6 @@ struct dio200_subdev_intr { unsigned int ofs; unsigned int valid_isns; unsigned int enabled_isns; - unsigned int stopcount; bool active:1; }; @@ -256,7 +255,6 @@ static void dio200_read_scan_intr(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int triggered) { - struct dio200_subdev_intr *subpriv = s->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned short val; unsigned int n, ch; @@ -267,26 +265,12 @@ static void dio200_read_scan_intr(struct comedi_device *dev, if (triggered & (1U << ch)) val |= (1U << n); } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s, val)) { - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - } else { - /* Error! Stop acquisition. */ - dio200_stop_intr(dev, s); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; - dev_err(dev->class_dev, "buffer overflow\n"); - } - /* Check for end of acquisition. */ - if (cmd->stop_src == TRIG_COUNT) { - if (subpriv->stopcount > 0) { - subpriv->stopcount--; - if (subpriv->stopcount == 0) { - s->async->events |= COMEDI_CB_EOA; - dio200_stop_intr(dev, s); - } - } - } + comedi_buf_write_samples(s, &val, 1); + + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) + s->async->events |= COMEDI_CB_EOA; } static int dio200_handle_read_intr(struct comedi_device *dev, @@ -297,13 +281,11 @@ static int dio200_handle_read_intr(struct comedi_device *dev, unsigned triggered; unsigned intstat; unsigned cur_enabled; - unsigned int oldevents; unsigned long flags; triggered = 0; spin_lock_irqsave(&subpriv->spinlock, flags); - oldevents = s->async->events; if (board->has_int_sce) { /* * Collect interrupt sources that have triggered and disable @@ -356,8 +338,7 @@ static int dio200_handle_read_intr(struct comedi_device *dev, } spin_unlock_irqrestore(&subpriv->spinlock, flags); - if (oldevents != s->async->events) - comedi_event(dev, s); + comedi_handle_events(dev, s); return (triggered != 0); } @@ -436,7 +417,6 @@ static int dio200_subdev_intr_cmd(struct comedi_device *dev, spin_lock_irqsave(&subpriv->spinlock, flags); subpriv->active = true; - subpriv->stopcount = cmd->stop_arg; if (cmd->start_src == TRIG_INT) s->async->inttrig = dio200_inttrig_start_intr; @@ -469,7 +449,7 @@ static int dio200_subdev_intr_init(struct comedi_device *dev, dio200_write8(dev, subpriv->ofs, 0); s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_PACKED; if (board->has_int_sce) { s->n_chan = DIO200_MAX_ISNS; s->len_chanlist = DIO200_MAX_ISNS; diff --git a/drivers/staging/comedi/drivers/amplc_pc236_common.c b/drivers/staging/comedi/drivers/amplc_pc236_common.c index 963c5d868b81..be87172d1f3f 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236_common.c +++ b/drivers/staging/comedi/drivers/amplc_pc236_common.c @@ -135,9 +135,8 @@ static irqreturn_t pc236_interrupt(int irq, void *d) handled = pc236_intr_check(dev); if (dev->attached && handled) { - comedi_buf_put(s, 0); - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(dev, s); + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); } return IRQ_RETVAL(handled); } diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index f8e551d8fd9e..b1946ce6ecc1 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -83,7 +83,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) s = &dev->subdevices[0]; /* digital output subdevice */ s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 3bbbb57f19d6..924c8298c7a0 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -381,7 +381,6 @@ struct pci224_private { unsigned short daccon; unsigned int cached_div1; unsigned int cached_div2; - unsigned int ao_stop_count; unsigned short ao_enab; /* max 16 channels so 'short' will do */ unsigned char intsce; }; @@ -514,30 +513,21 @@ 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 num_scans = comedi_nscans_left(s, 0); unsigned int room; unsigned short dacstat; unsigned int i, n; - /* Determine number of scans available in buffer. */ - 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; - } - /* Determine how much room is in the FIFO (in samples). */ dacstat = inw(dev->iobase + PCI224_DACCON); switch (dacstat & PCI224_DACCON_FIFOFL_MASK) { case PCI224_DACCON_FIFOFL_EMPTY: room = PCI224_FIFO_ROOM_EMPTY; if (cmd->stop_src == TRIG_COUNT && - devpriv->ao_stop_count == 0) { + s->async->scans_done >= cmd->stop_arg) { /* FIFO empty at end of counted acquisition. */ s->async->events |= COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } break; @@ -568,25 +558,23 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, /* Process scans. */ for (n = 0; n < num_scans; n++) { - cfc_read_array_from_buffer(s, &devpriv->ao_scan_vals[0], - bytes_per_scan); + comedi_buf_read_samples(s, &devpriv->ao_scan_vals[0], + cmd->chanlist_len); for (i = 0; i < cmd->chanlist_len; i++) { outw(devpriv->ao_scan_vals[devpriv->ao_scan_order[i]], dev->iobase + PCI224_DACDATA); } } - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ao_stop_count -= num_scans; - if (devpriv->ao_stop_count == 0) { - /* - * Change FIFO interrupt trigger level to wait - * until FIFO is empty. - */ - devpriv->daccon = COMBINE(devpriv->daccon, - PCI224_DACCON_FIFOINTR_EMPTY, - PCI224_DACCON_FIFOINTR_MASK); - outw(devpriv->daccon, dev->iobase + PCI224_DACCON); - } + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) { + /* + * Change FIFO interrupt trigger level to wait + * until FIFO is empty. + */ + devpriv->daccon = COMBINE(devpriv->daccon, + PCI224_DACCON_FIFOINTR_EMPTY, + PCI224_DACCON_FIFOINTR_MASK); + outw(devpriv->daccon, dev->iobase + PCI224_DACCON); } if ((devpriv->daccon & PCI224_DACCON_TRIG_MASK) == PCI224_DACCON_TRIG_NONE) { @@ -618,7 +606,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, outw(devpriv->daccon, dev->iobase + PCI224_DACCON); } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static int pci224_ao_inttrig_start(struct comedi_device *dev, @@ -908,14 +896,6 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->scan_begin_src == TRIG_TIMER) pci224_ao_start_pacer(dev, s); - /* - * Sort out end of acquisition. - */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->ao_stop_count = cmd->stop_arg; - else /* TRIG_EXT | TRIG_NONE */ - devpriv->ao_stop_count = 0; - spin_lock_irqsave(&devpriv->ao_spinlock, flags); if (cmd->start_src == TRIG_INT) { s->async->inttrig = pci224_ao_inttrig_start; @@ -1095,7 +1075,6 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_model) s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = thisboard->ao_range; s->insn_write = pci224_ao_insn_write; - s->insn_read = comedi_readback_insn_read; s->len_chanlist = s->n_chan; dev->write_subdev = s; s->do_cmd = pci224_ao_cmd; diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 01796cd28e5b..49806a5e514c 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -35,7 +35,7 @@ * automatically. * * The PCI230+ and PCI260+ have the same PCI device IDs as the PCI230 and - * PCI260, but can be distinguished by the the size of the PCI regions. A + * PCI260, but can be distinguished by the size of the PCI regions. A * card will be configured as a "+" model if detected as such. * * Subdevices: @@ -490,9 +490,6 @@ struct pci230_private { spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */ spinlock_t ao_stop_spinlock; /* Spin lock for stopping AO command */ unsigned long daqio; /* PCI230's DAQ I/O space */ - unsigned int ai_scan_count; /* Number of AI scans remaining */ - unsigned int ai_scan_pos; /* Current position within AI scan */ - unsigned int ao_scan_count; /* Number of AO scans remaining. */ int intr_cpuid; /* ID of CPU running ISR */ unsigned short hwver; /* Hardware version (for '+' models) */ unsigned short adccon; /* ADCCON register value */ @@ -1074,37 +1071,27 @@ static void pci230_ao_stop(struct comedi_device *dev, static void pci230_handle_ao_nofifo(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pci230_private *devpriv = dev->private; - unsigned short data; - int i, ret; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned short data; + int i; - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) return; + for (i = 0; i < cmd->chanlist_len; i++) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); - /* Read sample from Comedi's circular buffer. */ - ret = comedi_buf_get(s, &data); - if (ret == 0) { - s->async->events |= COMEDI_CB_OVERFLOW; - pci230_ao_stop(dev, s); - dev_err(dev->class_dev, "AO buffer underrun\n"); + if (!comedi_buf_read_samples(s, &data, 1)) { + async->events |= COMEDI_CB_OVERFLOW; return; } pci230_ao_write_nofifo(dev, data, chan); s->readback[chan] = data; } - async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ao_scan_count--; - if (devpriv->ao_scan_count == 0) { - /* End of acquisition. */ - async->events |= COMEDI_CB_EOA; - pci230_ao_stop(dev, s); - } - } + + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; } /* @@ -1117,26 +1104,18 @@ static bool pci230_handle_ao_fifo(struct comedi_device *dev, struct pci230_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - unsigned int num_scans; + unsigned int num_scans = comedi_nscans_left(s, 0); unsigned int room; unsigned short dacstat; unsigned int i, n; unsigned int events = 0; - bool running; /* Get DAC FIFO status. */ dacstat = inw(devpriv->daqio + PCI230_DACCON); - /* Determine number of scans available in buffer. */ - 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; - if (devpriv->ao_scan_count == 0) { - /* End of acquisition. */ - events |= COMEDI_CB_EOA; - } - } + + if (cmd->stop_src == TRIG_COUNT && num_scans == 0) + events |= COMEDI_CB_EOA; + if (events == 0) { /* Check for FIFO underrun. */ if (dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) { @@ -1175,27 +1154,22 @@ static bool pci230_handle_ao_fifo(struct comedi_device *dev, unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned short datum; - comedi_buf_get(s, &datum); + comedi_buf_read_samples(s, &datum, 1); pci230_ao_write_fifo(dev, datum, chan); s->readback[chan] = datum; } } - events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK; - 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 - * to FIFO. Set FIFO interrupt trigger level - * to 'empty'. - */ - devpriv->daccon = - (devpriv->daccon & - ~PCI230P2_DAC_INT_FIFO_MASK) | - PCI230P2_DAC_INT_FIFO_EMPTY; - outw(devpriv->daccon, - devpriv->daqio + PCI230_DACCON); - } + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { + /* + * All data for the command has been written + * to FIFO. Set FIFO interrupt trigger level + * to 'empty'. + */ + devpriv->daccon &= ~PCI230P2_DAC_INT_FIFO_MASK; + devpriv->daccon |= PCI230P2_DAC_INT_FIFO_EMPTY; + outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON); } /* Check if FIFO underrun occurred while writing to FIFO. */ dacstat = inw(devpriv->daqio + PCI230_DACCON); @@ -1204,15 +1178,8 @@ static bool pci230_handle_ao_fifo(struct comedi_device *dev, events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; } } - if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { - /* Stopping AO due to completion or error. */ - pci230_ao_stop(dev, s); - running = false; - } else { - running = true; - } async->events |= events; - return running; + return !(async->events & COMEDI_CB_CANCEL_MASK); } static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, @@ -1235,7 +1202,7 @@ static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, /* Not using DAC FIFO. */ spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); pci230_handle_ao_nofifo(dev, s); - comedi_event(dev, s); + comedi_handle_events(dev, s); } else { /* Using DAC FIFO. */ /* Read DACSWTRIG register to trigger conversion. */ @@ -1265,7 +1232,7 @@ static void pci230_ao_start(struct comedi_device *dev, /* Preload FIFO data. */ run = pci230_handle_ao_fifo(dev, s); - comedi_event(dev, s); + comedi_handle_events(dev, s); if (!run) { /* Stopped. */ return; @@ -1354,8 +1321,6 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return -EBUSY; } - devpriv->ao_scan_count = cmd->stop_arg; - /* * Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale @@ -1754,19 +1719,15 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, { struct pci230_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int scanlen = cmd->scan_end_arg; unsigned int wake; unsigned short triglev; unsigned short adccon; if (cmd->flags & CMDF_WAKE_EOS) - wake = scanlen - devpriv->ai_scan_pos; - else if (cmd->stop_src != TRIG_COUNT || - devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || - scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) - wake = PCI230_ADC_FIFOLEVEL_HALFFULL; + wake = cmd->scan_end_arg - s->async->cur_chan; else - wake = devpriv->ai_scan_count * scanlen - devpriv->ai_scan_pos; + wake = comedi_nsamples_left(s, PCI230_ADC_FIFOLEVEL_HALFFULL); + if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) { triglev = PCI230_ADC_INT_FIFO_HALF; } else if (wake > 1 && devpriv->hwver > 0) { @@ -2059,28 +2020,17 @@ static void pci230_handle_ai(struct comedi_device *dev, 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; + unsigned short val; /* Determine number of samples to read. */ - if (cmd->stop_src != TRIG_COUNT) { - todo = PCI230_ADC_FIFOLEVEL_HALFFULL; - } else if (devpriv->ai_scan_count == 0) { - todo = 0; - } else if (devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL || - scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL) { - todo = PCI230_ADC_FIFOLEVEL_HALFFULL; - } else { - todo = devpriv->ai_scan_count * scanlen - devpriv->ai_scan_pos; - if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL) - todo = PCI230_ADC_FIFOLEVEL_HALFFULL; - } + todo = comedi_nsamples_left(s, PCI230_ADC_FIFOLEVEL_HALFFULL); if (todo == 0) return; + fifoamount = 0; for (i = 0; i < todo; i++) { if (fifoamount == 0) { @@ -2092,7 +2042,7 @@ static void pci230_handle_ai(struct comedi_device *dev, * unnoticed by the caller. */ dev_err(dev->class_dev, "AI FIFO overrun\n"); - events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + async->events |= COMEDI_CB_ERROR; break; } else if (status_fifo & PCI230_ADC_FIFO_EMPTY) { /* FIFO empty. */ @@ -2111,37 +2061,23 @@ static void pci230_handle_ai(struct comedi_device *dev, fifoamount = 1; } } - /* Read sample and store in Comedi's circular buffer. */ - if (comedi_buf_put(s, pci230_ai_read(dev)) == 0) { - events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; - dev_err(dev->class_dev, "AI buffer overflow\n"); + + val = pci230_ai_read(dev); + if (!comedi_buf_write_samples(s, &val, 1)) break; - } + fifoamount--; - devpriv->ai_scan_pos++; - if (devpriv->ai_scan_pos == scanlen) { - /* End of scan. */ - devpriv->ai_scan_pos = 0; - devpriv->ai_scan_count--; - async->events |= COMEDI_CB_EOS; + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { + async->events |= COMEDI_CB_EOA; + break; } } - if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { - /* End of acquisition. */ - events |= COMEDI_CB_EOA; - } else { - /* More samples required, tell Comedi to block. */ - events |= COMEDI_CB_BLOCK; - } - async->events |= events; - if (async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - /* disable hardware conversions */ - pci230_ai_stop(dev, s); - } else { - /* update FIFO interrupt trigger level */ + + /* update FIFO interrupt trigger level if still running */ + if (!(async->events & COMEDI_CB_CANCEL_MASK)) pci230_ai_update_fifo_trigger_level(dev, s); - } } static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) @@ -2177,9 +2113,6 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (!pci230_claim_shared(dev, res_mask, OWNER_AICMD)) return -EBUSY; - devpriv->ai_scan_count = cmd->stop_arg; - devpriv->ai_scan_pos = 0; /* Position within scan. */ - /* * Steps: * - Set channel scan list. @@ -2355,7 +2288,8 @@ static irqreturn_t pci230_interrupt(int irq, void *d) unsigned char status_int, valid_status_int, temp_ier; struct comedi_device *dev = (struct comedi_device *)d; struct pci230_private *devpriv = dev->private; - struct comedi_subdevice *s; + struct comedi_subdevice *s_ao = dev->write_subdev; + struct comedi_subdevice *s_ai = dev->read_subdev; unsigned long irqflags; /* Read interrupt status/enable register. */ @@ -2385,23 +2319,14 @@ static irqreturn_t pci230_interrupt(int irq, void *d) * two. */ - if (valid_status_int & PCI230_INT_ZCLK_CT1) { - s = dev->write_subdev; - pci230_handle_ao_nofifo(dev, s); - comedi_event(dev, s); - } + if (valid_status_int & PCI230_INT_ZCLK_CT1) + pci230_handle_ao_nofifo(dev, s_ao); - if (valid_status_int & PCI230P2_INT_DAC) { - s = dev->write_subdev; - pci230_handle_ao_fifo(dev, s); - comedi_event(dev, s); - } + if (valid_status_int & PCI230P2_INT_DAC) + pci230_handle_ao_fifo(dev, s_ao); - if (valid_status_int & PCI230_INT_ADC) { - s = dev->read_subdev; - pci230_handle_ai(dev, s); - comedi_event(dev, s); - } + if (valid_status_int & PCI230_INT_ADC) + pci230_handle_ai(dev, s_ai); /* Reenable interrupts. */ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); @@ -2410,6 +2335,9 @@ static irqreturn_t pci230_interrupt(int irq, void *d) devpriv->intr_running = false; spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + comedi_handle_events(dev, s_ao); + comedi_handle_events(dev, s_ai); + return IRQ_HANDLED; } @@ -2583,7 +2511,6 @@ static int pci230_auto_attach(struct comedi_device *dev, s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = &pci230_ao_range; s->insn_write = pci230_ao_insn_write; - s->insn_read = comedi_readback_insn_read; s->len_chanlist = 2; if (dev->irq) { dev->write_subdev = s; diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index 2259bee98d48..0d2224b832ac 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -71,7 +71,7 @@ static int pci263_auto_attach(struct comedi_device *dev, s = &dev->subdevices[0]; /* digital output subdevice */ s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index e03dd6e71415..e7cb7032a910 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -265,7 +265,7 @@ static int c6xdigio_attach(struct comedi_device *dev, s = &dev->subdevices[0]; /* pwm output subdevice */ s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = 500; s->range_table = &range_unknown; diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index f88880aea6da..0a48d2a961d5 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -305,7 +305,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = &das16cs_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 1ec363b7505c..669b1703eb99 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -346,8 +346,6 @@ struct cb_pcidas_private { /* divisors of master clock for analog input pacing */ unsigned int divisor1; unsigned int divisor2; - /* number of analog input samples remaining */ - unsigned int count; /* bits to write to registers */ unsigned int adc_fifo_bits; unsigned int s5933_intcsr_bits; @@ -358,11 +356,6 @@ struct cb_pcidas_private { /* divisors of master clock for analog output pacing */ unsigned int ao_divisor1; unsigned int ao_divisor2; - /* number of analog output samples remaining */ - unsigned int ao_count; - unsigned int caldac_value[NUM_CHANNELS_8800]; - unsigned int trimpot_value[NUM_CHANNELS_8402]; - unsigned int dac08_value; unsigned int calibration_source; }; @@ -596,25 +589,14 @@ static void write_calibration_bitstream(struct comedi_device *dev, } } -static int caldac_8800_write(struct comedi_device *dev, unsigned int address, - uint8_t value) +static void caldac_8800_write(struct comedi_device *dev, + unsigned int chan, uint8_t val) { struct cb_pcidas_private *devpriv = dev->private; - static const int num_caldac_channels = 8; static const int bitstream_length = 11; - unsigned int bitstream = ((address & 0x7) << 8) | value; + unsigned int bitstream = ((chan & 0x7) << 8) | val; static const int caldac_8800_udelay = 1; - if (address >= num_caldac_channels) { - dev_err(dev->class_dev, "illegal caldac channel\n"); - return -1; - } - - if (value == devpriv->caldac_value[address]) - return 1; - - devpriv->caldac_value[address] = value; - write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream, bitstream_length); @@ -623,75 +605,62 @@ static int caldac_8800_write(struct comedi_device *dev, unsigned int address, devpriv->control_status + CALIBRATION_REG); udelay(caldac_8800_udelay); outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); - - return 1; } -static int caldac_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas_caldac_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - const unsigned int channel = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); - return caldac_8800_write(dev, channel, data[0]); -} + if (insn->n) { + unsigned int val = data[insn->n - 1]; -static int caldac_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct cb_pcidas_private *devpriv = dev->private; - - data[0] = devpriv->caldac_value[CR_CHAN(insn->chanspec)]; + if (s->readback[chan] != val) { + caldac_8800_write(dev, chan, val); + s->readback[chan] = val; + } + } - return 1; + return insn->n; } /* 1602/16 pregain offset */ static void dac08_write(struct comedi_device *dev, unsigned int value) { struct cb_pcidas_private *devpriv = dev->private; - unsigned long cal_reg; - - if (devpriv->dac08_value != value) { - devpriv->dac08_value = value; - - cal_reg = devpriv->control_status + CALIBRATION_REG; - value &= 0xff; - value |= cal_enable_bits(dev); + value &= 0xff; + value |= cal_enable_bits(dev); - /* latch the new value into the caldac */ - outw(value, cal_reg); - udelay(1); - outw(value | SELECT_DAC08_BIT, cal_reg); - udelay(1); - outw(value, cal_reg); - udelay(1); - } + /* latch the new value into the caldac */ + outw(value, devpriv->control_status + CALIBRATION_REG); + udelay(1); + outw(value | SELECT_DAC08_BIT, + devpriv->control_status + CALIBRATION_REG); + udelay(1); + outw(value, devpriv->control_status + CALIBRATION_REG); + udelay(1); } -static int dac08_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas_dac08_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int i; - - for (i = 0; i < insn->n; i++) - dac08_write(dev, data[i]); - - return insn->n; -} + unsigned int chan = CR_CHAN(insn->chanspec); -static int dac08_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct cb_pcidas_private *devpriv = dev->private; + if (insn->n) { + unsigned int val = data[insn->n - 1]; - data[0] = devpriv->dac08_value; + if (s->readback[chan] != val) { + dac08_write(dev, val); + s->readback[chan] = val; + } + } - return 1; + return insn->n; } static int trimpot_7376_write(struct comedi_device *dev, uint8_t value) @@ -740,50 +709,41 @@ static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, return 0; } -static int cb_pcidas_trimpot_write(struct comedi_device *dev, - unsigned int channel, unsigned int value) +static void cb_pcidas_trimpot_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) { const struct cb_pcidas_board *thisboard = dev->board_ptr; - struct cb_pcidas_private *devpriv = dev->private; - - if (devpriv->trimpot_value[channel] == value) - return 1; - devpriv->trimpot_value[channel] = value; switch (thisboard->trimpot) { case AD7376: - trimpot_7376_write(dev, value); + trimpot_7376_write(dev, val); break; case AD8402: - trimpot_8402_write(dev, channel, value); + trimpot_8402_write(dev, chan, val); break; default: dev_err(dev->class_dev, "driver bug?\n"); - return -1; + break; } - - return 1; } -static int trimpot_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas_trimpot_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int channel = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); - return cb_pcidas_trimpot_write(dev, channel, data[0]); -} + if (insn->n) { + unsigned int val = data[insn->n - 1]; -static int trimpot_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct cb_pcidas_private *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); - - data[0] = devpriv->trimpot_value[channel]; + if (s->readback[chan] != val) { + cb_pcidas_trimpot_write(dev, chan, val); + s->readback[chan] = val; + } + } - return 1; + return insn->n; } static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev, @@ -976,9 +936,6 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, 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) - devpriv->count = cmd->chanlist_len * cmd->stop_arg; /* enable interrupts */ spin_lock_irqsave(&dev->spinlock, flags); devpriv->adc_fifo_bits |= INTE; @@ -1134,32 +1091,34 @@ static int cb_pcidas_cancel(struct comedi_device *dev, return 0; } +static void cb_pcidas_ao_load_fifo(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int nsamples) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned int nbytes; + + nsamples = comedi_nsamples_left(s, nsamples); + nbytes = comedi_buf_read_samples(s, devpriv->ao_buffer, nsamples); + + nsamples = comedi_bytes_to_samples(s, nbytes); + outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, nsamples); +} + static int cb_pcidas_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; - unsigned int num_bytes, num_points = thisboard->fifo_size; struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &s->async->cmd; + struct comedi_cmd *cmd = &async->cmd; unsigned long flags; if (trig_num != cmd->start_arg) return -EINVAL; - /* load up fifo */ - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points) - num_points = devpriv->ao_count; - - num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer, - num_points * sizeof(short)); - num_points = num_bytes / sizeof(short); - - 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, num_bytes); + cb_pcidas_ao_load_fifo(dev, s, thisboard->fifo_size); /* enable dac half-full and empty interrupts */ spin_lock_irqsave(&dev->spinlock, flags); @@ -1224,9 +1183,6 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) cb_pcidas_ao_load_counters(dev); - /* set number of conversions */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg; /* set pacer source */ spin_lock_irqsave(&dev->spinlock, flags); switch (cmd->scan_begin_src) { @@ -1275,8 +1231,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) struct comedi_subdevice *s = dev->write_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - unsigned int half_fifo = thisboard->fifo_size / 2; - unsigned int num_points; unsigned long flags; if (status & DAEMI) { @@ -1286,32 +1240,17 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) devpriv->control_status + INT_ADCFIFO); spin_unlock_irqrestore(&dev->spinlock, flags); if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) { - if (cmd->stop_src == TRIG_NONE || - (cmd->stop_src == TRIG_COUNT - && devpriv->ao_count)) { + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { + async->events |= COMEDI_CB_EOA; + } else { dev_err(dev->class_dev, "dac fifo underflow\n"); async->events |= COMEDI_CB_ERROR; } - async->events |= COMEDI_CB_EOA; } } else if (status & DAHFI) { - unsigned int num_bytes; + cb_pcidas_ao_load_fifo(dev, s, thisboard->fifo_size / 2); - /* figure out how many points we are writing to fifo */ - num_points = half_fifo; - if (cmd->stop_src == TRIG_COUNT && - devpriv->ao_count < num_points) - num_points = devpriv->ao_count; - num_bytes = - cfc_read_array_from_buffer(s, devpriv->ao_buffer, - num_points * sizeof(short)); - num_points = num_bytes / sizeof(short); - - 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, - num_points); /* clear half-full interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | DAHFI, @@ -1319,7 +1258,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) spin_unlock_irqrestore(&dev->spinlock, flags); } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static irqreturn_t cb_pcidas_interrupt(int irq, void *d) @@ -1362,18 +1301,15 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) /* if fifo half-full */ if (status & ADHFI) { /* read data */ - num_samples = half_fifo; - if (cmd->stop_src == TRIG_COUNT && - num_samples > devpriv->count) { - num_samples = devpriv->count; - } + num_samples = comedi_nsamples_left(s, half_fifo); insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer, num_samples); - cfc_write_array_to_buffer(s, devpriv->ai_buffer, - num_samples * sizeof(short)); - devpriv->count -= num_samples; - if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) + comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples); + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) async->events |= COMEDI_CB_EOA; + /* clear half-full interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | INT, @@ -1382,14 +1318,17 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) /* else if fifo not empty */ } else if (status & (ADNEI | EOBI)) { for (i = 0; i < timeout; i++) { + unsigned short val; + /* break if fifo is empty */ if ((ADNE & inw(devpriv->control_status + INT_ADCFIFO)) == 0) break; - cfc_write_to_buffer(s, inw(devpriv->adc_fifo)); + val = inw(devpriv->adc_fifo); + comedi_buf_write_samples(s, &val, 1); + if (cmd->stop_src == TRIG_COUNT && - --devpriv->count == 0) { - /* end of acquisition */ + async->scans_done >= cmd->stop_arg) { async->events |= COMEDI_CB_EOA; break; } @@ -1419,7 +1358,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -1503,7 +1442,6 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, s->range_table = &cb_pcidas_ao_ranges; /* default to no fifo (*insn_write) */ s->insn_write = cb_pcidas_ao_nofifo_winsn; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -1542,10 +1480,16 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = NUM_CHANNELS_8800; s->maxdata = 0xff; - s->insn_read = caldac_read_insn; - s->insn_write = caldac_write_insn; - for (i = 0; i < s->n_chan; i++) + s->insn_write = cb_pcidas_caldac_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + for (i = 0; i < s->n_chan; i++) { caldac_8800_write(dev, i, s->maxdata / 2); + s->readback[i] = s->maxdata / 2; + } /* trim potentiometer */ s = &dev->subdevices[5]; @@ -1558,10 +1502,16 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, s->n_chan = NUM_CHANNELS_8402; s->maxdata = 0xff; } - s->insn_read = trimpot_read_insn; - s->insn_write = trimpot_write_insn; - for (i = 0; i < s->n_chan; i++) + s->insn_write = cb_pcidas_trimpot_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + for (i = 0; i < s->n_chan; i++) { cb_pcidas_trimpot_write(dev, i, s->maxdata / 2); + s->readback[i] = s->maxdata / 2; + } /* dac08 caldac */ s = &dev->subdevices[6]; @@ -1569,10 +1519,17 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = NUM_CHANNELS_DAC08; - s->insn_read = dac08_read_insn; - s->insn_write = dac08_write_insn; s->maxdata = 0xff; - dac08_write(dev, s->maxdata / 2); + s->insn_write = cb_pcidas_dac08_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + for (i = 0; i < s->n_chan; i++) { + dac08_write(dev, s->maxdata / 2); + s->readback[i] = s->maxdata / 2; + } } else s->type = COMEDI_SUBD_UNUSED; diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 3b6bffc66918..eddb7ace43df 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1065,8 +1065,6 @@ struct pcidas64_private { /* local address (used by dma controller) */ uint32_t local0_iobase; uint32_t local1_iobase; - /* number of analog input samples remaining */ - unsigned int ai_count; /* dma buffers for analog input */ uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT]; /* physical addresses of ai dma buffers */ @@ -1087,8 +1085,6 @@ struct pcidas64_private { dma_addr_t ao_dma_desc_bus_addr; /* keeps track of buffer where the next ao sample should go */ unsigned int ao_dma_index; - /* number of analog output samples remaining */ - unsigned long ao_count; unsigned int hw_revision; /* stc chip hardware revision number */ /* last bits sent to INTR_ENABLE_REG register */ unsigned int intr_enable_bits; @@ -1109,9 +1105,6 @@ struct pcidas64_private { uint8_t i2c_cal_range_bits; /* configure digital triggers to trigger on falling edge */ unsigned int ext_trig_falling; - /* states of various devices stored to enable read-back */ - unsigned int ad8402_state[2]; - unsigned int caldac_state[8]; short ai_cmd_running; unsigned int ai_fifo_segment_length; struct ext_clock_info ext_clock; @@ -2199,10 +2192,6 @@ static void setup_sample_counters(struct comedi_device *dev, { struct pcidas64_private *devpriv = dev->private; - if (cmd->stop_src == TRIG_COUNT) { - /* set software count */ - devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len; - } /* load hardware conversion counter */ if (use_hw_sample_counter(cmd)) { writew(cmd->stop_arg & 0xffff, @@ -2642,8 +2631,6 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev) { struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; unsigned int i; uint16_t prepost_bits; int read_segment, read_index, write_segment, write_index; @@ -2672,26 +2659,21 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev) devpriv->ai_fifo_segment_length - read_index; else num_samples = write_index - read_index; - - if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->ai_count == 0) - break; - if (num_samples > devpriv->ai_count) - num_samples = devpriv->ai_count; - - devpriv->ai_count -= num_samples; - } - if (num_samples < 0) { dev_err(dev->class_dev, "cb_pcidas64: bug! num_samples < 0\n"); break; } + num_samples = comedi_nsamples_left(s, num_samples); + if (num_samples == 0) + break; + for (i = 0; i < num_samples; i++) { - cfc_write_to_buffer(s, - readw(devpriv->main_iobase + - ADC_FIFO_REG)); + unsigned short val; + + val = readw(devpriv->main_iobase + ADC_FIFO_REG); + comedi_buf_write_samples(s, &val, 1); } } while (read_segment != write_segment); @@ -2706,33 +2688,30 @@ static void pio_drain_ai_fifo_32(struct comedi_device *dev) { struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; + unsigned int nsamples; unsigned int i; - unsigned int max_transfer = 100000; uint32_t fifo_data; int write_code = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff; int read_code = readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; - if (cmd->stop_src == TRIG_COUNT) { - if (max_transfer > devpriv->ai_count) - max_transfer = devpriv->ai_count; + nsamples = comedi_nsamples_left(s, 100000); + for (i = 0; read_code != write_code && i < nsamples;) { + unsigned short val; - } - for (i = 0; read_code != write_code && i < max_transfer;) { fifo_data = readl(dev->mmio + ADC_FIFO_REG); - cfc_write_to_buffer(s, fifo_data & 0xffff); + val = fifo_data & 0xffff; + comedi_buf_write_samples(s, &val, 1); i++; - if (i < max_transfer) { - cfc_write_to_buffer(s, (fifo_data >> 16) & 0xffff); + if (i < nsamples) { + val = (fifo_data >> 16) & 0xffff; + comedi_buf_write_samples(s, &val, 1); i++; } read_code = readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; } - devpriv->ai_count -= i; } /* empty fifo */ @@ -2750,8 +2729,7 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) { const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; - struct comedi_async *async = dev->read_subdev->async; - struct comedi_cmd *cmd = &async->cmd; + struct comedi_subdevice *s = dev->read_subdev; uint32_t next_transfer_addr; int j; int num_samples = 0; @@ -2772,16 +2750,10 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] + 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 (cmd->stop_src == TRIG_COUNT) { - if (num_samples > devpriv->ai_count) - num_samples = devpriv->ai_count; - devpriv->ai_count -= num_samples; - } - cfc_write_array_to_buffer(dev->read_subdev, - devpriv->ai_buffer[devpriv-> - ai_dma_index], - num_samples * sizeof(uint16_t)); + num_samples = comedi_nsamples_left(s, dma_transfer_size(dev)); + comedi_buf_write_samples(s, + devpriv->ai_buffer[devpriv->ai_dma_index], + num_samples); devpriv->ai_dma_index = (devpriv->ai_dma_index + 1) % ai_dma_ring_count(thisboard); } @@ -2831,12 +2803,12 @@ static void handle_ai_interrupt(struct comedi_device *dev, spin_unlock_irqrestore(&dev->spinlock, flags); } /* if we are have all the data, then quit */ - if ((cmd->stop_src == TRIG_COUNT && (int)devpriv->ai_count <= 0) || - (cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT))) { + if ((cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) || + (cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT))) async->events |= COMEDI_CB_EOA; - } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static inline unsigned int prev_ao_dma_index(struct comedi_device *dev) @@ -2871,22 +2843,6 @@ static int last_ao_dma_load_completed(struct comedi_device *dev) return 1; } -static int ao_stopped_by_error(struct comedi_device *dev, - const struct comedi_cmd *cmd) -{ - struct pcidas64_private *devpriv = dev->private; - - if (cmd->stop_src == TRIG_NONE) - return 1; - if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->ao_count) - return 1; - if (last_ao_dma_load_completed(dev) == 0) - return 1; - } - return 0; -} - static inline int ao_dma_needs_restart(struct comedi_device *dev, unsigned short dma_status) { @@ -2912,32 +2868,39 @@ static void restart_ao_dma(struct comedi_device *dev) dma_start_sync(dev, 0); } +static unsigned int cb_pcidas64_ao_fill_buffer(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned short *dest, + unsigned int max_bytes) +{ + unsigned int nsamples = comedi_bytes_to_samples(s, max_bytes); + unsigned int actual_bytes; + + nsamples = comedi_nsamples_left(s, nsamples); + actual_bytes = comedi_buf_read_samples(s, dest, nsamples); + + return comedi_bytes_to_samples(s, actual_bytes); +} + static unsigned int load_ao_dma_buffer(struct comedi_device *dev, const struct comedi_cmd *cmd) { struct pcidas64_private *devpriv = dev->private; - unsigned int num_bytes, buffer_index, prev_buffer_index; + struct comedi_subdevice *s = dev->write_subdev; + unsigned int buffer_index = devpriv->ao_dma_index; + unsigned int prev_buffer_index = prev_ao_dma_index(dev); + unsigned int nsamples; + unsigned int nbytes; unsigned int next_bits; - buffer_index = devpriv->ao_dma_index; - prev_buffer_index = prev_ao_dma_index(dev); - - 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) - num_bytes = devpriv->ao_count; - num_bytes -= num_bytes % bytes_in_sample; - - if (num_bytes == 0) + nsamples = cb_pcidas64_ao_fill_buffer(dev, s, + devpriv->ao_buffer[buffer_index], + DMA_BUFFER_SIZE); + if (nsamples == 0) return 0; - num_bytes = cfc_read_array_from_buffer(dev->write_subdev, - devpriv-> - ao_buffer[buffer_index], - num_bytes); - devpriv->ao_dma_desc[buffer_index].transfer_size = - cpu_to_le32(num_bytes); + nbytes = comedi_samples_to_bytes(s, nsamples); + devpriv->ao_dma_desc[buffer_index].transfer_size = cpu_to_le32(nbytes); /* set end of chain bit so we catch underruns */ next_bits = le32_to_cpu(devpriv->ao_dma_desc[buffer_index].next); next_bits |= PLX_END_OF_CHAIN_BIT; @@ -2949,9 +2912,8 @@ static unsigned int load_ao_dma_buffer(struct comedi_device *dev, devpriv->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits); devpriv->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT; - devpriv->ao_count -= num_bytes; - return num_bytes; + return nbytes; } static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) @@ -3016,11 +2978,14 @@ static void handle_ao_interrupt(struct comedi_device *dev, } if ((status & DAC_DONE_BIT)) { - async->events |= COMEDI_CB_EOA; - if (ao_stopped_by_error(dev, cmd)) + if ((cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) || + last_ao_dma_load_completed(dev)) + async->events |= COMEDI_CB_EOA; + else async->events |= COMEDI_CB_ERROR; } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static irqreturn_t handle_interrupt(int irq, void *d) @@ -3191,7 +3156,9 @@ static void set_dac_interval_regs(struct comedi_device *dev, static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) { struct pcidas64_private *devpriv = dev->private; - unsigned int num_bytes; + struct comedi_subdevice *s = dev->write_subdev; + unsigned int nsamples; + unsigned int nbytes; int i; /* clear queue pointer too, since external queue has @@ -3199,22 +3166,23 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); writew(0, devpriv->main_iobase + DAC_BUFFER_CLEAR_REG); - num_bytes = (DAC_FIFO_SIZE / 2) * bytes_in_sample; - if (cmd->stop_src == TRIG_COUNT && - num_bytes / bytes_in_sample > devpriv->ao_count) - num_bytes = devpriv->ao_count * bytes_in_sample; - num_bytes = cfc_read_array_from_buffer(dev->write_subdev, - devpriv->ao_bounce_buffer, - num_bytes); - for (i = 0; i < num_bytes / bytes_in_sample; i++) { + nsamples = cb_pcidas64_ao_fill_buffer(dev, s, + devpriv->ao_bounce_buffer, + DAC_FIFO_SIZE); + if (nsamples == 0) + return -1; + + for (i = 0; i < nsamples; i++) { writew(devpriv->ao_bounce_buffer[i], devpriv->main_iobase + DAC_FIFO_REG); } - devpriv->ao_count -= num_bytes / bytes_in_sample; - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count == 0) + + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) return 0; - num_bytes = load_ao_dma_buffer(dev, cmd); - if (num_bytes == 0) + + nbytes = load_ao_dma_buffer(dev, cmd); + if (nbytes == 0) return -1; load_ao_dma(dev, cmd); @@ -3275,7 +3243,6 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) writew(0x0, devpriv->main_iobase + DAC_CONTROL0_REG); devpriv->ao_dma_index = 0; - devpriv->ao_count = cmd->stop_arg * cmd->chanlist_len; set_dac_select_reg(dev, cmd); set_dac_interval_regs(dev, cmd); @@ -3580,9 +3547,6 @@ static void caldac_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { const struct pcidas64_board *thisboard = dev->board_ptr; - struct pcidas64_private *devpriv = dev->private; - - devpriv->caldac_state[channel] = value; switch (thisboard->layout) { case LAYOUT_60XX: @@ -3597,33 +3561,27 @@ static void caldac_write(struct comedi_device *dev, unsigned int channel, } } -static int calib_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas64_calib_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pcidas64_private *devpriv = dev->private; - int channel = CR_CHAN(insn->chanspec); - - /* return immediately if setting hasn't changed, since - * programming these things is slow */ - if (devpriv->caldac_state[channel] == data[0]) - return 1; - - caldac_write(dev, channel, data[0]); - - return 1; -} + unsigned int chan = CR_CHAN(insn->chanspec); -static int calib_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct pcidas64_private *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); + /* + * Programming the calib device is slow. Only write the + * last data value if the value has changed. + */ + if (insn->n) { + unsigned int val = data[insn->n - 1]; - data[0] = devpriv->caldac_state[channel]; + if (s->readback[chan] != val) { + caldac_write(dev, chan, val); + s->readback[chan] = val; + } + } - return 1; + return insn->n; } static void ad8402_write(struct comedi_device *dev, unsigned int channel, @@ -3635,8 +3593,6 @@ static void ad8402_write(struct comedi_device *dev, unsigned int channel, unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); static const int ad8402_udelay = 1; - devpriv->ad8402_state[channel] = value; - register_bits = SELECT_8402_64XX_BIT; udelay(ad8402_udelay); writew(register_bits, devpriv->main_iobase + CALIBRATION_REG); @@ -3658,35 +3614,27 @@ static void ad8402_write(struct comedi_device *dev, unsigned int channel, } /* for pci-das6402/16, channel 0 is analog input gain and channel 1 is offset */ -static int ad8402_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas64_ad8402_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pcidas64_private *devpriv = dev->private; - int channel = CR_CHAN(insn->chanspec); - - /* return immediately if setting hasn't changed, since - * programming these things is slow */ - if (devpriv->ad8402_state[channel] == data[0]) - return 1; - - devpriv->ad8402_state[channel] = data[0]; - - ad8402_write(dev, channel, data[0]); - - return 1; -} + unsigned int chan = CR_CHAN(insn->chanspec); -static int ad8402_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pcidas64_private *devpriv = dev->private; - unsigned int channel = CR_CHAN(insn->chanspec); + /* + * Programming the calib device is slow. Only write the + * last data value if the value has changed. + */ + if (insn->n) { + unsigned int val = data[insn->n - 1]; - data[0] = devpriv->ad8402_state[channel]; + if (s->readback[chan] != val) { + ad8402_write(dev, chan, val); + s->readback[chan] = val; + } + } - return 1; + return insn->n; } static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) @@ -3816,7 +3764,6 @@ static int setup_subdevices(struct comedi_device *dev) s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = thisboard->ao_range_table; s->insn_write = ao_winsn; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -3849,7 +3796,7 @@ static int setup_subdevices(struct comedi_device *dev) if (thisboard->layout == LAYOUT_64XX) { s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; @@ -3895,10 +3842,16 @@ static int setup_subdevices(struct comedi_device *dev) s->maxdata = 0xfff; else s->maxdata = 0xff; - s->insn_read = calib_read_insn; - s->insn_write = calib_write_insn; - for (i = 0; i < s->n_chan; i++) + s->insn_write = cb_pcidas64_calib_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + for (i = 0; i < s->n_chan; i++) { caldac_write(dev, i, s->maxdata / 2); + s->readback[i] = s->maxdata / 2; + } /* 2 channel ad8402 potentiometer */ s = &dev->subdevices[7]; @@ -3906,11 +3859,17 @@ static int setup_subdevices(struct comedi_device *dev) s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 2; - s->insn_read = ad8402_read_insn; - s->insn_write = ad8402_write_insn; s->maxdata = 0xff; - for (i = 0; i < s->n_chan; i++) + s->insn_write = cb_pcidas64_ad8402_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + for (i = 0; i < s->n_chan; i++) { ad8402_write(dev, i, s->maxdata / 2); + s->readback[i] = s->maxdata / 2; + } } else s->type = COMEDI_SUBD_UNUSED; diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index fe4d2544f3dc..70dd2c9eecdb 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -1,40 +1,45 @@ /* - comedi/drivers/cb_pcimdas.c - Comedi driver for Computer Boards PCIM-DAS1602/16 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/cb_pcimdas.c + * Comedi driver for Computer Boards PCIM-DAS1602/16 and PCIe-DAS1602/16 + * + * 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: cb_pcimdas -Description: Measurement Computing PCI Migration series boards -Devices: [ComputerBoards] PCIM-DAS1602/16 (cb_pcimdas) -Author: Richard Bytheway -Updated: Wed, 13 Nov 2002 12:34:56 +0000 -Status: experimental - -Written to support the PCIM-DAS1602/16 on a 2.4 series kernel. - -Configuration Options: - [0] - PCI bus number - [1] - PCI slot number - -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. -See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. -*/ + * Driver: cb_pcimdas + * Description: Measurement Computing PCI Migration series boards + * Devices: [ComputerBoards] PCIM-DAS1602/16 (cb_pcimdas), PCIe-DAS1602/16 + * Author: Richard Bytheway + * Updated: Mon, 13 Oct 2014 11:57:39 +0000 + * Status: experimental + * + * Written to support the PCIM-DAS1602/16 and PCIe-DAS1602/16. + * + * Configuration Options: + * none + * + * Manual configuration of PCI(e) cards is not supported; they are configured + * automatically. + * + * 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. + * + * http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf + * http://www.mccdaq.com/PDFs/Manuals/pcie-das1602-16.pdf + */ #include <linux/module.h> #include <linux/pci.h> @@ -45,7 +50,7 @@ See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. #include "plx9052.h" #include "8255.h" -/* Registers for the PCIM-DAS1602/16 */ +/* Registers for the PCIM-DAS1602/16 and PCIe-DAS1602/16 */ /* DAC Offsets */ #define ADC_TRIG 0 @@ -221,7 +226,6 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, /* ranges are hardware settable, but not software readable. */ s->range_table = &range_unknown; s->insn_write = cb_pcimdas_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -251,7 +255,8 @@ static int cb_pcimdas_pci_probe(struct pci_dev *dev, } static const struct pci_device_id cb_pcimdas_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) }, /* PCIM-DAS1602/16 */ + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0115) }, /* PCIe-DAS1602/16 */ { 0 } }; MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); @@ -265,5 +270,5 @@ static struct pci_driver cb_pcimdas_pci_driver = { module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for PCIM-DAS1602/16 and PCIe-DAS1602/16"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 8450c99af8b0..85b2f4ab1ba4 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -61,8 +61,7 @@ struct bonded_device { }; struct comedi_bond_private { -# define MAX_BOARD_NAME 256 - char name[MAX_BOARD_NAME]; + char name[256]; struct bonded_device **devs; unsigned ndevs; unsigned nchans; @@ -262,12 +261,10 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) { /* Append dev:subdev to devpriv->name */ char buf[20]; - int left = - MAX_BOARD_NAME - strlen(devpriv->name) - 1; snprintf(buf, sizeof(buf), "%u:%u ", bdev->minor, bdev->subdev); - buf[sizeof(buf) - 1] = 0; - strncat(devpriv->name, buf, left); + strlcat(devpriv->name, buf, + sizeof(devpriv->name)); } } diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index ce2835972507..756be931c1a4 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -23,49 +23,6 @@ #include "../comedidev.h" -static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) -{ - return comedi_bytes_per_scan(s); -} - -static inline void cfc_inc_scan_progress(struct comedi_subdevice *s, - unsigned int num_bytes) -{ - comedi_inc_scan_progress(s, num_bytes); -} - -static inline unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s, - const void *data, - unsigned int num_bytes) -{ - return comedi_write_array_to_buffer(s, data, num_bytes); -} - -static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s, - unsigned short data) -{ - return comedi_write_array_to_buffer(s, &data, sizeof(data)); -}; - -static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s, - unsigned int data) -{ - return comedi_write_array_to_buffer(s, &data, sizeof(data)); -}; - -static inline unsigned int -cfc_read_array_from_buffer(struct comedi_subdevice *s, void *data, - unsigned int num_bytes) -{ - return comedi_read_array_from_buffer(s, data, num_bytes); -} - -static inline unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - return comedi_handle_events(dev, s); -} - /** * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source * @src: pointer to the trigger source to validate diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index bf002988192d..3bac903c8627 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -225,10 +225,9 @@ static irqreturn_t parport_interrupt(int irq, void *d) if (!(ctrl & PARPORT_CTRL_IRQ_ENA)) return IRQ_NONE; - comedi_buf_put(s, 0); - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); - comedi_event(dev, s); return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index 00c03df72523..e56525a1c8f3 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -52,18 +52,23 @@ zero volts). #include "comedi_fc.h" #include <linux/timer.h> +#include <linux/ktime.h> #define N_CHANS 8 +enum waveform_state_bits { + WAVEFORM_AI_RUNNING = 0 +}; + /* Data unique to this driver */ struct waveform_private { struct timer_list timer; - struct timeval last; /* time last timer interrupt occurred */ + ktime_t last; /* time last timer interrupt occurred */ unsigned int uvolt_amplitude; /* waveform amplitude in microvolts */ unsigned long usec_period; /* waveform period in microseconds */ unsigned long usec_current; /* current time (mod waveform period) */ unsigned long usec_remainder; /* usec since last scan */ - unsigned long ai_count; /* number of conversions remaining */ + unsigned long state_bits; unsigned int scan_period; /* scan period in usec */ unsigned int convert_period; /* conversion period in usec */ unsigned int ao_loopbacks[N_CHANS]; @@ -164,36 +169,29 @@ static void waveform_ai_interrupt(unsigned long arg) { struct comedi_device *dev = (struct comedi_device *)arg; struct waveform_private *devpriv = dev->private; - struct comedi_async *async = dev->read_subdev->async; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int i, j; /* all times in microsec */ unsigned long elapsed_time; unsigned int num_scans; - struct timeval now; - bool stopping = false; + ktime_t now; + + /* check command is still active */ + if (!test_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits)) + return; - do_gettimeofday(&now); + now = ktime_get(); - elapsed_time = - 1000000 * (now.tv_sec - devpriv->last.tv_sec) + now.tv_usec - - devpriv->last.tv_usec; + elapsed_time = ktime_to_us(ktime_sub(now, devpriv->last)); devpriv->last = now; num_scans = (devpriv->usec_remainder + elapsed_time) / devpriv->scan_period; devpriv->usec_remainder = (devpriv->usec_remainder + elapsed_time) % devpriv->scan_period; - if (cmd->stop_src == TRIG_COUNT) { - unsigned int remaining = cmd->stop_arg - devpriv->ai_count; - - if (num_scans >= remaining) { - /* about to finish */ - num_scans = remaining; - stopping = true; - } - } - + num_scans = comedi_nscans_left(s, num_scans); for (i = 0; i < num_scans; i++) { for (j = 0; j < cmd->chanlist_len; j++) { unsigned short sample; @@ -203,20 +201,19 @@ static void waveform_ai_interrupt(unsigned long arg) devpriv->usec_current + i * devpriv->scan_period + j * devpriv->convert_period); - cfc_write_to_buffer(dev->read_subdev, sample); + comedi_buf_write_samples(s, &sample, 1); } } - devpriv->ai_count += i; devpriv->usec_current += elapsed_time; devpriv->usec_current %= devpriv->usec_period; - if (stopping) + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) async->events |= COMEDI_CB_EOA; else mod_timer(&devpriv->timer, jiffies + 1); - comedi_event(dev, dev->read_subdev); + comedi_handle_events(dev, s); } static int waveform_ai_cmdtest(struct comedi_device *dev, @@ -308,7 +305,6 @@ static int waveform_ai_cmd(struct comedi_device *dev, return -1; } - devpriv->ai_count = 0; devpriv->scan_period = cmd->scan_begin_arg / nano_per_micro; if (cmd->convert_src == TRIG_NOW) @@ -316,11 +312,16 @@ static int waveform_ai_cmd(struct comedi_device *dev, else /* TRIG_TIMER */ devpriv->convert_period = cmd->convert_arg / nano_per_micro; - do_gettimeofday(&devpriv->last); - devpriv->usec_current = devpriv->last.tv_usec % devpriv->usec_period; + devpriv->last = ktime_get(); + devpriv->usec_current = + ((u32)ktime_to_us(devpriv->last)) % devpriv->usec_period; devpriv->usec_remainder = 0; devpriv->timer.expires = jiffies + 1; + /* mark command as active */ + smp_mb__before_atomic(); + set_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits); + smp_mb__after_atomic(); add_timer(&devpriv->timer); return 0; } @@ -330,7 +331,11 @@ static int waveform_ai_cancel(struct comedi_device *dev, { struct waveform_private *devpriv = dev->private; - del_timer_sync(&devpriv->timer); + /* mark command as no longer active */ + clear_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits); + smp_mb__after_atomic(); + /* cannot call del_timer_sync() as may be called from timer routine */ + del_timer(&devpriv->timer); return 0; } @@ -405,7 +410,7 @@ static int waveform_attach(struct comedi_device *dev, dev->write_subdev = s; /* analog output subdevice (loopback) */ s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; s->n_chan = N_CHANS; s->maxdata = 0xffff; s->range_table = &waveform_ai_ranges; @@ -432,7 +437,7 @@ static void waveform_detach(struct comedi_device *dev) struct waveform_private *devpriv = dev->private; if (devpriv) - waveform_ai_cancel(dev, dev->read_subdev); + del_timer_sync(&devpriv->timer); } static struct comedi_driver waveform_driver = { diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c index 34cbe83f0ce7..beb36c8dd00a 100644 --- a/drivers/staging/comedi/drivers/dac02.c +++ b/drivers/staging/comedi/drivers/dac02.c @@ -129,7 +129,6 @@ static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = &das02_ao_ranges; s->insn_write = dac02_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index e5b5a8133b34..96697fbb5239 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -707,7 +707,6 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, s->n_chan = 2; s->maxdata = 0xffff; s->insn_write = daqboard2000_ao_insn_write; - s->insn_read = comedi_readback_insn_read; s->range_table = &range_bipolar10; result = comedi_alloc_subdev_readback(s); diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index bdb671a66e22..20a9f0eb72b5 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -474,7 +474,6 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->maxdata = (1 << thisboard->ao_nbits) - 1; s->range_table = &range_bipolar5; s->insn_write = das08_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -507,7 +506,7 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) /* do */ if (thisboard->do_nchan) { s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = thisboard->do_nchan; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 2d8e86cec47a..2436057304a3 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -541,6 +541,7 @@ static void das16_interrupt(struct comedi_device *dev) struct comedi_cmd *cmd = &async->cmd; unsigned long spin_flags; unsigned long dma_flags; + unsigned int nsamples; int num_bytes, residue; int buffer_index; @@ -583,21 +584,25 @@ static void das16_interrupt(struct comedi_device *dev) spin_unlock_irqrestore(&dev->spinlock, spin_flags); - cfc_write_array_to_buffer(s, - devpriv->dma_buffer[buffer_index], num_bytes); + nsamples = comedi_bytes_to_samples(s, num_bytes); + comedi_buf_write_samples(s, devpriv->dma_buffer[buffer_index], + nsamples); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static void das16_timer_interrupt(unsigned long arg) { struct comedi_device *dev = (struct comedi_device *)arg; struct das16_private_struct *devpriv = dev->private; + unsigned long flags; das16_interrupt(dev); + spin_lock_irqsave(&dev->spinlock, flags); if (devpriv->timer_running) mod_timer(&devpriv->timer, jiffies + timer_period()); + spin_unlock_irqrestore(&dev->spinlock, flags); } static int das16_ai_check_chanlist(struct comedi_device *dev, @@ -764,7 +769,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) return -1; } - devpriv->adc_byte_count = cmd->stop_arg * cfc_bytes_per_scan(s); + devpriv->adc_byte_count = cmd->stop_arg * comedi_bytes_per_scan(s); if (devpriv->can_burst) outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG); @@ -814,7 +819,8 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) enable_dma(devpriv->dma_chan); release_dma_lock(flags); - /* set up interrupt */ + /* set up timer */ + spin_lock_irqsave(&dev->spinlock, flags); devpriv->timer_running = 1; devpriv->timer.expires = jiffies + timer_period(); add_timer(&devpriv->timer); @@ -823,6 +829,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) if (devpriv->can_burst) outb(0, dev->iobase + DAS1600_CONV_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } @@ -856,8 +863,9 @@ static void das16_ai_munge(struct comedi_device *dev, unsigned int num_bytes, unsigned int start_chan_index) { - unsigned int i, num_samples = num_bytes / sizeof(short); unsigned short *data = array; + unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes); + unsigned int i; for (i = 0; i < num_samples; i++) { data[i] = le16_to_cpu(data[i]); @@ -1167,7 +1175,6 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = devpriv->user_ao_range_table; s->insn_write = das16_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -1226,6 +1233,8 @@ static void das16_detach(struct comedi_device *dev) int i; if (devpriv) { + if (devpriv->timer.data) + del_timer_sync(&devpriv->timer); if (dev->iobase) das16_reset(dev); diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 24b63c452f51..80f41b7e8273 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -442,8 +442,7 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) num_samples = FIFO_SIZE; insw(dev->iobase, devpriv->ai_buffer, num_samples); munge_sample_array(devpriv->ai_buffer, num_samples); - cfc_write_array_to_buffer(s, devpriv->ai_buffer, - num_samples * sizeof(short)); + comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples); devpriv->adc_count += num_samples; if (cmd->stop_src == TRIG_COUNT) { @@ -460,7 +459,7 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) dev_err(dev->class_dev, "fifo overflow\n"); } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) @@ -598,7 +597,7 @@ static int das16m1_attach(struct comedi_device *dev, s = &dev->subdevices[2]; /* do */ s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index a53d87ce9b14..be825d21a185 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -421,7 +421,6 @@ static const struct das1800_board das1800_boards[] = { }; struct das1800_private { - unsigned int count; /* number of data points left to be taken */ unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ int irq_dma_bits; /* bits for control register b */ @@ -479,42 +478,33 @@ static void das1800_handle_fifo_half_full(struct comedi_device *dev, struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; - int numPoints = 0; /* number of points to read */ - struct comedi_cmd *cmd = &s->async->cmd; + unsigned int nsamples = comedi_nsamples_left(s, FIFO_SIZE / 2); - numPoints = FIFO_SIZE / 2; - /* if we only need some of the points */ - if (cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints) - numPoints = devpriv->count; - insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints); - munge_data(dev, devpriv->ai_buf0, numPoints); - cfc_write_array_to_buffer(s, devpriv->ai_buf0, - numPoints * sizeof(devpriv->ai_buf0[0])); - if (cmd->stop_src == TRIG_COUNT) - devpriv->count -= numPoints; + insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, nsamples); + munge_data(dev, devpriv->ai_buf0, nsamples); + comedi_buf_write_samples(s, devpriv->ai_buf0, nsamples); } static void das1800_handle_fifo_not_empty(struct comedi_device *dev, struct comedi_subdevice *s) { - struct das1800_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned short dpnt; int unipolar; - struct comedi_cmd *cmd = &s->async->cmd; unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB; while (inb(dev->iobase + DAS1800_STATUS) & FNE) { - if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) - break; dpnt = inw(dev->iobase + DAS1800_FIFO); /* convert to unsigned type if we are in a bipolar mode */ if (!unipolar) ; dpnt = munge_bipolar_sample(dev, dpnt); - cfc_write_to_buffer(s, dpnt); - if (cmd->stop_src == TRIG_COUNT) - devpriv->count--; + comedi_buf_write_samples(s, &dpnt, 1); + + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) + break; } } @@ -525,8 +515,8 @@ static void das1800_flush_dma_channel(struct comedi_device *dev, unsigned int channel, uint16_t *buffer) { struct das1800_private *devpriv = dev->private; - unsigned int num_bytes, num_samples; - struct comedi_cmd *cmd = &s->async->cmd; + unsigned int nbytes; + unsigned int nsamples; disable_dma(channel); @@ -535,17 +525,12 @@ static void das1800_flush_dma_channel(struct comedi_device *dev, clear_dma_ff(channel); /* figure out how many points to read */ - num_bytes = devpriv->dma_transfer_size - get_dma_residue(channel); - num_samples = num_bytes / sizeof(short); - - /* if we only need some of the points */ - if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples) - num_samples = devpriv->count; + nbytes = devpriv->dma_transfer_size - get_dma_residue(channel); + nsamples = comedi_bytes_to_samples(s, nbytes); + nsamples = comedi_nsamples_left(s, nsamples); - munge_data(dev, buffer, num_samples); - cfc_write_array_to_buffer(s, buffer, num_bytes); - if (cmd->stop_src == TRIG_COUNT) - devpriv->count -= num_samples; + munge_data(dev, buffer, nsamples); + comedi_buf_write_samples(s, buffer, nsamples); } /* flushes remaining data from board when external trigger has stopped acquisition @@ -649,14 +634,13 @@ static void das1800_ai_handler(struct comedi_device *dev) das1800_handle_fifo_not_empty(dev, s); } - async->events |= COMEDI_CB_BLOCK; /* if the card's fifo has overflowed */ if (status & OVF) { /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); dev_err(dev->class_dev, "FIFO overflow\n"); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } /* stop taking data if appropriate */ @@ -670,11 +654,12 @@ static void das1800_ai_handler(struct comedi_device *dev) else das1800_handle_fifo_not_empty(dev, s); async->events |= COMEDI_CB_EOA; - } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */ + } else if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { async->events |= COMEDI_CB_EOA; } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static int das1800_ai_poll(struct comedi_device *dev, @@ -1102,9 +1087,6 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, /* interrupt fifo half full */ devpriv->irq_dma_bits |= FIMD; } - /* determine how many conversions we need */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->count = cmd->stop_arg * cmd->chanlist_len; das1800_cancel(dev, s); @@ -1515,7 +1497,7 @@ static int das1800_attach(struct comedi_device *dev, /* do */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = thisboard->do_n_chan; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index ab6e40608885..780f4f646ea0 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -35,6 +35,7 @@ #include <linux/interrupt.h> #include "../comedidev.h" +#include "comedi_fc.h" #include "8253.h" /* @@ -192,26 +193,197 @@ static void das6402_enable_counter(struct comedi_device *dev, bool load) } } +static unsigned int das6402_ai_read_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inw(dev->iobase + DAS6402_AI_DATA_REG); + if (s->maxdata == 0x0fff) + val >>= 4; + return val; +} + static irqreturn_t das6402_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int status; + + status = inb(dev->iobase + DAS6402_STATUS_REG); + if ((status & DAS6402_STATUS_INT) == 0) + return IRQ_NONE; + + if (status & DAS6402_STATUS_FFULL) { + async->events |= COMEDI_CB_OVERFLOW; + } else if (status & DAS6402_STATUS_FFNE) { + unsigned int val; + + val = das6402_ai_read_sample(dev, s); + comedi_buf_write_samples(s, &val, 1); + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; + } das6402_clear_all_interrupts(dev); + comedi_handle_events(dev, s); + return IRQ_HANDLED; } +static void das6402_ai_set_mode(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chanspec, + unsigned int mode) +{ + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + + mode |= DAS6402_MODE_RANGE(range); + if (aref == AREF_GROUND) + mode |= DAS6402_MODE_SE; + if (comedi_range_is_unipolar(s, range)) + mode |= DAS6402_MODE_UNI; + + das6402_set_mode(dev, mode); +} + static int das6402_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - return -EINVAL; + struct das6402_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int chan_lo = CR_CHAN(cmd->chanlist[0]); + unsigned int chan_hi = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); + + das6402_ai_set_mode(dev, s, cmd->chanlist[0], DAS6402_MODE_FIFONEPTY); + + /* load the mux for chanlist conversion */ + outw(DAS6402_AI_MUX_HI(chan_hi) | DAS6402_AI_MUX_LO(chan_lo), + dev->iobase + DAS6402_AI_MUX_REG); + + das6402_enable_counter(dev, true); + + /* enable interrupt and pacer trigger */ + outb(DAS6402_CTRL_INTE | + DAS6402_CTRL_IRQ(devpriv->irq) | + DAS6402_CTRL_PACER_TRIG, dev->iobase + DAS6402_CTRL_REG); + + return 0; +} + +static int das6402_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]); + 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 != chan0 + i) { + dev_dbg(dev->class_dev, + "chanlist must be consecutive\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "chanlist must have the same range\n"); + return -EINVAL; + } + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "chanlist must have the same reference\n"); + return -EINVAL; + } + + if (aref0 == AREF_DIFF && chan > (s->n_chan / 2)) { + dev_dbg(dev->class_dev, + "chanlist differential channel to large\n"); + return -EINVAL; + } + } + return 0; } static int das6402_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - return -EINVAL; + struct das6402_private *devpriv = dev->private; + int err = 0; + unsigned int arg; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + 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 (cmd->convert_src == TRIG_TIMER) { + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divider1, + &devpriv->divider2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + } + + if (err) + return 4; + + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das6402_ai_check_chanlist(dev, s, cmd); + + if (err) + return 5; + + return 0; } static int das6402_ai_cancel(struct comedi_device *dev, @@ -246,26 +418,17 @@ static int das6402_ai_insn_read(struct comedi_device *dev, 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; + if (aref == AREF_DIFF && chan > (s->n_chan / 2)) + return -EINVAL; /* enable software conversion trigger */ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); - das6402_set_mode(dev, val); + das6402_ai_set_mode(dev, s, insn->chanspec, DAS6402_MODE_POLLED); /* load the mux for single channel conversion */ outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan), @@ -279,12 +442,7 @@ static int das6402_ai_insn_read(struct comedi_device *dev, if (ret) break; - val = inw(dev->iobase + DAS6402_AI_DATA_REG); - - if (s->maxdata == 0x0fff) - val >>= 4; - - data[i] = val; + data[i] = das6402_ai_read_sample(dev, s); } das6402_ai_clear_eoc(dev); @@ -497,7 +655,7 @@ static int das6402_attach(struct comedi_device *dev, /* Analog Output subdevice */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = board->maxdata; s->range_table = &das6402_ao_ranges; @@ -520,7 +678,7 @@ static int das6402_attach(struct comedi_device *dev, /* Digital Input subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 8; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index d75e5528258c..e5bdc2423445 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -219,7 +219,6 @@ static const struct das800_board das800_boards[] = { }; struct das800_private { - unsigned int count; /* number of data points left to be taken */ 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 */ @@ -286,9 +285,6 @@ static void das800_set_frequency(struct comedi_device *dev) static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct das800_private *devpriv = dev->private; - - devpriv->count = 0; das800_disable(dev); return 0; } @@ -399,7 +395,6 @@ static int das800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { const struct das800_board *thisboard = dev->board_ptr; - struct das800_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int gain = CR_RANGE(cmd->chanlist[0]); @@ -422,11 +417,6 @@ static int das800_ai_do_cmd(struct comedi_device *dev, gain &= 0xf; outb(gain, dev->iobase + DAS800_GAIN); - if (cmd->stop_src == TRIG_COUNT) - devpriv->count = cmd->stop_arg * cmd->chanlist_len; - else /* TRIG_NONE */ - devpriv->count = 0; - /* enable auto channel scan, send interrupts on end of conversion * and set clock source to internal or external */ @@ -509,25 +499,28 @@ static irqreturn_t das800_interrupt(int irq, void *d) if (s->maxdata == 0x0fff) val >>= 4; /* 12-bit sample */ - /* if there are more data points to collect */ - if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) { - /* write data point to buffer */ - cfc_write_to_buffer(s, val & s->maxdata); - devpriv->count--; + val &= s->maxdata; + comedi_buf_write_samples(s, &val, 1); + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { + async->events |= COMEDI_CB_EOA; + break; } } - async->events |= COMEDI_CB_BLOCK; if (fifo_overflow) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } - if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) { - /* Re-enable card's interrupt. - * We already have spinlock, so indirect addressing is safe */ + if (!(async->events & COMEDI_CB_CANCEL_MASK)) { + /* + * Re-enable card's interrupt. + * We already have spinlock, so indirect addressing is safe + */ das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1); spin_unlock_irqrestore(&dev->spinlock, irq_flags); @@ -535,9 +528,8 @@ static irqreturn_t das800_interrupt(int irq, void *d) /* otherwise, stop taking data */ spin_unlock_irqrestore(&dev->spinlock, irq_flags); das800_disable(dev); - async->events |= COMEDI_CB_EOA; } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -738,7 +730,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* Digital Output subdevice */ s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 7215e09305cf..6df298a99cc6 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -1,125 +1,139 @@ /* - comedi/drivers/dmm32at.c - Diamond Systems mm32at code for a Comedi driver - - 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. -*/ + * dmm32at.c + * Diamond Systems Diamond-MM-32-AT Comedi driver + * + * 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: dmm32at -Description: Diamond Systems mm32at driver. -Devices: -Author: Perry J. Piplani <perry.j.piplani@nasa.gov> -Updated: Fri Jun 4 09:13:24 CDT 2004 -Status: experimental - -This driver is for the Diamond Systems MM-32-AT board -http://www.diamondsystems.com/products/diamondmm32at It is being used -on serveral projects inside NASA, without problems so far. For analog -input commands, TRIG_EXT is not yet supported at all.. - -Configuration Options: - comedi_config /dev/comedi0 dmm32at baseaddr,irq -*/ + * Driver: dmm32at + * Description: Diamond Systems Diamond-MM-32-AT + * Devices: (Diamond Systems) Diamond-MM-32-AT [dmm32at] + * Author: Perry J. Piplani <perry.j.piplani@nasa.gov> + * Updated: Fri Jun 4 09:13:24 CDT 2004 + * Status: experimental + * + * Configuration Options: + * comedi_config /dev/comedi0 dmm32at baseaddr,irq + * + * This driver is for the Diamond Systems MM-32-AT board + * http://www.diamondsystems.com/products/diamondmm32at + * + * It is being used on serveral projects inside NASA, without + * problems so far. For analog input commands, TRIG_EXT is not + * yet supported. + */ #include <linux/module.h> #include <linux/delay.h> #include <linux/interrupt.h> #include "../comedidev.h" +#include "8255.h" #include "comedi_fc.h" /* Board register addresses */ -#define DMM32AT_CONV 0x00 -#define DMM32AT_AILSB 0x00 -#define DMM32AT_AUXDOUT 0x01 -#define DMM32AT_AIMSB 0x01 -#define DMM32AT_AILOW 0x02 -#define DMM32AT_AIHIGH 0x03 - -#define DMM32AT_DACSTAT 0x04 -#define DMM32AT_DACLSB_REG 0x04 -#define DMM32AT_DACMSB_REG 0x05 -#define DMM32AT_DACMSB_CHAN(x) ((x) << 6) - -#define DMM32AT_FIFOCNTRL 0x07 -#define DMM32AT_FIFOSTAT 0x07 - -#define DMM32AT_CNTRL 0x08 -#define DMM32AT_AISTAT 0x08 - -#define DMM32AT_INTCLOCK 0x09 - -#define DMM32AT_CNTRDIO 0x0a - -#define DMM32AT_AICONF 0x0b -#define DMM32AT_AIRBACK 0x0b +#define DMM32AT_AI_START_CONV_REG 0x00 +#define DMM32AT_AI_LSB_REG 0x00 +#define DMM32AT_AUX_DOUT_REG 0x01 +#define DMM32AT_AUX_DOUT2 (1 << 2) /* J3.42 - OUT2 (OUT2EN) */ +#define DMM32AT_AUX_DOUT1 (1 << 1) /* J3.43 */ +#define DMM32AT_AUX_DOUT0 (1 << 0) /* J3.44 - OUT0 (OUT0EN) */ +#define DMM32AT_AI_MSB_REG 0x01 +#define DMM32AT_AI_LO_CHAN_REG 0x02 +#define DMM32AT_AI_HI_CHAN_REG 0x03 +#define DMM32AT_AUX_DI_REG 0x04 +#define DMM32AT_AUX_DI_DACBUSY (1 << 7) +#define DMM32AT_AUX_DI_CALBUSY (1 << 6) +#define DMM32AT_AUX_DI3 (1 << 3) /* J3.45 - ADCLK (CLKSEL) */ +#define DMM32AT_AUX_DI2 (1 << 2) /* J3.46 - GATE12 (GT12EN) */ +#define DMM32AT_AUX_DI1 (1 << 1) /* J3.47 - GATE0 (GT0EN) */ +#define DMM32AT_AUX_DI0 (1 << 0) /* J3.48 - CLK0 (SRC0) */ +#define DMM32AT_AO_LSB_REG 0x04 +#define DMM32AT_AO_MSB_REG 0x05 +#define DMM32AT_AO_MSB_DACH(x) ((x) << 6) +#define DMM32AT_FIFO_DEPTH_REG 0x06 +#define DMM32AT_FIFO_CTRL_REG 0x07 +#define DMM32AT_FIFO_CTRL_FIFOEN (1 << 3) +#define DMM32AT_FIFO_CTRL_SCANEN (1 << 2) +#define DMM32AT_FIFO_CTRL_FIFORST (1 << 1) +#define DMM32AT_FIFO_STATUS_REG 0x07 +#define DMM32AT_FIFO_STATUS_EF (1 << 7) +#define DMM32AT_FIFO_STATUS_HF (1 << 6) +#define DMM32AT_FIFO_STATUS_FF (1 << 5) +#define DMM32AT_FIFO_STATUS_OVF (1 << 4) +#define DMM32AT_FIFO_STATUS_FIFOEN (1 << 3) +#define DMM32AT_FIFO_STATUS_SCANEN (1 << 2) +#define DMM32AT_FIFO_STATUS_PAGE_MASK (3 << 0) +#define DMM32AT_CTRL_REG 0x08 +#define DMM32AT_CTRL_RESETA (1 << 5) +#define DMM32AT_CTRL_RESETD (1 << 4) +#define DMM32AT_CTRL_INTRST (1 << 3) +#define DMM32AT_CTRL_PAGE_8254 (0 << 0) +#define DMM32AT_CTRL_PAGE_8255 (1 << 0) +#define DMM32AT_CTRL_PAGE_CALIB (3 << 0) +#define DMM32AT_AI_STATUS_REG 0x08 +#define DMM32AT_AI_STATUS_STS (1 << 7) +#define DMM32AT_AI_STATUS_SD1 (1 << 6) +#define DMM32AT_AI_STATUS_SD0 (1 << 5) +#define DMM32AT_AI_STATUS_ADCH_MASK (0x1f << 0) +#define DMM32AT_INTCLK_REG 0x09 +#define DMM32AT_INTCLK_ADINT (1 << 7) +#define DMM32AT_INTCLK_DINT (1 << 6) +#define DMM32AT_INTCLK_TINT (1 << 5) +#define DMM32AT_INTCLK_CLKEN (1 << 1) /* 1=see below 0=software */ +#define DMM32AT_INTCLK_CLKSEL (1 << 0) /* 1=OUT2 0=EXTCLK */ +#define DMM32AT_CTRDIO_CFG_REG 0x0a +#define DMM32AT_CTRDIO_CFG_FREQ12 (1 << 7) /* CLK12 1=100KHz 0=10MHz */ +#define DMM32AT_CTRDIO_CFG_FREQ0 (1 << 6) /* CLK0 1=10KHz 0=10MHz */ +#define DMM32AT_CTRDIO_CFG_OUT2EN (1 << 5) /* J3.42 1=OUT2 is DOUT2 */ +#define DMM32AT_CTRDIO_CFG_OUT0EN (1 << 4) /* J3,44 1=OUT0 is DOUT0 */ +#define DMM32AT_CTRDIO_CFG_GT0EN (1 << 2) /* J3.47 1=DIN1 is GATE0 */ +#define DMM32AT_CTRDIO_CFG_SRC0 (1 << 1) /* CLK0 is 0=FREQ0 1=J3.48 */ +#define DMM32AT_CTRDIO_CFG_GT12EN (1 << 0) /* J3.46 1=DIN2 is GATE12 */ +#define DMM32AT_AI_CFG_REG 0x0b +#define DMM32AT_AI_CFG_SCINT_20US (0 << 4) +#define DMM32AT_AI_CFG_SCINT_15US (1 << 4) +#define DMM32AT_AI_CFG_SCINT_10US (2 << 4) +#define DMM32AT_AI_CFG_SCINT_5US (3 << 4) +#define DMM32AT_AI_CFG_RANGE (1 << 3) /* 0=5V 1=10V */ +#define DMM32AT_AI_CFG_ADBU (1 << 2) /* 0=bipolar 1=unipolar */ +#define DMM32AT_AI_CFG_GAIN(x) ((x) << 0) +#define DMM32AT_AI_READBACK_REG 0x0b +#define DMM32AT_AI_READBACK_WAIT (1 << 7) /* DMM32AT_AI_STATUS_STS */ +#define DMM32AT_AI_READBACK_RANGE (1 << 3) +#define DMM32AT_AI_READBACK_ADBU (1 << 2) +#define DMM32AT_AI_READBACK_GAIN_MASK (3 << 0) #define DMM32AT_CLK1 0x0d #define DMM32AT_CLK2 0x0e #define DMM32AT_CLKCT 0x0f -#define DMM32AT_DIOA 0x0c -#define DMM32AT_DIOB 0x0d -#define DMM32AT_DIOC 0x0e -#define DMM32AT_DIOCONF 0x0f +#define DMM32AT_8255_IOBASE 0x0c /* Page 1 registers */ /* Board register values. */ -/* DMM32AT_DACSTAT 0x04 */ -#define DMM32AT_DACBUSY 0x80 - -/* DMM32AT_FIFOCNTRL 0x07 */ -#define DMM32AT_FIFORESET 0x02 -#define DMM32AT_SCANENABLE 0x04 - -/* DMM32AT_CNTRL 0x08 */ -#define DMM32AT_RESET 0x20 -#define DMM32AT_INTRESET 0x08 -#define DMM32AT_CLKACC 0x00 -#define DMM32AT_DIOACC 0x01 - -/* DMM32AT_AISTAT 0x08 */ -#define DMM32AT_STATUS 0x80 - -/* DMM32AT_INTCLOCK 0x09 */ -#define DMM32AT_ADINT 0x80 -#define DMM32AT_CLKSEL 0x03 - -/* DMM32AT_CNTRDIO 0x0a */ -#define DMM32AT_FREQ12 0x80 - -/* DMM32AT_AICONF 0x0b */ +/* DMM32AT_AI_CFG_REG 0x0b */ #define DMM32AT_RANGE_U10 0x0c #define DMM32AT_RANGE_U5 0x0d #define DMM32AT_RANGE_B10 0x08 #define DMM32AT_RANGE_B5 0x00 -#define DMM32AT_SCINT_20 0x00 -#define DMM32AT_SCINT_15 0x10 -#define DMM32AT_SCINT_10 0x20 -#define DMM32AT_SCINT_5 0x30 /* DMM32AT_CLKCT 0x0f */ #define DMM32AT_CLKCT1 0x56 /* mode3 counter 1 - write low byte only */ #define DMM32AT_CLKCT2 0xb6 /* mode3 counter 2 - write high and low byte */ -/* DMM32AT_DIOCONF 0x0f */ -#define DMM32AT_DIENABLE 0x80 -#define DMM32AT_DIRA 0x10 -#define DMM32AT_DIRB 0x02 -#define DMM32AT_DIRCL 0x01 -#define DMM32AT_DIRCH 0x08 - /* board AI ranges in comedi structure */ static const struct comedi_lrange dmm32at_airanges = { 4, { @@ -150,12 +164,36 @@ static const struct comedi_lrange dmm32at_aoranges = { } }; -struct dmm32at_private { - int data; - int ai_inuse; - unsigned int ai_scans_left; - unsigned char dio_config; -}; +static void dmm32at_ai_set_chanspec(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chanspec, int nchan) +{ + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int last_chan = (chan + nchan - 1) % s->n_chan; + + outb(DMM32AT_FIFO_CTRL_FIFORST, dev->iobase + DMM32AT_FIFO_CTRL_REG); + + if (nchan > 1) + outb(DMM32AT_FIFO_CTRL_SCANEN, + dev->iobase + DMM32AT_FIFO_CTRL_REG); + + outb(chan, dev->iobase + DMM32AT_AI_LO_CHAN_REG); + outb(last_chan, dev->iobase + DMM32AT_AI_HI_CHAN_REG); + outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AI_CFG_REG); +} + +static unsigned int dmm32at_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + DMM32AT_AI_LSB_REG); + val |= (inb(dev->iobase + DMM32AT_AI_MSB_REG) << 8); + + /* munge two's complement value to offset binary */ + return comedi_offset_munge(s, val); +} static int dmm32at_ai_status(struct comedi_device *dev, struct comedi_subdevice *s, @@ -165,75 +203,39 @@ static int dmm32at_ai_status(struct comedi_device *dev, unsigned char status; status = inb(dev->iobase + context); - if ((status & DMM32AT_STATUS) == 0) + if ((status & DMM32AT_AI_STATUS_STS) == 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) +static int dmm32at_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - unsigned int d; - unsigned short msb, lsb; - unsigned char chan; - int range; int ret; + int i; - /* get the channel and range number */ - - chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1); - range = CR_RANGE(insn->chanspec); - - /* zero scan and fifo control and reset fifo */ - outb(DMM32AT_FIFORESET, dev->iobase + DMM32AT_FIFOCNTRL); - - /* write the ai channel range regs */ - outb(chan, dev->iobase + DMM32AT_AILOW); - outb(chan, dev->iobase + DMM32AT_AIHIGH); - /* set the range bits */ - outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); + dmm32at_ai_set_chanspec(dev, s, insn->chanspec, 1); /* wait for circuit to settle */ - ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK); + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, + DMM32AT_AI_READBACK_REG); if (ret) return ret; - /* convert n samples */ - for (n = 0; n < insn->n; n++) { - /* trigger conversion */ - outb(0xff, dev->iobase + DMM32AT_CONV); + for (i = 0; i < insn->n; i++) { + outb(0xff, dev->iobase + DMM32AT_AI_START_CONV_REG); - /* wait for conversion to end */ ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, - DMM32AT_AISTAT); + DMM32AT_AI_STATUS_REG); if (ret) return ret; - /* read data */ - lsb = inb(dev->iobase + DMM32AT_AILSB); - msb = inb(dev->iobase + DMM32AT_AIMSB); - - /* invert sign bit to make range unsigned, this is an - idiosyncrasy of the diamond board, it return - conversions as a signed value, i.e. -32768 to - 32767, flipping the bit and interpreting it as - signed gives you a range of 0 to 65535 which is - used by comedi */ - d = ((msb ^ 0x0080) << 8) + lsb; - - data[n] = d; + data[i] = dmm32at_ai_get_sample(dev, s); } - /* return the number of samples read/written */ - return n; -} - -static int dmm32at_ns_to_timer(unsigned int *ns, unsigned int flags) -{ - /* trivial timer */ - return *ns; + return insn->n; } static int dmm32at_ai_check_chanlist(struct comedi_device *dev, @@ -273,10 +275,8 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, /* Step 1 : check if triggers are trivially valid */ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER /*| TRIG_EXT */); - err |= cfc_check_trigger_src(&cmd->convert_src, - TRIG_TIMER /*| TRIG_EXT */); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -285,8 +285,6 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, /* 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 */ @@ -298,67 +296,32 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); -#define MAX_SCAN_SPEED 1000000 /* in nanoseconds */ -#define MIN_SCAN_SPEED 1000000000 /* in nanoseconds */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SCAN_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SCAN_SPEED); - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 1000000); + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 1000000000); - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg >= 17500) - cmd->convert_arg = 20000; - else if (cmd->convert_arg >= 12500) - cmd->convert_arg = 15000; - else if (cmd->convert_arg >= 7500) - cmd->convert_arg = 10000; - else - cmd->convert_arg = 5000; - } else { - /* external trigger */ - /* see above */ - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); - } + if (cmd->convert_arg >= 17500) + cmd->convert_arg = 20000; + else if (cmd->convert_arg >= 12500) + cmd->convert_arg = 15000; + else if (cmd->convert_arg >= 7500) + cmd->convert_arg = 10000; + else + cmd->convert_arg = 5000; 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, 0xfffffff0); + if (cmd->stop_src == TRIG_COUNT) err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); - } else { - /* TRIG_NONE */ + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; - /* step 4: fix up any arguments */ + /* Step 4: fix up any arguments */ - if (cmd->scan_begin_src == TRIG_TIMER) { - arg = cmd->scan_begin_arg; - dmm32at_ns_to_timer(&arg, cmd->flags); - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); - } - if (cmd->convert_src == TRIG_TIMER) { - arg = cmd->convert_arg; - dmm32at_ns_to_timer(&arg, cmd->flags); - 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); - } - } + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, arg); if (err) return 4; @@ -384,11 +347,11 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec) hi2 = (both2 & 0xff00) >> 8; lo2 = both2 & 0x00ff; - /* set the counter frequency to 10mhz */ - outb(0, dev->iobase + DMM32AT_CNTRDIO); + /* set counter clocks to 10MHz, disable all aux dio */ + outb(0, dev->iobase + DMM32AT_CTRDIO_CFG_REG); /* get access to the clock regs */ - outb(DMM32AT_CLKACC, dev->iobase + DMM32AT_CNTRL); + outb(DMM32AT_CTRL_PAGE_8254, dev->iobase + DMM32AT_CTRL_REG); /* write the counter 1 control word and low byte to counter */ outb(DMM32AT_CLKCT1, dev->iobase + DMM32AT_CLKCT); @@ -400,65 +363,37 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec) outb(hi2, dev->iobase + DMM32AT_CLK2); /* enable the ai conversion interrupt and the clock to start scans */ - outb(DMM32AT_ADINT | DMM32AT_CLKSEL, dev->iobase + DMM32AT_INTCLOCK); + outb(DMM32AT_INTCLK_ADINT | + DMM32AT_INTCLK_CLKEN | DMM32AT_INTCLK_CLKSEL, + dev->iobase + DMM32AT_INTCLK_REG); } 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 range; - unsigned char chanlo, chanhi; int ret; - if (!cmd->chanlist) - return -EINVAL; - - /* get the channel list and range */ - chanlo = CR_CHAN(cmd->chanlist[0]) & (s->n_chan - 1); - chanhi = chanlo + cmd->chanlist_len - 1; - if (chanhi >= s->n_chan) - return -EINVAL; - range = CR_RANGE(cmd->chanlist[0]); - - /* reset fifo */ - outb(DMM32AT_FIFORESET, dev->iobase + DMM32AT_FIFOCNTRL); - - /* set scan enable */ - outb(DMM32AT_SCANENABLE, dev->iobase + DMM32AT_FIFOCNTRL); - - /* write the ai channel range regs */ - outb(chanlo, dev->iobase + DMM32AT_AILOW); - outb(chanhi, dev->iobase + DMM32AT_AIHIGH); - - /* set the range bits */ - outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); + dmm32at_ai_set_chanspec(dev, s, cmd->chanlist[0], cmd->chanlist_len); /* reset the interrupt just in case */ - outb(DMM32AT_INTRESET, dev->iobase + DMM32AT_CNTRL); - - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans_left = cmd->stop_arg; - else { /* TRIG_NONE */ - devpriv->ai_scans_left = 0xffffffff; /* indicates TRIG_NONE to - * isr */ - } + outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG); /* * 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); + ret = comedi_timeout(dev, s, NULL, dmm32at_ai_status, + DMM32AT_AI_READBACK_REG); if (ret) return ret; - if (devpriv->ai_scans_left > 1) { + if (cmd->stop_src == TRIG_NONE || cmd->stop_arg > 1) { /* start the clock and enable the interrupts */ dmm32at_setaitimer(dev, cmd->scan_begin_arg); } else { /* start the interrups and initiate a single scan */ - outb(DMM32AT_ADINT, dev->iobase + DMM32AT_INTCLOCK); - outb(0xff, dev->iobase + DMM32AT_CONV); + outb(DMM32AT_INTCLK_ADINT, dev->iobase + DMM32AT_INTCLK_REG); + outb(0xff, dev->iobase + DMM32AT_AI_START_CONV_REG); } return 0; @@ -468,19 +403,16 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int dmm32at_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct dmm32at_private *devpriv = dev->private; - - devpriv->ai_scans_left = 1; + /* disable further interrupts and clocks */ + outb(0x0, dev->iobase + DMM32AT_INTCLK_REG); return 0; } static irqreturn_t dmm32at_isr(int irq, void *d) { struct comedi_device *dev = d; - struct dmm32at_private *devpriv = dev->private; unsigned char intstat; - unsigned int samp; - unsigned short msb, lsb; + unsigned int val; int i; if (!dev->attached) { @@ -488,38 +420,26 @@ static irqreturn_t dmm32at_isr(int irq, void *d) return IRQ_HANDLED; } - intstat = inb(dev->iobase + DMM32AT_INTCLOCK); + intstat = inb(dev->iobase + DMM32AT_INTCLK_REG); - if (intstat & DMM32AT_ADINT) { + if (intstat & DMM32AT_INTCLK_ADINT) { struct comedi_subdevice *s = dev->read_subdev; struct comedi_cmd *cmd = &s->async->cmd; for (i = 0; i < cmd->chanlist_len; i++) { - /* read data */ - lsb = inb(dev->iobase + DMM32AT_AILSB); - msb = inb(dev->iobase + DMM32AT_AIMSB); - - /* invert sign bit to make range unsigned */ - samp = ((msb ^ 0x0080) << 8) + lsb; - comedi_buf_put(s, samp); + val = dmm32at_ai_get_sample(dev, s); + comedi_buf_write_samples(s, &val, 1); } - if (devpriv->ai_scans_left != 0xffffffff) { /* TRIG_COUNT */ - devpriv->ai_scans_left--; - if (devpriv->ai_scans_left == 0) { - /* disable further interrupts and clocks */ - outb(0x0, dev->iobase + DMM32AT_INTCLOCK); - /* set the buffer to be flushed with an EOF */ - s->async->events |= COMEDI_CB_EOA; - } + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) + s->async->events |= COMEDI_CB_EOA; - } - /* flush the buffer */ - comedi_event(dev, s); + comedi_handle_events(dev, s); } /* reset the interrupt */ - outb(DMM32AT_INTRESET, dev->iobase + DMM32AT_CNTRL); + outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG); return IRQ_HANDLED; } @@ -530,8 +450,8 @@ static int dmm32at_ao_eoc(struct comedi_device *dev, { unsigned char status; - status = inb(dev->iobase + DMM32AT_DACSTAT); - if ((status & DMM32AT_DACBUSY) == 0) + status = inb(dev->iobase + DMM32AT_AUX_DI_REG); + if ((status & DMM32AT_AUX_DI_DACBUSY) == 0) return 0; return -EBUSY; } @@ -549,9 +469,9 @@ static int dmm32at_ao_insn_write(struct comedi_device *dev, int ret; /* write LSB then MSB + chan to load DAC */ - outb(val & 0xff, dev->iobase + DMM32AT_DACLSB_REG); - outb((val >> 8) | DMM32AT_DACMSB_CHAN(chan), - dev->iobase + DMM32AT_DACMSB_REG); + outb(val & 0xff, dev->iobase + DMM32AT_AO_LSB_REG); + outb((val >> 8) | DMM32AT_AO_MSB_DACH(chan), + dev->iobase + DMM32AT_AO_MSB_REG); /* wait for circuit to settle */ ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0); @@ -559,7 +479,7 @@ static int dmm32at_ao_insn_write(struct comedi_device *dev, return ret; /* dummy read to update DAC */ - inb(dev->iobase + DMM32AT_DACMSB_REG); + inb(dev->iobase + DMM32AT_AO_MSB_REG); s->readback[chan] = val; } @@ -567,136 +487,82 @@ static int dmm32at_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int dmm32at_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct dmm32at_private *devpriv = dev->private; - unsigned int mask; - unsigned int val; - - mask = comedi_dio_update_state(s, data); - if (mask) { - /* get access to the DIO regs */ - outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); - - /* if either part of dio is set for output */ - if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || - ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { - val = (s->state & 0x00ff0000) >> 16; - outb(val, dev->iobase + DMM32AT_DIOC); - } - if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { - val = (s->state & 0x0000ff00) >> 8; - outb(val, dev->iobase + DMM32AT_DIOB); - } - if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { - val = (s->state & 0x000000ff); - outb(val, dev->iobase + DMM32AT_DIOA); - } - } - - val = inb(dev->iobase + DMM32AT_DIOA); - val |= inb(dev->iobase + DMM32AT_DIOB) << 8; - val |= inb(dev->iobase + DMM32AT_DIOC) << 16; - s->state = val; - - data[1] = val; - - return insn->n; -} - -static int dmm32at_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int dmm32at_8255_io(struct comedi_device *dev, + int dir, int port, int data, unsigned long regbase) { - struct dmm32at_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask; - unsigned char chanbit; - int ret; - - if (chan < 8) { - mask = 0x0000ff; - chanbit = DMM32AT_DIRA; - } else if (chan < 16) { - mask = 0x00ff00; - chanbit = DMM32AT_DIRB; - } else if (chan < 20) { - mask = 0x0f0000; - chanbit = DMM32AT_DIRCL; - } else { - mask = 0xf00000; - chanbit = DMM32AT_DIRCH; - } - - ret = comedi_dio_insn_config(dev, s, insn, data, mask); - if (ret) - return ret; - - if (data[0] == INSN_CONFIG_DIO_OUTPUT) - devpriv->dio_config &= ~chanbit; - else - devpriv->dio_config |= chanbit; /* get access to the DIO regs */ - outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); - /* set the DIO's to the new configuration setting */ - outb(devpriv->dio_config, dev->iobase + DMM32AT_DIOCONF); + outb(DMM32AT_CTRL_PAGE_8255, dev->iobase + DMM32AT_CTRL_REG); - return insn->n; + if (dir) { + outb(data, dev->iobase + regbase + port); + return 0; + } + return inb(dev->iobase + regbase + port); } -static int dmm32at_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +/* Make sure the board is there and put it to a known state */ +static int dmm32at_reset(struct comedi_device *dev) { - struct dmm32at_private *devpriv; - int ret; - struct comedi_subdevice *s; unsigned char aihi, ailo, fifostat, aistat, intstat, airback; - ret = comedi_request_region(dev, it->options[0], 0x10); - if (ret) - return ret; - - /* the following just makes sure the board is there and gets - it to a known state */ - /* reset the board */ - outb(DMM32AT_RESET, dev->iobase + DMM32AT_CNTRL); + outb(DMM32AT_CTRL_RESETA, dev->iobase + DMM32AT_CTRL_REG); /* allow a millisecond to reset */ udelay(1000); /* zero scan and fifo control */ - outb(0x0, dev->iobase + DMM32AT_FIFOCNTRL); + outb(0x0, dev->iobase + DMM32AT_FIFO_CTRL_REG); /* zero interrupt and clock control */ - outb(0x0, dev->iobase + DMM32AT_INTCLOCK); + outb(0x0, dev->iobase + DMM32AT_INTCLK_REG); /* write a test channel range, the high 3 bits should drop */ - outb(0x80, dev->iobase + DMM32AT_AILOW); - outb(0xff, dev->iobase + DMM32AT_AIHIGH); + outb(0x80, dev->iobase + DMM32AT_AI_LO_CHAN_REG); + outb(0xff, dev->iobase + DMM32AT_AI_HI_CHAN_REG); /* set the range at 10v unipolar */ - outb(DMM32AT_RANGE_U10, dev->iobase + DMM32AT_AICONF); + outb(DMM32AT_RANGE_U10, dev->iobase + DMM32AT_AI_CFG_REG); /* should take 10 us to settle, here's a hundred */ udelay(100); /* read back the values */ - ailo = inb(dev->iobase + DMM32AT_AILOW); - aihi = inb(dev->iobase + DMM32AT_AIHIGH); - fifostat = inb(dev->iobase + DMM32AT_FIFOSTAT); - aistat = inb(dev->iobase + DMM32AT_AISTAT); - intstat = inb(dev->iobase + DMM32AT_INTCLOCK); - airback = inb(dev->iobase + DMM32AT_AIRBACK); - - if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) || - (aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) { - dev_err(dev->class_dev, "board detection failed\n"); + ailo = inb(dev->iobase + DMM32AT_AI_LO_CHAN_REG); + aihi = inb(dev->iobase + DMM32AT_AI_HI_CHAN_REG); + fifostat = inb(dev->iobase + DMM32AT_FIFO_STATUS_REG); + aistat = inb(dev->iobase + DMM32AT_AI_STATUS_REG); + intstat = inb(dev->iobase + DMM32AT_INTCLK_REG); + airback = inb(dev->iobase + DMM32AT_AI_READBACK_REG); + + /* + * NOTE: The (DMM32AT_AI_STATUS_SD1 | DMM32AT_AI_STATUS_SD0) + * test makes this driver only work if the board is configured + * with all A/D channels set for single-ended operation. + */ + if (ailo != 0x00 || aihi != 0x1f || + fifostat != DMM32AT_FIFO_STATUS_EF || + aistat != (DMM32AT_AI_STATUS_SD1 | DMM32AT_AI_STATUS_SD0) || + intstat != 0x00 || airback != 0x0c) return -EIO; + + return 0; +} + +static int dmm32at_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int ret; + + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + + ret = dmm32at_reset(dev); + if (ret) { + dev_err(dev->class_dev, "board detection failed\n"); + return ret; } if (it->options[1]) { @@ -706,65 +572,45 @@ static int dmm32at_attach(struct comedi_device *dev, dev->irq = it->options[1]; } - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - /* we support single-ended (ground) and differential */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = 32; - s->maxdata = 0xffff; - s->range_table = &dmm32at_airanges; - s->insn_read = dmm32at_ai_rinsn; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 32; + s->maxdata = 0xffff; + s->range_table = &dmm32at_airanges; + s->insn_read = dmm32at_ai_insn_read; if (dev->irq) { dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = 32; - s->do_cmd = dmm32at_ai_cmd; - s->do_cmdtest = dmm32at_ai_cmdtest; - s->cancel = dmm32at_ai_cancel; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmd = dmm32at_ai_cmd; + s->do_cmdtest = dmm32at_ai_cmdtest; + s->cancel = dmm32at_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0x0fff; - s->range_table = &dmm32at_aoranges; - s->insn_write = dmm32at_ao_insn_write; - s->insn_read = comedi_readback_insn_read; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->range_table = &dmm32at_aoranges; + s->insn_write = dmm32at_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) return ret; + /* Digital I/O subdevice */ s = &dev->subdevices[2]; - /* digital i/o subdevice */ - - /* get access to the DIO regs */ - outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); - /* set the DIO's to the defualt input setting */ - devpriv->dio_config = DMM32AT_DIRA | DMM32AT_DIRB | - DMM32AT_DIRCL | DMM32AT_DIRCH | DMM32AT_DIENABLE; - outb(devpriv->dio_config, dev->iobase + DMM32AT_DIOCONF); - - /* set up the subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 24; - s->maxdata = 1; - s->state = 0; - s->range_table = &range_digital; - s->insn_bits = dmm32at_dio_insn_bits; - s->insn_config = dmm32at_dio_insn_config; + ret = subdev_8255_init(dev, s, dmm32at_8255_io, DMM32AT_8255_IOBASE); + if (ret) + return ret; return 0; } @@ -778,5 +624,5 @@ static struct comedi_driver dmm32at_driver = { module_comedi_driver(dmm32at_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi: Diamond Systems Diamond-MM-32-AT"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index e97386343a0e..b96e60ffad73 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -597,7 +597,6 @@ havetype: devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); s->insn_write = dt2801_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 1736e397ad2c..d660f277487e 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -418,7 +418,6 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]]; devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]]; s->insn_write = dt2811_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index 9216c35c414e..9805be13005a 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -230,7 +230,7 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) s->async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index cc974a5e5cf6..2be98bb9a809 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -449,13 +449,29 @@ static void dt282x_munge(struct comedi_device *dev, } } +static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s, + int cur_dma) +{ + struct dt282x_private *devpriv = dev->private; + void *ptr = devpriv->dma[cur_dma].buf; + unsigned int nsamples = comedi_bytes_to_samples(s, devpriv->dma_maxsize); + unsigned int nbytes; + + nbytes = comedi_buf_read_samples(s, ptr, nsamples); + if (nbytes) + dt282x_prep_ao_dma(dev, cur_dma, nbytes); + else + dev_err(dev->class_dev, "AO underrun\n"); + + return nbytes; +} + static void dt282x_ao_dma_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { struct dt282x_private *devpriv = dev->private; int cur_dma = devpriv->current_dma_index; - void *ptr = devpriv->dma[cur_dma].buf; - int size; outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE, dev->iobase + DT2821_SUPCSR_REG); @@ -464,13 +480,8 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev, devpriv->current_dma_index = 1 - cur_dma; - size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); - if (size == 0) { - dev_err(dev->class_dev, "AO underrun\n"); + if (!dt282x_ao_setup_dma(dev, s, cur_dma)) s->async->events |= COMEDI_CB_OVERFLOW; - } else { - dt282x_prep_ao_dma(dev, cur_dma, size); - } } static void dt282x_ai_dma_interrupt(struct comedi_device *dev, @@ -480,6 +491,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev, int cur_dma = devpriv->current_dma_index; void *ptr = devpriv->dma[cur_dma].buf; int size = devpriv->dma[cur_dma].size; + unsigned int nsamples = comedi_bytes_to_samples(s, size); int ret; outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE, @@ -490,13 +502,11 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev, devpriv->current_dma_index = 1 - cur_dma; dt282x_munge(dev, s, ptr, size); - ret = cfc_write_array_to_buffer(s, ptr, size); - if (ret != size) { - s->async->events |= COMEDI_CB_OVERFLOW; + ret = comedi_buf_write_samples(s, ptr, nsamples); + if (ret != size) return; - } - devpriv->nread -= size / 2; + devpriv->nread -= nsamples; if (devpriv->nread < 0) { dev_info(dev->class_dev, "nread off by one\n"); devpriv->nread = 0; @@ -555,7 +565,6 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) } #if 0 if (adcsr & DT2821_ADCSR_ADDONE) { - int ret; unsigned short data; data = inw(dev->iobase + DT2821_ADDAT_REG); @@ -563,10 +572,7 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) if (devpriv->ad_2scomp) data = comedi_offset_munge(s, data); - ret = comedi_buf_put(s, data); - - if (ret == 0) - s->async->events |= COMEDI_CB_OVERFLOW; + comedi_buf_write_samples(s, &data, 1); devpriv->nread--; if (!devpriv->nread) { @@ -579,8 +585,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) handled = 1; } #endif - cfc_handle_events(dev, s); - cfc_handle_events(dev, s_ao); + comedi_handle_events(dev, s); + comedi_handle_events(dev, s_ao); return IRQ_RETVAL(handled); } @@ -916,26 +922,15 @@ static int dt282x_ao_inttrig(struct comedi_device *dev, { struct dt282x_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int size; if (trig_num != cmd->start_src) return -EINVAL; - size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, - devpriv->dma_maxsize); - if (size == 0) { - dev_err(dev->class_dev, "AO underrun\n"); + if (!dt282x_ao_setup_dma(dev, s, 0)) return -EPIPE; - } - dt282x_prep_ao_dma(dev, 0, size); - size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, - devpriv->dma_maxsize); - if (size == 0) { - dev_err(dev->class_dev, "AO underrun\n"); + if (!dt282x_ao_setup_dma(dev, s, 1)) return -EPIPE; - } - dt282x_prep_ao_dma(dev, 1, size); outw(devpriv->supcsr | DT2821_SUPCSR_STRIG, dev->iobase + DT2821_SUPCSR_REG); @@ -1236,7 +1231,6 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* ranges are per-channel, set by jumpers on the board */ s->range_table = &dt282x_ao_range; s->insn_write = dt282x_ao_insn_write; - s->insn_read = comedi_readback_insn_read; if (dev->irq) { dev->write_subdev = s; s->subdev_flags |= SDF_CMD_WRITE; diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 825561046b6f..1d9a7a63e06f 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -315,7 +315,7 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, for (i = 0; i < count; i++) { data = readw(dev->mmio + DPR_ADC_buffer + rear); - comedi_buf_put(s, data); + comedi_buf_write_samples(s, &data, 1); rear++; if (rear >= AI_FIFO_DEPTH) rear = 0; @@ -351,10 +351,8 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) status = readw(dev->mmio + DPR_Intr_Flag); - if (status & DT3000_ADFULL) { + if (status & DT3000_ADFULL) dt3k_ai_empty_fifo(dev, s); - s->async->events |= COMEDI_CB_BLOCK; - } if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; @@ -363,7 +361,7 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) if (debug_n_ints >= 10) s->async->events |= COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -699,7 +697,6 @@ static int dt3000_auto_attach(struct comedi_device *dev, s->len_chanlist = 1; s->range_table = &range_bipolar10; s->insn_write = dt3k_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 77bb89fee327..06c601d8fdff 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -804,7 +804,7 @@ static int dt9812_auto_attach(struct comedi_device *dev, /* Digital Output subdevice */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 8; s->maxdata = 1; s->range_table = &range_digital; @@ -822,7 +822,7 @@ static int dt9812_auto_attach(struct comedi_device *dev, /* Analog Output subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = 0x0fff; s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index 608aee0c3a15..1b6324c6eb29 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -218,7 +218,7 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, /* digital input */ s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->subdev_flags = SDF_READABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; @@ -228,7 +228,7 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, /* digital output */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index 5a1e3c8fc01c..e1f493241cd6 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -135,7 +135,6 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = &range_fl512; s->insn_write = fl512_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index b8975a4606ea..0979f536ed39 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -196,8 +196,8 @@ static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) size = devpriv->dio_count; devpriv->dio_count -= size; } - cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx], - size * sizeof(uint32_t)); + comedi_buf_write_samples(s, devpriv->desc_dio_buffer[idx], + size); idx++; idx %= devpriv->num_dma_descriptors; start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); @@ -272,7 +272,7 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) if (devpriv->dio_count == 0) async->events |= COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -689,7 +689,7 @@ static int gsc_hpdi_auto_attach(struct comedi_device *dev, s = &dev->subdevices[0]; dev->read_subdev = s; s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ; s->n_chan = 32; s->len_chanlist = 32; diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index f4e1c1cf4178..1ea168620103 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -53,7 +53,7 @@ Configuration options: not applicable, uses PCI auto config #define ICP_MULTI_AI 2 /* R: Analogue input data */ #define ICP_MULTI_DAC_CSR 4 /* R/W: DAC command/status register */ #define ICP_MULTI_AO 6 /* R/W: Analogue output data */ -#define ICP_MULTI_DI 8 /* R/W: Digital inouts */ +#define ICP_MULTI_DI 8 /* R/W: Digital inputs */ #define ICP_MULTI_DO 0x0A /* R/W: Digital outputs */ #define ICP_MULTI_INT_EN 0x0C /* R/W: Interrupt enable register */ #define ICP_MULTI_INT_STAT 0x0E /* R/W: Interrupt status register */ @@ -319,7 +319,7 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev, if (comedi_dio_update_state(s, data)) writew(s->state, dev->mmio + ICP_MULTI_DO); - data[1] = readw(dev->mmio + ICP_MULTI_DI); + data[1] = s->state; return insn->n; } @@ -495,7 +495,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s->len_chanlist = 4; s->range_table = &range_analog; s->insn_write = icp_multi_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -512,7 +511,7 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 8; s->maxdata = 1; s->len_chanlist = 8; @@ -521,7 +520,7 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s = &dev->subdevices[4]; s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 4; s->maxdata = 0xffff; s->len_chanlist = 4; diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index cc5fd75b8bc0..1085d66935fe 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -392,7 +392,6 @@ static int ii20k_init_module(struct comedi_device *dev, s->maxdata = 0xffff; s->range_table = &ii20k_ao_ranges; s->insn_write = ii20k_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 6561b00bea59..915685c1c85c 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -44,8 +44,6 @@ broken. #include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/list.h> -#include <linux/spinlock.h> #include "../comedidev.h" @@ -53,10 +51,7 @@ broken. #include "8253.h" #include "plx9052.h" -#if 0 -/* file removed due to GPL incompatibility */ -#include "me4000_fw.h" -#endif +#define ME4000_FIRMWARE "me4000_firmware.bin" /* * ME4000 Register map and bit defines @@ -333,27 +328,20 @@ static const struct comedi_lrange me4000_ai_range = { } }; -#define FIRMWARE_NOT_AVAILABLE 1 -#if FIRMWARE_NOT_AVAILABLE -extern unsigned char *xilinx_firm; -#endif - -static int xilinx_download(struct comedi_device *dev) +static int me4000_xilinx_download(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct me4000_info *info = dev->private; unsigned long xilinx_iobase = pci_resource_start(pcidev, 5); - u32 value = 0; - wait_queue_head_t queue; - int idx = 0; - int size = 0; - unsigned int intcsr; + unsigned int file_length; + unsigned int val; + unsigned int i; if (!xilinx_iobase) return -ENODEV; - init_waitqueue_head(&queue); - /* * Set PLX local interrupt 2 polarity to high. * Interrupt is thrown by init pin of xilinx. @@ -361,61 +349,58 @@ static int xilinx_download(struct comedi_device *dev) outl(PLX9052_INTCSR_LI2POL, info->plx_regbase + PLX9052_INTCSR); /* Set /CS and /WRITE of the Xilinx */ - value = inl(info->plx_regbase + PLX9052_CNTRL); - value |= PLX9052_CNTRL_UIO2_DATA; - outl(value, info->plx_regbase + PLX9052_CNTRL); + val = inl(info->plx_regbase + PLX9052_CNTRL); + val |= PLX9052_CNTRL_UIO2_DATA; + outl(val, info->plx_regbase + PLX9052_CNTRL); /* Init Xilinx with CS1 */ inb(xilinx_iobase + 0xC8); /* Wait until /INIT pin is set */ udelay(20); - intcsr = inl(info->plx_regbase + PLX9052_INTCSR); - if (!(intcsr & PLX9052_INTCSR_LI2STAT)) { + val = inl(info->plx_regbase + PLX9052_INTCSR); + if (!(val & PLX9052_INTCSR_LI2STAT)) { dev_err(dev->class_dev, "Can't init Xilinx\n"); return -EIO; } /* Reset /CS and /WRITE of the Xilinx */ - value = inl(info->plx_regbase + PLX9052_CNTRL); - value &= ~PLX9052_CNTRL_UIO2_DATA; - outl(value, info->plx_regbase + PLX9052_CNTRL); - if (FIRMWARE_NOT_AVAILABLE) { - dev_err(dev->class_dev, - "xilinx firmware unavailable due to licensing, aborting"); - return -EIO; - } else { - /* Download Xilinx firmware */ - size = (xilinx_firm[0] << 24) + (xilinx_firm[1] << 16) + - (xilinx_firm[2] << 8) + xilinx_firm[3]; - udelay(10); + val = inl(info->plx_regbase + PLX9052_CNTRL); + val &= ~PLX9052_CNTRL_UIO2_DATA; + outl(val, info->plx_regbase + PLX9052_CNTRL); - for (idx = 0; idx < size; idx++) { - outb(xilinx_firm[16 + idx], xilinx_iobase); - udelay(10); + /* Download Xilinx firmware */ + file_length = (((unsigned int)data[0] & 0xff) << 24) + + (((unsigned int)data[1] & 0xff) << 16) + + (((unsigned int)data[2] & 0xff) << 8) + + ((unsigned int)data[3] & 0xff); + udelay(10); - /* Check if BUSY flag is low */ - if (inl(info->plx_regbase + PLX9052_CNTRL) & PLX9052_CNTRL_UIO1_DATA) { - dev_err(dev->class_dev, - "Xilinx is still busy (idx = %d)\n", - idx); - return -EIO; - } + for (i = 0; i < file_length; i++) { + outb(data[16 + i], xilinx_iobase); + udelay(10); + + /* Check if BUSY flag is low */ + val = inl(info->plx_regbase + PLX9052_CNTRL); + if (val & PLX9052_CNTRL_UIO1_DATA) { + dev_err(dev->class_dev, + "Xilinx is still busy (i = %d)\n", i); + return -EIO; } } /* If done flag is high download was successful */ - if (inl(info->plx_regbase + PLX9052_CNTRL) & PLX9052_CNTRL_UIO0_DATA) { - } else { + val = inl(info->plx_regbase + PLX9052_CNTRL); + if (!(val & PLX9052_CNTRL_UIO0_DATA)) { dev_err(dev->class_dev, "DONE flag is not set\n"); dev_err(dev->class_dev, "Download not successful\n"); return -EIO; } /* Set /CS and /WRITE */ - value = inl(info->plx_regbase + PLX9052_CNTRL); - value |= PLX9052_CNTRL_UIO2_DATA; - outl(value, info->plx_regbase + PLX9052_CNTRL); + val = inl(info->plx_regbase + PLX9052_CNTRL); + val |= PLX9052_CNTRL_UIO2_DATA; + outl(val, info->plx_regbase + PLX9052_CNTRL); return 0; } @@ -431,7 +416,7 @@ static void me4000_reset(struct comedi_device *dev) val |= PLX9052_CNTRL_PCI_RESET; outl(val, info->plx_regbase + PLX9052_CNTRL); val &= ~PLX9052_CNTRL_PCI_RESET; - outl(val , info->plx_regbase + PLX9052_CNTRL); + outl(val, info->plx_regbase + PLX9052_CNTRL); /* 0x8000 to the DACs means an output voltage of 0V */ for (chan = 0; chan < 4; chan++) @@ -848,9 +833,6 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, unsigned int scan_ticks; int err = 0; - /* Only rounding flags are implemented */ - cmd->flags &= CMDF_ROUND_NEAREST | CMDF_ROUND_UP | CMDF_ROUND_DOWN; - /* Round the timer arguments */ ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks); @@ -1092,8 +1074,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { - s->async->events |= COMEDI_CB_BLOCK; - c = ME4000_AI_FIFO_COUNT / 2; } else { dev_err(dev->class_dev, @@ -1119,7 +1099,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, lval)) { + if (!comedi_buf_write_samples(s, &lval, 1)) { /* * Buffer overflow, so stop conversion * and disable all interrupts @@ -1128,11 +1108,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - - s->async->events |= COMEDI_CB_OVERFLOW; - - dev_err(dev->class_dev, "Buffer overflow\n"); - break; } } @@ -1146,7 +1121,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_SC) { - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA; + s->async->events |= COMEDI_CB_EOA; /* * Acquisition is complete, so stop @@ -1164,11 +1139,8 @@ 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, lval)) { - dev_err(dev->class_dev, "Buffer overflow\n"); - s->async->events |= COMEDI_CB_OVERFLOW; + if (!comedi_buf_write_samples(s, &lval, 1)) break; - } } /* Work is done, so reset the interrupt */ @@ -1178,8 +1150,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } - if (s->async->events) - comedi_event(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -1397,8 +1368,9 @@ static int me4000_auto_attach(struct comedi_device *dev, if (!info->plx_regbase || !dev->iobase || !info->timer_regbase) return -ENODEV; - result = xilinx_download(dev); - if (result) + result = comedi_load_firmware(dev, &pcidev->dev, ME4000_FIRMWARE, + me4000_xilinx_download, 0); + if (result < 0) return result; me4000_reset(dev); @@ -1449,12 +1421,11 @@ static int me4000_auto_attach(struct comedi_device *dev, if (thisboard->ao_nchan) { s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; + s->subdev_flags = SDF_WRITABLE | SDF_COMMON | SDF_GROUND; s->n_chan = thisboard->ao_nchan; s->maxdata = 0xFFFF; /* 16 bit DAC */ s->range_table = &range_bipolar10; s->insn_write = me4000_ao_insn_write; - s->insn_read = comedi_readback_insn_read; result = comedi_alloc_subdev_readback(s); if (result) @@ -1561,3 +1532,4 @@ module_comedi_pci_driver(me4000_driver, me4000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(ME4000_FIRMWARE); diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 00eaaf8ac148..b5278c11e622 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -511,13 +511,12 @@ static int me_auto_attach(struct comedi_device *dev, s = &dev->subdevices[1]; if (board->has_ao) { s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_COMMON; + s->subdev_flags = SDF_WRITABLE | SDF_COMMON; s->n_chan = 4; s->maxdata = 0x0fff; s->len_chanlist = 4; s->range_table = &me_ao_range; s->insn_write = me_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -528,7 +527,7 @@ static int me_auto_attach(struct comedi_device *dev, s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 32; s->maxdata = 1; s->len_chanlist = 32; diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c index c8d3a22c5896..af21bc180c46 100644 --- a/drivers/staging/comedi/drivers/mf6x4.c +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -259,7 +259,6 @@ static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context) s->maxdata = 0x3fff; /* 14 bits DAC */ s->range_table = &range_bipolar10; s->insn_write = mf6x4_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index 4f7829010a99..ffc9e61d6cdd 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -494,13 +494,10 @@ EXPORT_SYMBOL_GPL(mite_bytes_read_from_memory_ub); unsigned mite_dma_tcr(struct mite_channel *mite_chan) { struct mite_struct *mite = mite_chan->mite; - int tcr; int lkar; lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); - tcr = readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel)); - - return tcr; + return readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel)); } EXPORT_SYMBOL_GPL(mite_dma_tcr); @@ -542,7 +539,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, return 0; comedi_buf_write_free(s, count); - cfc_inc_scan_progress(s, count); + comedi_inc_scan_progress(s, count); async->events |= COMEDI_CB_BLOCK; return 0; } @@ -553,7 +550,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan, { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - u32 stop_count = cmd->stop_arg * cfc_bytes_per_scan(s); + u32 stop_count = cmd->stop_arg * comedi_bytes_per_scan(s); unsigned int old_alloc_count = async->buf_read_alloc_count; u32 nbytes_ub, nbytes_lb; int count; diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index f710c8e81320..8471219210b6 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -238,7 +238,6 @@ static int multiq3_attach(struct comedi_device *dev, s->maxdata = 0xfff; s->range_table = &range_bipolar5; s->insn_write = multiq3_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 45fb601e4080..f99847f3999f 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -208,9 +208,8 @@ static irqreturn_t ni6527_interrupt(int irq, void *d) return IRQ_NONE; if (status & NI6527_STATUS_EDGE) { - comedi_buf_put(s, 0); - s->async->events |= COMEDI_CB_EOS; - comedi_event(dev, s); + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); } writeb(NI6527_CLR_IRQS, dev->mmio + NI6527_CLR_REG); @@ -238,9 +237,6 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 3b642861eb36..bcb326e31562 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -508,9 +508,9 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d) writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT, dev->mmio + NI_65XX_CLR_REG); - comedi_buf_put(s, 0); - s->async->events |= COMEDI_CB_EOS; - comedi_event(dev, s); + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); + return IRQ_HANDLED; } @@ -534,9 +534,6 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 5b6794c8232e..1e4dd82b12ea 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -780,7 +780,7 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, struct ni_gpct *counter = s->private; ni_tio_handle_interrupt(counter, s); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static irqreturn_t ni_660x_interrupt(int irq, void *d) diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 54721deb80cc..c42a81c0bfa1 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -228,7 +228,6 @@ static int ni_670x_auto_attach(struct comedi_device *dev, s->range_table = &range_bipolar10; } s->insn_write = ni_670x_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 72ec857d073e..69e543a0bf22 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -168,7 +168,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) struct comedi_cmd *cmd; unsigned int max_points, num_points, residue, leftover; unsigned short dpnt; - static const int sample_size = sizeof(devpriv->dma_buffer[0]); if (!dev->attached) { dev_err(dev->class_dev, "premature interrupt\n"); @@ -188,14 +187,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d) if (status & OVFL_BIT) { dev_err(dev->class_dev, "fifo overflow\n"); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } if ((status & DMA_TC_BIT) == 0) { dev_err(dev->class_dev, "caught non-dma interrupt? Aborting.\n"); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -206,12 +205,12 @@ static irqreturn_t a2150_interrupt(int irq, void *d) clear_dma_ff(devpriv->dma); /* figure out how many points to read */ - max_points = devpriv->dma_transfer_size / sample_size; + max_points = comedi_bytes_to_samples(s, devpriv->dma_transfer_size); /* residue is the number of points left to be done on the dma * transfer. It should always be zero at this point unless * the stop_src is set to external triggering. */ - residue = get_dma_residue(devpriv->dma) / sample_size; + residue = comedi_bytes_to_samples(s, get_dma_residue(devpriv->dma)); num_points = max_points - residue; if (devpriv->count < num_points && cmd->stop_src == TRIG_COUNT) num_points = devpriv->count; @@ -219,7 +218,8 @@ static irqreturn_t a2150_interrupt(int irq, void *d) /* figure out how many points will be stored next time */ leftover = 0; if (cmd->stop_src == TRIG_NONE) { - leftover = devpriv->dma_transfer_size / sample_size; + leftover = comedi_bytes_to_samples(s, + devpriv->dma_transfer_size); } else if (devpriv->count > max_points) { leftover = devpriv->count - max_points; if (leftover > max_points) @@ -237,7 +237,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) dpnt = devpriv->dma_buffer[i]; /* convert from 2's complement to unsigned coding */ dpnt ^= 0x8000; - cfc_write_to_buffer(s, dpnt); + comedi_buf_write_samples(s, &dpnt, 1); if (cmd->stop_src == TRIG_COUNT) { if (--devpriv->count == 0) { /* end of acquisition */ async->events |= COMEDI_CB_EOA; @@ -248,14 +248,13 @@ static irqreturn_t a2150_interrupt(int irq, void *d) /* re-enable dma */ if (leftover) { set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer)); - set_dma_count(devpriv->dma, leftover * sample_size); + set_dma_count(devpriv->dma, + comedi_samples_to_bytes(s, leftover)); enable_dma(devpriv->dma); } release_dma_lock(flags); - async->events |= COMEDI_CB_BLOCK; - - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); /* clear interrupt */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 3e1ce5866147..05370a4a74a5 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -244,47 +244,31 @@ static int atao_calib_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct atao_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int bitstring; - unsigned int val; - int bit; - if (insn->n == 0) - return 0; + if (insn->n) { + unsigned int val = data[insn->n - 1]; + unsigned int bitstring = ((chan & 0x7) << 8) | val; + unsigned int bits; + int bit; - devpriv->caldac[chan] = data[insn->n - 1] & s->maxdata; + /* write the channel and last data value to the caldac */ + /* clock the bitstring to the caldac; MSB -> LSB */ + for (bit = 1 << 10; bit; bit >>= 1) { + bits = (bit & bitstring) ? ATAO_CFG2_SDATA : 0; - /* write the channel and last data value to the caldac */ - bitstring = ((chan & 0x7) << 8) | devpriv->caldac[chan]; + outw(bits, dev->iobase + ATAO_CFG2_REG); + outw(bits | ATAO_CFG2_SCLK, + dev->iobase + ATAO_CFG2_REG); + } - /* clock the bitstring to the caldac; MSB -> LSB */ - for (bit = 1 << 10; bit; bit >>= 1) { - val = (bit & bitstring) ? ATAO_CFG2_SDATA : 0; + /* strobe the caldac to load the value */ + outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG); + outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); - outw(val, dev->iobase + ATAO_CFG2_REG); - outw(val | ATAO_CFG2_SCLK, dev->iobase + ATAO_CFG2_REG); + s->readback[chan] = val; } - /* strobe the caldac to load the value */ - outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG); - outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); - - return insn->n; -} - -static int atao_calib_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct atao_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->caldac[chan]; - return insn->n; } @@ -344,7 +328,6 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = it->options[3] ? &range_unipolar10 : &range_bipolar10; s->insn_write = atao_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -366,9 +349,12 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; s->n_chan = (board->n_ao_chans * 2) + 1; s->maxdata = 0xff; - s->insn_read = atao_calib_insn_read; s->insn_write = atao_calib_insn_write; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + /* EEPROM subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_UNUSED; diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index fc3c19de7005..c484c89c94b5 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -217,10 +217,12 @@ static irqreturn_t atmio16d_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; + unsigned short val; - comedi_buf_put(s, inw(dev->iobase + AD_FIFO_REG)); + val = inw(dev->iobase + AD_FIFO_REG); + comedi_buf_write_samples(s, &val, 1); + comedi_handle_events(dev, s); - comedi_event(dev, s); return IRQ_HANDLED; } @@ -298,7 +300,6 @@ static int atmio16d_ai_cmd(struct comedi_device *dev, * It is still uber-experimental */ reset_counters(dev); - s->async->cur_chan = 0; /* check if scanning multiple channels */ if (cmd->chanlist_len < 2) { @@ -691,7 +692,6 @@ static int atmio16d_attach(struct comedi_device *dev, break; } s->insn_write = atmio16d_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h index f6e5cd15a409..ac2c01f9dfdc 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.h +++ b/drivers/staging/comedi/drivers/ni_labpc.h @@ -37,8 +37,6 @@ struct labpc_boardinfo { struct labpc_private { /* number of data points left to be taken */ unsigned long long count; - /* software copy of analog output values */ - unsigned int ao_value[NUM_AO_CHAN]; /* software copys of bits written to command registers */ unsigned int cmd1; unsigned int cmd2; @@ -70,10 +68,6 @@ struct labpc_private { unsigned int dma_transfer_size; /* we are using dma/fifo-half-full/etc. */ enum transfer_type current_transfer; - /* stores contents of board's eeprom */ - unsigned int eeprom_data[EEPROM_SIZE]; - /* stores settings of calibration dacs */ - unsigned int caldac[16]; /* * function pointers so we can use inb/outb or readb/writeb as * appropriate diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/staging/comedi/drivers/ni_labpc_common.c index 35bc2c25ddfb..d89d5852aeea 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_common.c +++ b/drivers/staging/comedi/drivers/ni_labpc_common.c @@ -818,7 +818,7 @@ static int labpc_drain_fifo(struct comedi_device *dev) devpriv->count--; } data = labpc_read_adc_fifo(dev); - cfc_write_to_buffer(dev->read_subdev, data); + comedi_buf_write_samples(dev->read_subdev, &data, 1); devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); } if (i == timeout) { @@ -876,7 +876,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); dev_err(dev->class_dev, "overrun\n"); return IRQ_HANDLED; } @@ -896,7 +896,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); dev_err(dev->class_dev, "overflow\n"); return IRQ_HANDLED; } @@ -914,10 +914,22 @@ static irqreturn_t labpc_interrupt(int irq, void *d) async->events |= COMEDI_CB_EOA; } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } +static void labpc_ao_write(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, unsigned int val) +{ + struct labpc_private *devpriv = dev->private; + + devpriv->write_byte(dev, val & 0xff, DAC_LSB_REG(chan)); + devpriv->write_byte(dev, (val >> 8) & 0xff, DAC_MSB_REG(chan)); + + s->readback[chan] = val; +} + static int labpc_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -927,7 +939,6 @@ static int labpc_ao_insn_write(struct comedi_device *dev, struct labpc_private *devpriv = dev->private; int channel, range; unsigned long flags; - int lsb, msb; channel = CR_CHAN(insn->chanspec); @@ -950,25 +961,7 @@ static int labpc_ao_insn_write(struct comedi_device *dev, devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG); } /* send data */ - lsb = data[0] & 0xff; - msb = (data[0] >> 8) & 0xff; - devpriv->write_byte(dev, lsb, DAC_LSB_REG(channel)); - devpriv->write_byte(dev, msb, DAC_MSB_REG(channel)); - - /* remember value for readback */ - devpriv->ao_value[channel] = data[0]; - - return 1; -} - -static int labpc_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct labpc_private *devpriv = dev->private; - - data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; + labpc_ao_write(dev, s, channel, data[0]); return 1; } @@ -1085,29 +1078,13 @@ static unsigned int labpc_eeprom_read_status(struct comedi_device *dev) return value; } -static int labpc_eeprom_write(struct comedi_device *dev, - unsigned int address, unsigned int value) +static void labpc_eeprom_write(struct comedi_device *dev, + unsigned int address, unsigned int value) { struct labpc_private *devpriv = dev->private; const int write_enable_instruction = 0x6; const int write_instruction = 0x2; const int write_length = 8; /* 8 bit write lengths to eeprom */ - const int write_in_progress_bit = 0x1; - const int timeout = 10000; - int i; - - /* make sure there isn't already a write in progress */ - for (i = 0; i < timeout; i++) { - if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) == - 0) - break; - } - if (i == timeout) { - dev_err(dev->class_dev, "eeprom write timed out\n"); - return -ETIME; - } - /* update software copy of eeprom */ - devpriv->eeprom_data[address] = value; /* enable read/write to eeprom */ devpriv->cmd5 &= ~CMD5_EEPROMCS; @@ -1140,8 +1117,6 @@ static int labpc_eeprom_write(struct comedi_device *dev, devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); udelay(1); devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - return 0; } /* writes to 8 bit calibration dacs */ @@ -1150,10 +1125,6 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel, { struct labpc_private *devpriv = dev->private; - if (value == devpriv->caldac[channel]) - return; - devpriv->caldac[channel] = value; - /* clear caldac load bit and make sure we don't write to eeprom */ devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT); udelay(1); @@ -1184,25 +1155,30 @@ static int labpc_calib_insn_write(struct comedi_device *dev, * Only write the last data value to the caldac. Preceding * data would be overwritten anyway. */ - if (insn->n > 0) - write_caldac(dev, chan, data[insn->n - 1]); + if (insn->n > 0) { + unsigned int val = data[insn->n - 1]; + + if (s->readback[chan] != val) { + write_caldac(dev, chan, val); + s->readback[chan] = val; + } + } return insn->n; } -static int labpc_calib_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int labpc_eeprom_ready(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct labpc_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->caldac[chan]; + unsigned int status; - return insn->n; + /* make sure there isn't already a write in progress */ + status = labpc_eeprom_read_status(dev); + if ((status & 0x1) == 0) + return 0; + return -EBUSY; } static int labpc_eeprom_insn_write(struct comedi_device *dev, @@ -1222,25 +1198,15 @@ static int labpc_eeprom_insn_write(struct comedi_device *dev, * data would be overwritten anyway. */ if (insn->n > 0) { - ret = labpc_eeprom_write(dev, chan, data[insn->n - 1]); + unsigned int val = data[insn->n - 1]; + + ret = comedi_timeout(dev, s, insn, labpc_eeprom_ready, 0); if (ret) return ret; - } - - return insn->n; -} - -static int labpc_eeprom_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct labpc_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - for (i = 0; i < insn->n; i++) - data[i] = devpriv->eeprom_data[chan]; + labpc_eeprom_write(dev, chan, val); + s->readback[chan] = val; + } return insn->n; } @@ -1309,19 +1275,15 @@ int labpc_common_attach(struct comedi_device *dev, s->n_chan = NUM_AO_CHAN; s->maxdata = 0x0fff; s->range_table = &range_labpc_ao; - s->insn_read = labpc_ao_insn_read; s->insn_write = labpc_ao_insn_write; - /* initialize analog outputs to a known value */ - for (i = 0; i < s->n_chan; i++) { - short lsb, msb; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; - devpriv->ao_value[i] = s->maxdata / 2; - lsb = devpriv->ao_value[i] & 0xff; - msb = (devpriv->ao_value[i] >> 8) & 0xff; - devpriv->write_byte(dev, lsb, DAC_LSB_REG(i)); - devpriv->write_byte(dev, msb, DAC_MSB_REG(i)); - } + /* initialize analog outputs to a known value */ + for (i = 0; i < s->n_chan; i++) + labpc_ao_write(dev, s, i, s->maxdata / 2); } else { s->type = COMEDI_SUBD_UNUSED; } @@ -1342,11 +1304,16 @@ int labpc_common_attach(struct comedi_device *dev, s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 16; s->maxdata = 0xff; - s->insn_read = labpc_calib_insn_read; s->insn_write = labpc_calib_insn_write; - for (i = 0; i < s->n_chan; i++) + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + for (i = 0; i < s->n_chan; i++) { write_caldac(dev, i, s->maxdata / 2); + s->readback[i] = s->maxdata / 2; + } } else { s->type = COMEDI_SUBD_UNUSED; } @@ -1358,11 +1325,14 @@ int labpc_common_attach(struct comedi_device *dev, s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = EEPROM_SIZE; s->maxdata = 0xff; - s->insn_read = labpc_eeprom_insn_read; s->insn_write = labpc_eeprom_insn_write; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + for (i = 0; i < s->n_chan; i++) - devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); + s->readback[i] = labpc_eeprom_read(dev, i); } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c index 967202e0635e..6d386050e59d 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c @@ -91,7 +91,6 @@ void labpc_drain_dma(struct comedi_device *dev) int status; unsigned long flags; unsigned int max_points, num_points, residue, leftover; - int i; status = devpriv->stat1; @@ -122,9 +121,7 @@ void labpc_drain_dma(struct comedi_device *dev) leftover = max_points; } - /* write data to comedi buffer */ - for (i = 0; i < num_points; i++) - cfc_write_to_buffer(s, devpriv->dma_buffer[i]); + comedi_buf_write_samples(s, devpriv->dma_buffer, num_points); if (cmd->stop_src == TRIG_COUNT) devpriv->count -= num_points; @@ -133,8 +130,6 @@ void labpc_drain_dma(struct comedi_device *dev) set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); set_dma_count(devpriv->dma_chan, leftover * sample_size); release_dma_lock(flags); - - async->events |= COMEDI_CB_BLOCK; } EXPORT_SYMBOL_GPL(labpc_drain_dma); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 320b080149b6..11e70173712d 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -686,13 +686,12 @@ static inline void ni_set_ai_dma_channel(struct comedi_device *dev, int channel) { unsigned bitfield; - if (channel >= 0) { + if (channel >= 0) bitfield = (ni_stc_dma_channel_select_bitfield(channel) << AI_DMA_Select_Shift) & AI_DMA_Select_Mask; - } else { + else bitfield = 0; - } ni_set_bitfield(dev, AI_AO_Select, AI_DMA_Select_Mask, bitfield); } @@ -701,13 +700,12 @@ static inline void ni_set_ao_dma_channel(struct comedi_device *dev, int channel) { unsigned bitfield; - if (channel >= 0) { + if (channel >= 0) bitfield = (ni_stc_dma_channel_select_bitfield(channel) << AO_DMA_Select_Shift) & AO_DMA_Select_Mask; - } else { + else bitfield = 0; - } ni_set_bitfield(dev, AI_AO_Select, AO_DMA_Select_Mask, bitfield); } @@ -1127,31 +1125,18 @@ static void ni_ao_fifo_load(struct comedi_device *dev, struct comedi_subdevice *s, int n) { struct ni_private *devpriv = dev->private; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - int chan; int i; unsigned short d; u32 packed_data; - int range; - int err = 1; - chan = async->cur_chan; for (i = 0; i < n; i++) { - err &= comedi_buf_get(s, &d); - if (err == 0) - break; - - range = CR_RANGE(cmd->chanlist[chan]); + comedi_buf_read_samples(s, &d, 1); if (devpriv->is_6xxx) { packed_data = d & 0xffff; /* 6711 only has 16 bit wide ao fifo */ if (!devpriv->is_6711) { - err &= comedi_buf_get(s, &d); - if (err == 0) - break; - chan++; + comedi_buf_read_samples(s, &d, 1); i++; packed_data |= (d << 16) & 0xffff0000; } @@ -1159,12 +1144,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev, } else { ni_writew(dev, d, DAC_FIFO_Data); } - chan++; - chan %= cmd->chanlist_len; } - async->cur_chan = chan; - if (err == 0) - async->events |= COMEDI_CB_OVERFLOW; } /* @@ -1187,21 +1167,20 @@ static int ni_ao_fifo_half_empty(struct comedi_device *dev, struct comedi_subdevice *s) { const struct ni_board_struct *board = dev->board_ptr; - int n; + unsigned int nbytes; + unsigned int nsamples; - n = comedi_buf_read_n_available(s); - if (n == 0) { + nbytes = comedi_buf_read_n_available(s); + if (nbytes == 0) { s->async->events |= COMEDI_CB_OVERFLOW; return 0; } - n /= sizeof(short); - if (n > board->ao_fifo_depth / 2) - n = board->ao_fifo_depth / 2; - - ni_ao_fifo_load(dev, s, n); + nsamples = comedi_bytes_to_samples(s, nbytes); + if (nsamples > board->ao_fifo_depth / 2) + nsamples = board->ao_fifo_depth / 2; - s->async->events |= COMEDI_CB_BLOCK; + ni_ao_fifo_load(dev, s, nsamples); return 1; } @@ -1211,7 +1190,8 @@ static int ni_ao_prep_fifo(struct comedi_device *dev, { const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; - int n; + unsigned int nbytes; + unsigned int nsamples; /* reset fifo */ ni_stc_writew(dev, 1, DAC_FIFO_Clear); @@ -1219,17 +1199,17 @@ 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); - if (n == 0) + nbytes = comedi_buf_read_n_available(s); + if (nbytes == 0) return 0; - n /= sizeof(short); - if (n > board->ao_fifo_depth) - n = board->ao_fifo_depth; + nsamples = comedi_bytes_to_samples(s, nbytes); + if (nsamples > board->ao_fifo_depth) + nsamples = board->ao_fifo_depth; - ni_ao_fifo_load(dev, s, n); + ni_ao_fifo_load(dev, s, nsamples); - return n; + return nsamples; } static void ni_ai_fifo_read(struct comedi_device *dev, @@ -1237,44 +1217,42 @@ static void ni_ai_fifo_read(struct comedi_device *dev, { struct ni_private *devpriv = dev->private; struct comedi_async *async = s->async; + u32 dl; + unsigned short data; int i; if (devpriv->is_611x) { - unsigned short data[2]; - u32 dl; - for (i = 0; i < n / 2; i++) { dl = ni_readl(dev, ADC_FIFO_Data_611x); /* This may get the hi/lo data in the wrong order */ - data[0] = (dl >> 16) & 0xffff; - data[1] = dl & 0xffff; - cfc_write_array_to_buffer(s, data, sizeof(data)); + data = (dl >> 16) & 0xffff; + comedi_buf_write_samples(s, &data, 1); + data = dl & 0xffff; + comedi_buf_write_samples(s, &data, 1); } /* Check if there's a single sample stuck in the FIFO */ if (n % 2) { dl = ni_readl(dev, ADC_FIFO_Data_611x); - data[0] = dl & 0xffff; - cfc_write_to_buffer(s, data[0]); + data = dl & 0xffff; + comedi_buf_write_samples(s, &data, 1); } } else if (devpriv->is_6143) { - unsigned short data[2]; - u32 dl; - /* This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed */ for (i = 0; i < n / 2; i++) { dl = ni_readl(dev, AIFIFO_Data_6143); - data[0] = (dl >> 16) & 0xffff; - data[1] = dl & 0xffff; - cfc_write_array_to_buffer(s, data, sizeof(data)); + data = (dl >> 16) & 0xffff; + comedi_buf_write_samples(s, &data, 1); + data = dl & 0xffff; + comedi_buf_write_samples(s, &data, 1); } if (n % 2) { /* Assume there is a single sample stuck in the FIFO */ /* Get stranded sample into FIFO */ ni_writel(dev, 0x01, AIFIFO_Control_6143); dl = ni_readl(dev, AIFIFO_Data_6143); - data[0] = (dl >> 16) & 0xffff; - cfc_write_to_buffer(s, data[0]); + data = (dl >> 16) & 0xffff; + comedi_buf_write_samples(s, &data, 1); } } else { if (n > sizeof(devpriv->ai_fifo_buffer) / @@ -1288,9 +1266,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev, devpriv->ai_fifo_buffer[i] = ni_readw(dev, ADC_FIFO_Data_Register); } - cfc_write_array_to_buffer(s, devpriv->ai_fifo_buffer, - n * - sizeof(devpriv->ai_fifo_buffer[0])); + comedi_buf_write_samples(s, devpriv->ai_fifo_buffer, n); } } @@ -1313,8 +1289,8 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) { struct ni_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - unsigned short data[2]; u32 dl; + unsigned short data; unsigned short fifo_empty; int i; @@ -1324,9 +1300,10 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) dl = ni_readl(dev, ADC_FIFO_Data_611x); /* This may get the hi/lo data in the wrong order */ - data[0] = (dl >> 16); - data[1] = (dl & 0xffff); - cfc_write_array_to_buffer(s, data, sizeof(data)); + data = dl >> 16; + comedi_buf_write_samples(s, &data, 1); + data = dl & 0xffff; + comedi_buf_write_samples(s, &data, 1); } } else if (devpriv->is_6143) { i = 0; @@ -1334,9 +1311,10 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) dl = ni_readl(dev, AIFIFO_Data_6143); /* This may get the hi/lo data in the wrong order */ - data[0] = (dl >> 16); - data[1] = (dl & 0xffff); - cfc_write_array_to_buffer(s, data, sizeof(data)); + data = dl >> 16; + comedi_buf_write_samples(s, &data, 1); + data = dl & 0xffff; + comedi_buf_write_samples(s, &data, 1); i += 2; } /* Check if stranded sample is present */ @@ -1344,8 +1322,8 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) /* Get stranded sample into FIFO */ ni_writel(dev, 0x01, AIFIFO_Control_6143); dl = ni_readl(dev, AIFIFO_Data_6143); - data[0] = (dl >> 16) & 0xffff; - cfc_write_to_buffer(s, data[0]); + data = (dl >> 16) & 0xffff; + comedi_buf_write_samples(s, &data, 1); } } else { @@ -1364,10 +1342,7 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) devpriv->ai_fifo_buffer[i] = ni_readw(dev, ADC_FIFO_Data_Register); } - cfc_write_array_to_buffer(s, devpriv->ai_fifo_buffer, - i * - sizeof(devpriv-> - ai_fifo_buffer[0])); + comedi_buf_write_samples(s, devpriv->ai_fifo_buffer, i); } } } @@ -1386,7 +1361,7 @@ static void get_last_sample_611x(struct comedi_device *dev) if (ni_readb(dev, XXX_Status) & 0x80) { dl = ni_readl(dev, ADC_FIFO_Data_611x); data = (dl & 0xffff); - cfc_write_to_buffer(s, data); + comedi_buf_write_samples(s, &data, 1); } } @@ -1408,7 +1383,7 @@ static void get_last_sample_6143(struct comedi_device *dev) /* This may get the hi/lo data in the wrong order */ data = (dl >> 16) & 0xffff; - cfc_write_to_buffer(s, data); + comedi_buf_write_samples(s, &data, 1); } } @@ -1462,7 +1437,7 @@ static void handle_gpct_interrupt(struct comedi_device *dev, ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index], s); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); #endif } @@ -1518,7 +1493,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; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } return; } @@ -1533,7 +1508,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; - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return; } if (status & AI_SC_TC_St) { @@ -1559,7 +1534,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if ((status & AI_STOP_St)) ni_handle_eos(dev, s); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) @@ -1635,7 +1610,7 @@ static void handle_b_interrupt(struct comedi_device *dev, } #endif - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, @@ -1645,12 +1620,12 @@ 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; struct comedi_cmd *cmd = &async->cmd; - unsigned int length = num_bytes / bytes_per_sample(s); + unsigned int nsamples = comedi_bytes_to_samples(s, num_bytes); unsigned short *array = data; unsigned int *larray = data; unsigned int i; - for (i = 0; i < length; i++) { + for (i = 0; i < nsamples; i++) { #ifdef PCIDMA if (s->subdev_flags & SDF_LSAMPL) larray[i] = le32_to_cpu(larray[i]); @@ -2253,9 +2228,6 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 1 : check if triggers are trivially valid */ - if ((cmd->flags & CMDF_WRITE)) - cmd->flags &= ~CMDF_WRITE; - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, @@ -2762,11 +2734,11 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int chan_index) { struct comedi_cmd *cmd = &s->async->cmd; - unsigned int length = num_bytes / bytes_per_sample(s); + unsigned int nsamples = comedi_bytes_to_samples(s, num_bytes); unsigned short *array = data; unsigned int i; - for (i = 0; i < length; i++) { + for (i = 0; i < nsamples; i++) { unsigned int range = CR_RANGE(cmd->chanlist[chan_index]); unsigned short val = array[i]; @@ -2981,12 +2953,15 @@ static int ni_ao_insn_config(struct comedi_device *dev, { const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; + unsigned int nbytes; switch (data[0]) { case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: switch (data[1]) { case COMEDI_OUTPUT: - data[2] = 1 + board->ao_fifo_depth * sizeof(short); + nbytes = comedi_samples_to_bytes(s, + board->ao_fifo_depth); + data[2] = 1 + nbytes; if (devpriv->mite) data[2] += devpriv->mite->fifo_size; break; @@ -3288,9 +3263,6 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 1 : check if triggers are trivially valid */ - if ((cmd->flags & CMDF_WRITE) == 0) - cmd->flags |= CMDF_WRITE; - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER | TRIG_EXT); @@ -3515,9 +3487,6 @@ static int ni_cdio_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); @@ -3693,7 +3662,7 @@ static void handle_cdio_interrupt(struct comedi_device *dev) M_Offset_CDIO_Command); /* s->async->events |= COMEDI_CB_EOA; */ } - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } static int ni_serial_hw_readwrite8(struct comedi_device *dev, @@ -3976,7 +3945,7 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg) stc_register = Interrupt_B_Enable_Register; break; default: - printk("%s: unhandled register 0x%x in switch.\n", + pr_err("%s: unhandled register 0x%x in switch.\n", __func__, reg); BUG(); return 0; @@ -5472,7 +5441,6 @@ static int ni_E_init(struct comedi_device *dev, s->range_table = board->ao_range_table; s->insn_config = ni_ao_insn_config; s->insn_write = ni_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 5252cba82e5e..db7e8aac67b5 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -384,11 +384,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; - - /* int i, j; */ - unsigned int auxdata = 0; - unsigned short data1 = 0; - unsigned short data2 = 0; + unsigned int auxdata; int flags; int status; int work = 0; @@ -451,13 +447,9 @@ static irqreturn_t nidio_interrupt(int irq, void *d) goto out; } auxdata = readl(dev->mmio + Group_1_FIFO); - data1 = auxdata & 0xffff; - data2 = (auxdata & 0xffff0000) >> 16; - comedi_buf_put(s, data1); - comedi_buf_put(s, data2); + comedi_buf_write_samples(s, &auxdata, 1); flags = readb(dev->mmio + Group_1_Flags); } - async->events |= COMEDI_CB_BLOCK; } if (flags & CountExpired) { @@ -485,7 +477,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) } out: - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); #if 0 if (!tag) writeb(0x03, dev->mmio + Master_DMA_And_Interrupt_Control); diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index 29efce30eb7f..bd69c3f0acdc 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -334,7 +334,7 @@ static inline unsigned RTSI_Output_Bit(unsigned channel, int is_mseries) max_channel = 6; } if (channel > max_channel) { - printk("%s: bug, invalid RTSI_channel=%i\n", __func__, channel); + pr_err("%s: bug, invalid RTSI_channel=%i\n", __func__, channel); return 0; } return 1 << (base_bit_shift + channel); @@ -1090,7 +1090,7 @@ static inline int M_Offset_Static_AI_Control(int i) 0x263, }; if (((unsigned)i) >= ARRAY_SIZE(offset)) { - printk("%s: invalid channel=%i\n", __func__, i); + pr_err("%s: invalid channel=%i\n", __func__, i); return offset[0]; } return offset[i]; @@ -1105,7 +1105,7 @@ static inline int M_Offset_AO_Reference_Attenuation(int channel) 0x267 }; if (((unsigned)channel) >= ARRAY_SIZE(offset)) { - printk("%s: invalid channel=%i\n", __func__, channel); + pr_err("%s: invalid channel=%i\n", __func__, channel); return offset[0]; } return offset[channel]; @@ -1114,7 +1114,7 @@ static inline int M_Offset_AO_Reference_Attenuation(int channel) static inline unsigned M_Offset_PFI_Output_Select(unsigned n) { if (n < 1 || n > NUM_PFI_OUTPUT_SELECT_REGS) { - printk("%s: invalid pfi output select register=%i\n", + pr_err("%s: invalid pfi output select register=%i\n", __func__, n); return M_Offset_PFI_Output_Select_1; } @@ -1171,7 +1171,7 @@ static inline unsigned MSeries_PLL_In_Source_Select_RTSI_Bits(unsigned RTSI_channel) { if (RTSI_channel > 7) { - printk("%s: bug, invalid RTSI_channel=%i\n", __func__, + pr_err("%s: bug, invalid RTSI_channel=%i\n", __func__, RTSI_channel); return 0; } @@ -1192,7 +1192,7 @@ static inline unsigned MSeries_PLL_Divisor_Bits(unsigned divisor) { static const unsigned max_divisor = 0x10; if (divisor < 1 || divisor > max_divisor) { - printk("%s: bug, invalid divisor=%i\n", __func__, divisor); + pr_err("%s: bug, invalid divisor=%i\n", __func__, divisor); return 0; } return (divisor & 0xf) << 8; @@ -1202,7 +1202,7 @@ static inline unsigned MSeries_PLL_Multiplier_Bits(unsigned multiplier) { static const unsigned max_multiplier = 0x100; if (multiplier < 1 || multiplier > max_multiplier) { - printk("%s: bug, invalid multiplier=%i\n", __func__, + pr_err("%s: bug, invalid multiplier=%i\n", __func__, multiplier); return 0; } @@ -1464,7 +1464,7 @@ struct ni_private { unsigned short ai_fifo_buffer[0x2000]; uint8_t eeprom_buffer[M_SERIES_EEPROM_SIZE]; - uint32_t serial_number; + __be32 serial_number; struct mite_struct *mite; struct mite_channel *ai_mite_chan; diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 26e7291c4a51..6037bec77ef1 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -371,9 +371,8 @@ static void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, of gate interrupt via dma read/write and report bogus gate errors */ if (counter->counter_dev->variant != - ni_gpct_variant_660x) { + ni_gpct_variant_660x) *gate_error = 1; - } } } if (gxx_status & GI_TC_ERROR(cidx)) { @@ -450,11 +449,10 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, return; } gpct_mite_status = mite_get_status(counter->mite_chan); - if (gpct_mite_status & CHSR_LINKC) { + if (gpct_mite_status & CHSR_LINKC) writel(CHOR_CLRLC, counter->mite_chan->mite->mite_io_addr + MITE_CHOR(counter->mite_chan->channel)); - } mite_sync_input_dma(counter->mite_chan, s); spin_unlock_irqrestore(&counter->lock, flags); } diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c index df7ada8611f4..3b5a1b90366d 100644 --- a/drivers/staging/comedi/drivers/ni_usb6501.c +++ b/drivers/staging/comedi/drivers/ni_usb6501.c @@ -561,7 +561,7 @@ static int ni6501_auto_attach(struct comedi_device *dev, /* Counter subdevice */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; s->n_chan = 1; s->maxdata = 0xffffffff; s->insn_read = ni6501_cnt_insn_read; diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index 47f4887108a7..938aebc8e0ea 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -156,7 +156,6 @@ static const struct pcl711_board boardtypes[] = { }; struct pcl711_private { - unsigned int ntrig; unsigned int divisor1; unsigned int divisor2; }; @@ -199,7 +198,6 @@ static int pcl711_ai_cancel(struct comedi_device *dev, 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; @@ -213,16 +211,14 @@ 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, data) == 0) { - s->async->events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; - } else { - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (cmd->stop_src == TRIG_COUNT && !(--devpriv->ntrig)) { - pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); - s->async->events |= COMEDI_CB_EOA; - } - } - comedi_event(dev, s); + comedi_buf_write_samples(s, &data, 1); + + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) + s->async->events |= COMEDI_CB_EOA; + + comedi_handle_events(dev, s); + return IRQ_HANDLED; } @@ -373,14 +369,10 @@ static void pcl711_ai_load_counters(struct comedi_device *dev) static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pcl711_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; pcl711_set_changain(dev, s, cmd->chanlist[0]); - if (cmd->stop_src == TRIG_COUNT) - devpriv->ntrig = cmd->stop_arg; - if (cmd->scan_begin_src == TRIG_TIMER) { pcl711_ai_load_counters(dev); outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); @@ -505,7 +497,6 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xfff; s->range_table = &range_bipolar5; s->insn_write = pcl711_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index dc179bd02dfd..86f713fdf1d0 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -235,9 +235,8 @@ static irqreturn_t pcl726_interrupt(int irq, void *d) if (devpriv->cmd_running) { pcl726_intr_cancel(dev, s); - comedi_buf_put(s, 0); - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - comedi_event(dev, s); + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); } return IRQ_HANDLED; @@ -377,7 +376,6 @@ static int pcl726_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table_list = devpriv->rangelist; s->insn_write = pcl726_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index fd5ea6e01619..ac243ca5e0f8 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -512,7 +512,6 @@ struct pcl812_private { unsigned int last_ai_chanspec; unsigned char mode_reg_int; /* there is stored INT number for some card */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - unsigned int ai_act_scan; /* how many scans we finished */ unsigned int dmapages; unsigned int hwdmasize; unsigned long dmabuf[2]; /* PTR to DMA buf */ @@ -556,8 +555,8 @@ static void pcl812_ai_setup_dma(struct comedi_device *dev, /* 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->dmabytestomove[0] = comedi_bytes_per_scan(s); + devpriv->dmabytestomove[1] = comedi_bytes_per_scan(s); devpriv->dma_runs_to_end = 1; } else { devpriv->dmabytestomove[0] = devpriv->hwdmasize; @@ -572,7 +571,7 @@ static void pcl812_ai_setup_dma(struct comedi_device *dev, devpriv->dma_runs_to_end = 1; } else { /* how many samples we must transfer? */ - bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + bytes = cmd->stop_arg * comedi_bytes_per_scan(s); /* how many DMA pages we must fill */ devpriv->dma_runs_to_end = @@ -807,9 +806,7 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_dma = 0; } - devpriv->ai_act_scan = 0; devpriv->ai_poll_ptr = 0; - s->async->cur_chan = 0; /* don't we want wake up every scan? */ if (cmd->flags & CMDF_WAKE_EOS) { @@ -841,21 +838,10 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static bool pcl812_ai_next_chan(struct comedi_device *dev, struct comedi_subdevice *s) { - struct pcl812_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 >= cmd->chanlist_len) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - s->async->events |= COMEDI_CB_EOS; - } - if (cmd->stop_src == TRIG_COUNT && - devpriv->ai_act_scan >= cmd->stop_arg) { - /* all data sampled */ + s->async->scans_done >= cmd->stop_arg) { s->async->events |= COMEDI_CB_EOA; return false; } @@ -867,7 +853,9 @@ static void pcl812_handle_eoc(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; + unsigned int chan = s->async->cur_chan; unsigned int next_chan; + unsigned short val; if (pcl812_ai_eoc(dev, s, NULL, 0)) { dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); @@ -875,13 +863,12 @@ static void pcl812_handle_eoc(struct comedi_device *dev, return; } - comedi_buf_put(s, pcl812_ai_get_sample(dev, s)); + val = pcl812_ai_get_sample(dev, s); + comedi_buf_write_samples(s, &val, 1); /* Set up next channel. Added by abbotti 2010-01-20, but untested. */ - next_chan = s->async->cur_chan + 1; - if (next_chan >= cmd->chanlist_len) - next_chan = 0; - if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan]) + next_chan = s->async->cur_chan; + if (cmd->chanlist[chan] != cmd->chanlist[next_chan]) pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0); pcl812_ai_next_chan(dev, s); @@ -893,9 +880,11 @@ static void transfer_from_dma_buf(struct comedi_device *dev, unsigned int bufptr, unsigned int len) { unsigned int i; + unsigned short val; for (i = len; i; i--) { - comedi_buf_put(s, ptr[bufptr++]); + val = ptr[bufptr++]; + comedi_buf_write_samples(s, &val, 1); if (!pcl812_ai_next_chan(dev, s)) break; @@ -939,7 +928,7 @@ static irqreturn_t pcl812_interrupt(int irq, void *d) pcl812_ai_clear_eoc(dev); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -1335,7 +1324,6 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) break; } s->insn_write = pcl812_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index aa6487132017..73deb4bd5c93 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -122,7 +122,6 @@ struct pcl816_private { 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 */ - int ai_act_scan; /* how many scans we finished */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ unsigned int divisor1; unsigned int divisor2; @@ -160,7 +159,7 @@ static void pcl816_ai_setup_dma(struct comedi_device *dev, bytes = devpriv->hwdmasize; if (cmd->stop_src == TRIG_COUNT) { /* how many */ - bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + bytes = cmd->stop_arg * comedi_bytes_per_scan(s); /* how many DMA pages we must fill */ devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; @@ -286,21 +285,10 @@ static int pcl816_ai_eoc(struct comedi_device *dev, 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 >= cmd->chanlist_len) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - s->async->events |= COMEDI_CB_EOS; - } - if (cmd->stop_src == TRIG_COUNT && - devpriv->ai_act_scan >= cmd->stop_arg) { - /* all data sampled */ + s->async->scans_done >= cmd->stop_arg) { s->async->events |= COMEDI_CB_EOA; return false; } @@ -313,10 +301,12 @@ static void transfer_from_dma_buf(struct comedi_device *dev, unsigned short *ptr, unsigned int bufptr, unsigned int len) { + unsigned short val; int i; for (i = 0; i < len; i++) { - comedi_buf_put(s, ptr[bufptr++]); + val = ptr[bufptr++]; + comedi_buf_write_samples(s, &val, 1); if (!pcl816_ai_next_chan(dev, s)) return; @@ -355,7 +345,7 @@ static irqreturn_t pcl816_interrupt(int irq, void *d) pcl816_ai_clear_eoc(dev); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -508,8 +498,6 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen); udelay(1); - devpriv->ai_act_scan = 0; - s->async->cur_chan = 0; devpriv->ai_cmd_running = 1; devpriv->ai_poll_ptr = 0; devpriv->ai_cmd_canceled = 0; @@ -566,7 +554,7 @@ 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); + comedi_handle_events(dev, s); return comedi_buf_n_bytes_ready(s); } diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index ac19e83ce62a..8edea35532a9 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -313,8 +313,6 @@ struct pcl818_private { unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */ int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ - 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 */ @@ -352,7 +350,7 @@ static void pcl818_ai_setup_dma(struct comedi_device *dev, disable_dma(devpriv->dma); /* disable dma */ bytes = devpriv->hwdmasize; if (cmd->stop_src == TRIG_COUNT) { - bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + bytes = cmd->stop_arg * comedi_bytes_per_scan(s); devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; devpriv->last_dma_run = bytes % devpriv->hwdmasize; devpriv->dma_runs_to_end--; @@ -521,21 +519,12 @@ static bool pcl818_ai_next_chan(struct comedi_device *dev, 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 >= cmd->chanlist_len) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - s->async->events |= COMEDI_CB_EOS; - } - - if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) { - /* all data sampled */ + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) { s->async->events |= COMEDI_CB_EOA; return false; } @@ -560,7 +549,7 @@ static void pcl818_handle_eoc(struct comedi_device *dev, if (pcl818_ai_dropout(dev, s, chan)) return; - comedi_buf_put(s, val); + comedi_buf_write_samples(s, &val, 1); pcl818_ai_next_chan(dev, s); } @@ -589,7 +578,7 @@ static void pcl818_handle_dma(struct comedi_device *dev, if (pcl818_ai_dropout(dev, s, chan)) break; - comedi_buf_put(s, val); + comedi_buf_write_samples(s, &val, 1); if (!pcl818_ai_next_chan(dev, s)) break; @@ -630,7 +619,7 @@ static void pcl818_handle_fifo(struct comedi_device *dev, if (pcl818_ai_dropout(dev, s, chan)) break; - comedi_buf_put(s, val); + comedi_buf_write_samples(s, &val, 1); if (!pcl818_ai_next_chan(dev, s)) break; @@ -642,6 +631,7 @@ 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; + struct comedi_cmd *cmd = &s->async->cmd; if (!dev->attached || !devpriv->ai_cmd_running) { pcl818_ai_clear_eoc(dev); @@ -655,7 +645,7 @@ static irqreturn_t pcl818_interrupt(int irq, void *d) * being reprogrammed while a DMA transfer is in * progress. */ - devpriv->ai_act_scan = 0; + s->async->scans_done = cmd->stop_arg; s->cancel(dev, s); return IRQ_HANDLED; } @@ -669,7 +659,7 @@ static irqreturn_t pcl818_interrupt(int irq, void *d) pcl818_ai_clear_eoc(dev); - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); return IRQ_HANDLED; } @@ -829,8 +819,6 @@ static int pcl818_ai_cmd(struct comedi_device *dev, pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen); devpriv->ai_data_len = s->async->prealloc_bufsz; - 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; @@ -873,7 +861,8 @@ static int pcl818_ai_cancel(struct comedi_device *dev, if (devpriv->dma) { if (cmd->stop_src == TRIG_NONE || - (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) { + (cmd->stop_src == TRIG_COUNT && + s->async->scans_done < cmd->stop_arg)) { if (!devpriv->ai_cmd_canceled) { /* * Wait for running dma transfer to end, @@ -1169,7 +1158,6 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_unknown; } s->insn_write = pcl818_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index fc40ee2b34e9..f0059e935da0 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -190,7 +190,6 @@ struct pcmmio_private { spinlock_t pagelock; /* protects the page registers */ spinlock_t spinlock; /* protects the member variables */ unsigned int enabled_mask; - unsigned int stop_count; unsigned int active:1; }; @@ -337,7 +336,6 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev, { struct pcmmio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int oldevents = s->async->events; unsigned int val = 0; unsigned long flags; int i; @@ -357,31 +355,16 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev, val |= (1 << i); } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s, val) && - comedi_buf_put(s, val >> 16)) { - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - } else { - /* Overflow! Stop acquisition!! */ - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmmio_stop_intr(dev, s); - } + comedi_buf_write_samples(s, &val, 1); - /* Check for end of acquisition. */ - if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count > 0) { - devpriv->stop_count--; - if (devpriv->stop_count == 0) { - s->async->events |= COMEDI_CB_EOA; - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmmio_stop_intr(dev, s); - } - } + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) + s->async->events |= COMEDI_CB_EOA; done: spin_unlock_irqrestore(&devpriv->spinlock, flags); - if (oldevents != s->async->events) - comedi_event(dev, s); + comedi_handle_events(dev, s); } static irqreturn_t interrupt_pcmmio(int irq, void *d) @@ -481,8 +464,6 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) spin_lock_irqsave(&devpriv->spinlock, flags); devpriv->active = 1; - devpriv->stop_count = cmd->stop_arg; - /* Set up start of acquisition. */ if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmmio_inttrig_start_intr; @@ -751,7 +732,6 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xffff; s->range_table = &pcmmio_ao_ranges; s->insn_write = pcmmio_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -774,7 +754,7 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_config = pcmmio_dio_insn_config; if (dev->irq) { dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; + s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL | SDF_PACKED; s->len_chanlist = s->n_chan; s->cancel = pcmmio_cancel; s->do_cmd = pcmmio_cmd; diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index d4fe2ec25ecf..0f5483b6147f 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -130,7 +130,6 @@ struct pcmuio_asic { spinlock_t pagelock; /* protects the page registers */ spinlock_t spinlock; /* protects member variables */ unsigned int enabled_mask; - unsigned int stop_count; unsigned int active:1; }; @@ -317,7 +316,6 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, int asic = pcmuio_subdevice_to_asic(s); struct pcmuio_asic *chip = &devpriv->asics[asic]; struct comedi_cmd *cmd = &s->async->cmd; - unsigned oldevents = s->async->events; unsigned int val = 0; unsigned long flags; unsigned int i; @@ -337,33 +335,16 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, val |= (1 << i); } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s, val) && - comedi_buf_put(s, val >> 16)) { - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - } else { - /* Overflow! Stop acquisition!! */ - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmuio_stop_intr(dev, s); - } + comedi_buf_write_samples(s, &val, 1); - /* Check for end of acquisition. */ - if (cmd->stop_src == TRIG_COUNT) { - if (chip->stop_count > 0) { - chip->stop_count--; - if (chip->stop_count == 0) { - s->async->events |= COMEDI_CB_EOA; - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmuio_stop_intr(dev, s); - } - } - } + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) + s->async->events |= COMEDI_CB_EOA; done: spin_unlock_irqrestore(&chip->spinlock, flags); - if (oldevents != s->async->events) - comedi_event(dev, s); + comedi_handle_events(dev, s); } static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) @@ -487,8 +468,6 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) spin_lock_irqsave(&chip->spinlock, flags); chip->active = 1; - chip->stop_count = cmd->stop_arg; - /* Set up start of acquisition. */ if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmuio_inttrig_start_intr; @@ -614,7 +593,8 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) if ((i == 0 && dev->irq) || (i == 2 && devpriv->irq2)) { /* setup the interrupt subdevice */ dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; + s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL | + SDF_PACKED; s->len_chanlist = s->n_chan; s->cancel = pcmuio_cancel; s->do_cmd = pcmuio_cmd; diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 6407df0404f0..96098110b0b3 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -65,8 +65,6 @@ struct daqp_private { enum { semaphore, buffer } interrupt_mode; struct completion eos; - - int count; }; /* The DAQP communicates with the system through a 16 byte I/O window. */ @@ -194,6 +192,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) struct comedi_device *dev = dev_id; struct daqp_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; int loop_limit = 10000; int status; @@ -221,18 +220,16 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) data |= inb(dev->iobase + DAQP_FIFO) << 8; data ^= 0x8000; - comedi_buf_put(s, data); + comedi_buf_write_samples(s, &data, 1); /* If there's a limit, decrement it * and stop conversion if zero */ - if (devpriv->count > 0) { - devpriv->count--; - if (devpriv->count == 0) { - s->async->events |= COMEDI_CB_EOA; - break; - } + if (cmd->stop_src == TRIG_COUNT && + s->async->scans_done >= cmd->stop_arg) { + s->async->events |= COMEDI_CB_EOA; + break; } if ((loop_limit--) <= 0) @@ -245,9 +242,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - s->async->events |= COMEDI_CB_BLOCK; - - cfc_handle_events(dev, s); + comedi_handle_events(dev, s); } return IRQ_HANDLED; } @@ -575,12 +570,16 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) */ if (cmd->stop_src == TRIG_COUNT) { - devpriv->count = cmd->stop_arg * cmd->scan_end_arg; - threshold = 2 * devpriv->count; - while (threshold > DAQP_FIFO_SIZE * 3 / 4) - threshold /= 2; + unsigned long long nsamples; + unsigned long long nbytes; + + nsamples = (unsigned long long)cmd->stop_arg * + cmd->scan_end_arg; + nbytes = nsamples * comedi_bytes_per_sample(s); + while (nbytes > DAQP_FIFO_SIZE * 3 / 4) + nbytes /= 2; + threshold = nbytes; } else { - devpriv->count = -1; threshold = DAQP_FIFO_SIZE / 2; } @@ -736,12 +735,11 @@ static int daqp_auto_attach(struct comedi_device *dev, s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = 0x0fff; s->range_table = &range_bipolar5; s->insn_write = daqp_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -756,7 +754,7 @@ static int daqp_auto_attach(struct comedi_device *dev, s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 1; s->maxdata = 1; s->insn_bits = daqp_do_insn_bits; diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 7d4cb140959c..581aa58d9c0a 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -379,7 +379,6 @@ struct rtd_private { long ai_count; /* total transfer size (samples) */ int xfer_count; /* # to transfer data. 0->1/2FIFO */ int flags; /* flag event modes */ - DECLARE_BITMAP(chan_is_bipolar, RTD_MAX_CHANLIST); unsigned fifosz; }; @@ -438,7 +437,6 @@ static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, unsigned int chanspec, int index) { const struct rtd_boardinfo *board = dev->board_ptr; - struct rtd_private *devpriv = dev->private; unsigned int chan = CR_CHAN(chanspec); unsigned int range = CR_RANGE(chanspec); unsigned int aref = CR_AREF(chanspec); @@ -451,17 +449,14 @@ static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, /* +-5 range */ r |= 0x000; r |= (range & 0x7) << 4; - __set_bit(index, devpriv->chan_is_bipolar); } else if (range < board->range_uni10) { /* +-10 range */ r |= 0x100; r |= ((range - board->range_bip10) & 0x7) << 4; - __set_bit(index, devpriv->chan_is_bipolar); } else { /* +10 range */ r |= 0x200; r |= ((range - board->range_uni10) & 0x7) << 4; - __clear_bit(index, devpriv->chan_is_bipolar); } switch (aref) { @@ -561,6 +556,7 @@ static int rtd_ai_rinsn(struct comedi_device *dev, unsigned int *data) { struct rtd_private *devpriv = dev->private; + unsigned int range = CR_RANGE(insn->chanspec); int ret; int n; @@ -586,9 +582,11 @@ static int rtd_ai_rinsn(struct comedi_device *dev, /* read data */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); d = d >> 3; /* low 3 bits are marker lines */ - if (test_bit(0, devpriv->chan_is_bipolar)) - /* convert to comedi unsigned data */ + + /* convert bipolar data to comedi unsigned data */ + if (comedi_range_is_bipolar(s, range)) d = comedi_offset_munge(s, d); + data[n] = d & s->maxdata; } @@ -606,9 +604,12 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, int count) { struct rtd_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; int ii; for (ii = 0; ii < count; ii++) { + unsigned int range = CR_RANGE(cmd->chanlist[async->cur_chan]); unsigned short d; if (0 == devpriv->ai_count) { /* done */ @@ -618,41 +619,13 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, d = readw(devpriv->las1 + LAS1_ADC_FIFO); d = d >> 3; /* low 3 bits are marker lines */ - if (test_bit(s->async->cur_chan, devpriv->chan_is_bipolar)) - /* convert to comedi unsigned data */ - d = comedi_offset_munge(s, d); - d &= s->maxdata; - - if (!comedi_buf_put(s, d)) - return -1; - - if (devpriv->ai_count > 0) /* < 0, means read forever */ - devpriv->ai_count--; - } - return 0; -} - -/* - unknown amout of data is waiting in fifo. -*/ -static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct rtd_private *devpriv = dev->private; - - while (readl(dev->mmio + LAS0_ADC) & FS_ADC_NOT_EMPTY) { - unsigned short d = readw(devpriv->las1 + LAS1_ADC_FIFO); - - if (0 == devpriv->ai_count) { /* done */ - continue; /* read rest */ - } - d = d >> 3; /* low 3 bits are marker lines */ - if (test_bit(s->async->cur_chan, devpriv->chan_is_bipolar)) - /* convert to comedi unsigned data */ + /* convert bipolar data to comedi unsigned data */ + if (comedi_range_is_bipolar(s, range)) d = comedi_offset_munge(s, d); d &= s->maxdata; - if (!comedi_buf_put(s, d)) + if (!comedi_buf_write_samples(s, &d, 1)) return -1; if (devpriv->ai_count > 0) /* < 0, means read forever */ @@ -703,8 +676,6 @@ static irqreturn_t rtd_interrupt(int irq, void *d) if (0 == devpriv->ai_count) goto xfer_done; - - comedi_event(dev, s); } else if (devpriv->xfer_count > 0) { if (fifo_status & FS_ADC_NOT_EMPTY) { /* FIFO not empty */ @@ -713,8 +684,6 @@ static irqreturn_t rtd_interrupt(int irq, void *d) if (0 == devpriv->ai_count) goto xfer_done; - - comedi_event(dev, s); } } } @@ -726,28 +695,16 @@ static irqreturn_t rtd_interrupt(int irq, void *d) /* clear the interrupt */ writew(status, dev->mmio + LAS0_CLEAR); readw(dev->mmio + LAS0_CLEAR); + + comedi_handle_events(dev, s); + return IRQ_HANDLED; xfer_abort: - writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR); s->async->events |= COMEDI_CB_ERROR; - devpriv->ai_count = 0; /* stop and don't transfer any more */ - /* fall into xfer_done */ xfer_done: - /* pacer stop source: SOFTWARE */ - writel(0, dev->mmio + LAS0_PACER_STOP); - writel(0, dev->mmio + LAS0_PACER); /* stop pacer */ - writel(0, dev->mmio + LAS0_ADC_CONVERSION); - writew(0, dev->mmio + LAS0_IT); - - if (devpriv->ai_count > 0) { /* there shouldn't be anything left */ - fifo_status = readl(dev->mmio + LAS0_ADC); - ai_read_dregs(dev, s); /* read anything left in FIFO */ - } - - s->async->events |= COMEDI_CB_EOA; /* signal end to comedi */ - comedi_event(dev, s); + s->async->events |= COMEDI_CB_EOA; /* clear the interrupt */ status = readw(dev->mmio + LAS0_IT); @@ -757,6 +714,8 @@ xfer_done: fifo_status = readl(dev->mmio + LAS0_ADC); overrun = readl(dev->mmio + LAS0_OVERRUN) & 0xffff; + comedi_handle_events(dev, s); + return IRQ_HANDLED; } @@ -1083,6 +1042,7 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_count = 0; /* stop and don't transfer any more */ status = readw(dev->mmio + LAS0_IT); overrun = readl(dev->mmio + LAS0_OVERRUN) & 0xffff; + writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR); return 0; } @@ -1303,7 +1263,6 @@ static int rtd_auto_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table = &rtd_ao_range; s->insn_write = rtd_ao_winsn; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index e3d9f44cefb9..67b4b378bd01 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -313,7 +313,6 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) ? rti800_ao_ranges[it->options[7]] : &range_unknown; s->insn_write = rti800_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index c81b01c40f12..96c3974207ae 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -100,7 +100,6 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xfff; s->n_chan = 8; s->insn_write = rti802_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 75872c6aec2a..6f3e8a08e75c 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -583,7 +583,6 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = s526_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 0e7621e890c3..14932c5f3798 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -78,7 +78,6 @@ struct s626_buffer_dma { struct s626_private { uint8_t ai_cmd_running; /* ai_cmd is running */ - int ai_sample_count; /* number of samples to acquire */ unsigned int ai_sample_timer; /* time between samples in * units of the timer */ int ai_convert_count; /* conversion counter */ @@ -1480,7 +1479,6 @@ static bool s626_handle_eos_interrupt(struct comedi_device *dev) * from the final ADC of the previous poll list scan. */ uint32_t *readaddr = (uint32_t *)devpriv->ana_buf.logical_base + 1; - bool finished = false; int i; /* get the data and hand it over to comedi */ @@ -1494,36 +1492,21 @@ static bool s626_handle_eos_interrupt(struct comedi_device *dev) tempdata = s626_ai_reg_to_uint(*readaddr); readaddr++; - /* put data into read buffer */ - cfc_write_to_buffer(s, tempdata); + comedi_buf_write_samples(s, &tempdata, 1); } - /* end of scan occurs */ - async->events |= COMEDI_CB_EOS; + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_sample_count--; - if (devpriv->ai_sample_count <= 0) { - devpriv->ai_cmd_running = 0; - - /* Stop RPS program */ - s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); - - /* send end of acquisition */ - async->events |= COMEDI_CB_EOA; - - /* disable master interrupt */ - finished = true; - } - } + if (async->events & COMEDI_CB_CANCEL_MASK) + devpriv->ai_cmd_running = 0; if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT) s626_dio_set_irq(dev, cmd->scan_begin_arg); - /* tell comedi that data is there */ - comedi_event(dev, s); + comedi_handle_events(dev, s); - return finished; + return !devpriv->ai_cmd_running; } static irqreturn_t s626_irq_handler(int irq, void *d) @@ -1970,13 +1953,13 @@ static int s626_ns_to_timer(unsigned int *nanosec, unsigned int flags) switch (flags & CMDF_ROUND_MASK) { case CMDF_ROUND_NEAREST: default: - divider = (*nanosec + base / 2) / base; + divider = DIV_ROUND_CLOSEST(*nanosec, base); break; case CMDF_ROUND_DOWN: divider = (*nanosec) / base; break; case CMDF_ROUND_UP: - divider = (*nanosec + base - 1) / base; + divider = DIV_ROUND_UP(*nanosec, base); break; } @@ -2102,8 +2085,6 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) break; } - devpriv->ai_sample_count = cmd->stop_arg; - s626_reset_adc(dev, ppl); switch (cmd->start_src) { @@ -2820,7 +2801,6 @@ static int s626_auto_attach(struct comedi_device *dev, s->maxdata = 0x3fff; s->range_table = &range_bipolar10; s->insn_write = s626_ao_insn_write; - s->insn_read = comedi_readback_insn_read; ret = comedi_alloc_subdev_readback(s); if (ret) diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index 167f82418cb4..71226ee9064e 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -742,7 +742,7 @@ static int serial2002_attach(struct comedi_device *dev, /* digital output subdevice */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 0; s->maxdata = 1; s->range_table = &range_digital; @@ -760,7 +760,7 @@ static int serial2002_attach(struct comedi_device *dev, /* analog output subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 0; s->maxdata = 1; s->range_table = NULL; diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 5adbfedf780f..4737dbf8e01d 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -1,37 +1,34 @@ /* - comedi/drivers/usbdux.c - Copyright (C) 2003-2007 Bernd Porr, Bernd.Porr@f2s.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * usbdux.c + * Copyright (C) 2003-2014 Bernd Porr, mail@berndporr.me.uk + * + * 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: usbdux -Description: University of Stirling USB DAQ & INCITE Technology Limited -Devices: [ITL] USB-DUX (usbdux.o) -Author: Bernd Porr <BerndPorr@f2s.com> -Updated: 8 Dec 2008 -Status: Stable -Configuration options: - You have to upload firmware with the -i option. The - firmware is usually installed under /usr/share/usb or - /usr/local/share/usb or /lib/firmware. - -Connection scheme for the counter at the digital port: - 0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1. - The sampling rate of the counter is approximately 500Hz. - -Please note that under USB2.0 the length of the channel list determines -the max sampling rate. If you sample only one channel you get 8kHz -sampling rate. If you sample two channels you get 4kHz and so on. -*/ + * Driver: usbdux + * Description: University of Stirling USB DAQ & INCITE Technology Limited + * Devices: (ITL) USB-DUX [usbdux] + * Author: Bernd Porr <mail@berndporr.me.uk> + * Updated: 10 Oct 2014 + * Status: Stable + * Connection scheme for the counter at the digital port: + * 0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1. + * The sampling rate of the counter is approximately 500Hz. + * + * Note that under USB2.0 the length of the channel list determines + * the max sampling rate. If you sample only one channel you get 8kHz + * sampling rate. If you sample two channels you get 4kHz and so on. + */ + /* * I must give credit here to Chris Baugher who * wrote the driver for AT-MIO-16d. I used some parts of this @@ -205,9 +202,6 @@ struct usbdux_private { unsigned int ao_cmd_running:1; unsigned int pwm_cmd_running:1; - /* number of samples to acquire */ - int ai_sample_count; - int ao_sample_count; /* time between samples in units of the timer */ unsigned int ai_timer; unsigned int ao_timer; @@ -253,128 +247,107 @@ static int usbdux_ai_cancel(struct comedi_device *dev, return 0; } -/* analogue IN - interrupt service routine */ +static void usbduxsub_ai_handle_urb(struct comedi_device *dev, + struct comedi_subdevice *s, + struct urb *urb) +{ + struct usbdux_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + int ret; + int i; + + devpriv->ai_counter--; + if (devpriv->ai_counter == 0) { + devpriv->ai_counter = devpriv->ai_timer; + + /* get the data from the USB bus and hand it over to comedi */ + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int range = CR_RANGE(cmd->chanlist[i]); + uint16_t val = le16_to_cpu(devpriv->in_buf[i]); + + /* bipolar data is two's-complement */ + if (comedi_range_is_bipolar(s, range)) + val ^= ((s->maxdata + 1) >> 1); + + /* transfer data */ + if (!comedi_buf_write_samples(s, &val, 1)) + return; + } + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; + } + + /* if command is still running, resubmit urb */ + if (!(async->events & COMEDI_CB_CANCEL_MASK)) { + urb->dev = comedi_to_usb_dev(dev); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(dev->class_dev, + "urb resubmit failed in int-context! err=%d\n", + ret); + if (ret == -EL2NSYNC) + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler!\n"); + async->events |= COMEDI_CB_ERROR; + } + } +} + static void usbduxsub_ai_isoc_irq(struct urb *urb) { struct comedi_device *dev = urb->context; struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; struct usbdux_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - int i, err; - /* first we test if something unusual has just happened */ + /* exit if not running a command, do not resubmit urb */ + if (!devpriv->ai_cmd_running) + return; + switch (urb->status) { case 0: /* copy the result in the transfer buffer */ memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); + usbduxsub_ai_handle_urb(dev, s, urb); break; + case -EILSEQ: - /* error in the ISOchronous data */ - /* we don't copy the data into the transfer buffer */ - /* and recycle the last data byte */ + /* + * error in the ISOchronous data + * we don't copy the data into the transfer buffer + * and recycle the last data byte + */ dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); + usbduxsub_ai_handle_urb(dev, s, urb); break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: - /* happens after an unlink command */ - if (devpriv->ai_cmd_running) { - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(dev, s); - /* stop the transfer w/o unlink */ - usbdux_ai_stop(dev, 0); - } - return; + /* after an unlink command, unplug, ... etc */ + async->events |= COMEDI_CB_ERROR; + break; default: - /* a real error on the bus */ - /* pass error to comedi if we are really running a command */ - if (devpriv->ai_cmd_running) { - dev_err(dev->class_dev, - "Non-zero urb status received in ai intr context: %d\n", - urb->status); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(dev, s); - /* don't do an unlink here */ - usbdux_ai_stop(dev, 0); - } - return; + /* a real error */ + dev_err(dev->class_dev, + "Non-zero urb status received in ai intr context: %d\n", + urb->status); + async->events |= COMEDI_CB_ERROR; + break; } /* - * at this point we are reasonably sure that nothing dodgy has happened - * are we running a command? + * comedi_handle_events() cannot be used in this driver. The (*cancel) + * operation would unlink the urb. */ - if (unlikely(!devpriv->ai_cmd_running)) { - /* - * not running a command, do not continue execution if no - * asynchronous command is running in particular not resubmit - */ - return; - } - - urb->dev = comedi_to_usb_dev(dev); - - /* resubmit the urb */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err < 0)) { - dev_err(dev->class_dev, - "urb resubmit failed in int-context! err=%d\n", err); - if (err == -EL2NSYNC) - dev_err(dev->class_dev, - "buggy USB host controller or bug in IRQ handler!\n"); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(dev, s); - /* don't do an unlink here */ + if (async->events & COMEDI_CB_CANCEL_MASK) usbdux_ai_stop(dev, 0); - return; - } - - devpriv->ai_counter--; - if (likely(devpriv->ai_counter > 0)) - return; - - /* timer zero, transfer measurements to comedi */ - devpriv->ai_counter = devpriv->ai_timer; - - /* test, if we transmit only a fixed number of samples */ - if (cmd->stop_src == TRIG_COUNT) { - /* not continuous, fixed number of samples */ - devpriv->ai_sample_count--; - /* all samples received? */ - if (devpriv->ai_sample_count < 0) { - /* prevent a resubmit next time */ - usbdux_ai_stop(dev, 0); - /* say comedi that the acquistion is over */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } - } - /* get the data from the USB bus and hand it over to comedi */ - for (i = 0; i < cmd->chanlist_len; i++) { - unsigned int range = CR_RANGE(cmd->chanlist[i]); - uint16_t val = le16_to_cpu(devpriv->in_buf[i]); - - /* bipolar data is two's-complement */ - if (comedi_range_is_bipolar(s, range)) - val ^= ((s->maxdata + 1) >> 1); - /* transfer data */ - err = comedi_buf_put(s, val); - if (unlikely(err == 0)) { - /* buffer overflow */ - usbdux_ai_stop(dev, 0); - return; - } - } - /* tell comedi that data is there */ - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); } @@ -402,71 +375,25 @@ static int usbdux_ao_cancel(struct comedi_device *dev, return 0; } -static void usbduxsub_ao_isoc_irq(struct urb *urb) +static void usbduxsub_ao_handle_urb(struct comedi_device *dev, + struct comedi_subdevice *s, + 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; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; uint8_t *datap; int ret; int i; - switch (urb->status) { - case 0: - /* success */ - break; - - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - case -ECONNABORTED: - /* after an unlink command, unplug, ... etc */ - /* no unlink needed here. Already shutting down. */ - if (devpriv->ao_cmd_running) { - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - usbdux_ao_stop(dev, 0); - } - return; - - default: - /* a real error */ - if (devpriv->ao_cmd_running) { - dev_err(dev->class_dev, - "Non-zero urb status received in ao intr context: %d\n", - urb->status); - s->async->events |= COMEDI_CB_ERROR; - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - /* we do an unlink if we are in the high speed mode */ - usbdux_ao_stop(dev, 0); - } - return; - } - - /* are we actually running? */ - if (!devpriv->ao_cmd_running) - return; - - /* normal operation: executing a command in this subdevice */ devpriv->ao_counter--; - if ((int)devpriv->ao_counter <= 0) { - /* timer zero */ + if (devpriv->ao_counter == 0) { devpriv->ao_counter = devpriv->ao_timer; - /* handle non continous acquisition */ - if (cmd->stop_src == TRIG_COUNT) { - /* fixed number of samples */ - devpriv->ao_sample_count--; - if (devpriv->ao_sample_count < 0) { - /* all samples transmitted */ - usbdux_ao_stop(dev, 0); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - /* no resubmit of the urb */ - return; - } + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { + async->events |= COMEDI_CB_EOA; + return; } /* transmit data to the USB bus */ @@ -476,26 +403,25 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned short val; - ret = comedi_buf_get(s, &val); - if (ret < 0) { + if (!comedi_buf_read_samples(s, &val, 1)) { dev_err(dev->class_dev, "buffer underflow\n"); - s->async->events |= (COMEDI_CB_EOA | - COMEDI_CB_OVERFLOW); + async->events |= COMEDI_CB_OVERFLOW; + return; } + /* pointer to the DA */ *datap++ = val & 0xff; *datap++ = (val >> 8) & 0xff; *datap++ = chan << 6; s->readback[chan] = val; - - s->async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); } } - urb->transfer_buffer_length = SIZEOUTBUF; - urb->dev = comedi_to_usb_dev(dev); - urb->status = 0; - if (devpriv->ao_cmd_running) { + + /* if command is still running, resubmit urb for BULK transfer */ + if (!(async->events & COMEDI_CB_CANCEL_MASK)) { + urb->transfer_buffer_length = SIZEOUTBUF; + urb->dev = comedi_to_usb_dev(dev); + urb->status = 0; if (devpriv->high_speed) urb->interval = 8; /* uframes */ else @@ -512,16 +438,54 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) if (ret == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handling!\n"); - - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(dev, s); - /* don't do an unlink here */ - usbdux_ao_stop(dev, 0); + async->events |= COMEDI_CB_ERROR; } } } +static void usbduxsub_ao_isoc_irq(struct urb *urb) +{ + struct comedi_device *dev = urb->context; + struct comedi_subdevice *s = dev->write_subdev; + struct comedi_async *async = s->async; + struct usbdux_private *devpriv = dev->private; + + /* exit if not running a command, do not resubmit urb */ + if (!devpriv->ao_cmd_running) + return; + + switch (urb->status) { + case 0: + usbduxsub_ao_handle_urb(dev, s, urb); + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -ECONNABORTED: + /* after an unlink command, unplug, ... etc */ + async->events |= COMEDI_CB_ERROR; + break; + + default: + /* a real error */ + dev_err(dev->class_dev, + "Non-zero urb status received in ao intr context: %d\n", + urb->status); + async->events |= COMEDI_CB_ERROR; + break; + } + + /* + * comedi_handle_events() cannot be used in this driver. The (*cancel) + * operation would unlink the urb. + */ + if (async->events & COMEDI_CB_CANCEL_MASK) + usbdux_ao_stop(dev, 0); + + comedi_event(dev, s); +} + static int usbdux_submit_urbs(struct comedi_device *dev, struct urb **urbs, int num_urbs, int input_urb) @@ -725,9 +689,6 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (devpriv->ai_cmd_running) goto ai_cmd_exit; - /* set current channel of the running acquisition to zero */ - s->async->cur_chan = 0; - devpriv->dux_commands[1] = len; for (i = 0; i < len; ++i) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); @@ -765,14 +726,6 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_counter = devpriv->ai_timer; - if (cmd->stop_src == TRIG_COUNT) { - /* data arrives as one packet */ - devpriv->ai_sample_count = cmd->stop_arg; - } else { - /* continous acquisition */ - devpriv->ai_sample_count = 0; - } - if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ devpriv->ai_cmd_running = 1; @@ -1023,9 +976,6 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (devpriv->ao_cmd_running) goto ao_cmd_exit; - /* set current channel of the running acquisition to zero */ - s->async->cur_chan = 0; - /* we count in steps of 1ms (125us) */ /* 125us mode not used yet */ if (0) { /* (devpriv->high_speed) */ @@ -1044,24 +994,6 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ao_counter = devpriv->ao_timer; - if (cmd->stop_src == TRIG_COUNT) { - /* not continuous */ - /* counter */ - /* high speed also scans everything at once */ - if (0) { /* (devpriv->high_speed) */ - devpriv->ao_sample_count = cmd->stop_arg * - cmd->scan_end_arg; - } else { - /* there's no scan as the scan has been */ - /* perf inside the FX2 */ - /* data arrives as one packet */ - devpriv->ao_sample_count = cmd->stop_arg; - } - } else { - /* continous acquisition */ - devpriv->ao_sample_count = 0; - } - if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ devpriv->ao_cmd_running = 1; diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index f85818dd5e11..ddc4cb9d5ed4 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Bernd Porr, Bernd.Porr@f2s.com + * Copyright (C) 2004-2014 Bernd Porr, mail@berndporr.me.uk * * 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 @@ -13,6 +13,15 @@ */ /* + * Driver: usbduxfast + * Description: University of Stirling USB DAQ & INCITE Technology Limited + * Devices: (ITL) USB-DUX [usbduxfast] + * Author: Bernd Porr <mail@berndporr.me.uk> + * Updated: 10 Oct 2014 + * Status: stable + */ + +/* * I must give credit here to Chris Baugher who * wrote the driver for AT-MIO-16d. I used some parts of this * driver. I also must give credits to David Brownell @@ -152,7 +161,6 @@ struct usbduxfast_private { uint8_t *duxbuf; int8_t *inbuf; short int ai_cmd_running; /* asynchronous command is running */ - long int ai_sample_count; /* number of samples to acquire */ int ignore; /* counter which ignores the first buffers */ struct semaphore sem; @@ -227,114 +235,82 @@ static int usbduxfast_ai_cancel(struct comedi_device *dev, return ret; } -/* - * analogue IN - * interrupt service routine - */ +static void usbduxfast_ai_handle_urb(struct comedi_device *dev, + struct comedi_subdevice *s, + struct urb *urb) +{ + struct usbduxfast_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + int ret; + + if (devpriv->ignore) { + devpriv->ignore--; + } else { + unsigned int nsamples; + + nsamples = comedi_bytes_to_samples(s, urb->actual_length); + nsamples = comedi_nsamples_left(s, nsamples); + comedi_buf_write_samples(s, urb->transfer_buffer, nsamples); + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; + } + + /* if command is still running, resubmit urb for BULK transfer */ + if (!(async->events & COMEDI_CB_CANCEL_MASK)) { + urb->dev = comedi_to_usb_dev(dev); + urb->status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(dev->class_dev, "urb resubm failed: %d", ret); + async->events |= COMEDI_CB_ERROR; + } + } +} + 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; - /* are we running a command? */ - if (unlikely(!devpriv->ai_cmd_running)) { - /* - * not running a command - * do not continue execution if no asynchronous command - * is running in particular not resubmit - */ + /* exit if not running a command, do not resubmit urb */ + if (!devpriv->ai_cmd_running) return; - } - /* first we test if something unusual has just happened */ switch (urb->status) { case 0: + usbduxfast_ai_handle_urb(dev, s, urb); break; - /* - * happens after an unlink command or when the device - * is plugged out - */ case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: - /* tell this comedi */ - async->events |= COMEDI_CB_EOA; + /* after an unlink command, unplug, ... etc */ async->events |= COMEDI_CB_ERROR; - comedi_event(dev, s); - /* stop the transfer w/o unlink */ - usbduxfast_ai_stop(dev, 0); - return; + break; default: + /* a real error */ dev_err(dev->class_dev, "non-zero urb status received in ai intr context: %d\n", urb->status); - async->events |= COMEDI_CB_EOA; async->events |= COMEDI_CB_ERROR; - comedi_event(dev, s); - usbduxfast_ai_stop(dev, 0); - return; - } - - if (!devpriv->ignore) { - 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)) { - unsigned int num_bytes; - - /* partial sample received */ - num_bytes = devpriv->ai_sample_count * - sizeof(uint16_t); - cfc_write_array_to_buffer(s, - urb->transfer_buffer, - num_bytes); - usbduxfast_ai_stop(dev, 0); - /* tell comedi that the acquistion is over */ - async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } - devpriv->ai_sample_count -= n; - } - /* write the full buffer to comedi */ - err = cfc_write_array_to_buffer(s, urb->transfer_buffer, - urb->actual_length); - if (unlikely(err == 0)) { - /* buffer overflow */ - usbduxfast_ai_stop(dev, 0); - return; - } - - /* tell comedi that data is there */ - comedi_event(dev, s); - } else { - /* ignore this packet */ - devpriv->ignore--; + break; } /* - * command is still running - * resubmit urb for BULK transfer + * comedi_handle_events() cannot be used in this driver. The (*cancel) + * operation would unlink the urb. */ - urb->dev = usb; - urb->status = 0; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - dev_err(dev->class_dev, - "urb resubm failed: %d", err); - async->events |= COMEDI_CB_EOA; - async->events |= COMEDI_CB_ERROR; - comedi_event(dev, s); + if (async->events & COMEDI_CB_CANCEL_MASK) usbduxfast_ai_stop(dev, 0); - } + + comedi_event(dev, s); } static int usbduxfast_submit_urb(struct comedi_device *dev) @@ -499,8 +475,6 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, up(&devpriv->sem); return -EBUSY; } - /* set current channel of the running acquisition to zero */ - s->async->cur_chan = 0; /* * ignore the first buffers from the device if there @@ -810,11 +784,6 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, return result; } - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg; - else /* TRIG_NONE */ - devpriv->ai_sample_count = 0; - if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) { /* enable this acquisition operation */ devpriv->ai_cmd_running = 1; diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index ebd68e365bac..dc19435b6520 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -1,6 +1,6 @@ /* * usbduxsigma.c - * Copyright (C) 2011 Bernd Porr, Bernd.Porr@f2s.com + * Copyright (C) 2011-2014 Bernd Porr, mail@berndporr.me.uk * * 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 @@ -17,9 +17,9 @@ * Driver: usbduxsigma * Description: University of Stirling USB DAQ & INCITE Technology Limited * Devices: (ITL) USB-DUX [usbduxsigma] - * Author: Bernd Porr <BerndPorr@f2s.com> - * Updated: 8 Nov 2011 - * Status: testing + * Author: Bernd Porr <mail@berndporr.me.uk> + * Updated: 10 Oct 2014 + * Status: stable */ /* @@ -164,9 +164,6 @@ struct usbduxsigma_private { unsigned ao_cmd_running:1; unsigned pwm_cmd_running:1; - /* number of samples to acquire */ - int ai_sample_count; - int ao_sample_count; /* time between samples in units of the timer */ unsigned int ai_timer; unsigned int ao_timer; @@ -211,23 +208,75 @@ static int usbduxsigma_ai_cancel(struct comedi_device *dev, return 0; } -static void usbduxsigma_ai_urb_complete(struct urb *urb) +static void usbduxsigma_ai_handle_urb(struct comedi_device *dev, + struct comedi_subdevice *s, + 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; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; unsigned int dio_state; uint32_t val; int ret; int i; - /* first we test if something unusual has just happened */ + devpriv->ai_counter--; + if (devpriv->ai_counter == 0) { + devpriv->ai_counter = devpriv->ai_timer; + + /* get the state of the dio pins to allow external trigger */ + dio_state = be32_to_cpu(devpriv->in_buf[0]); + + /* get the data from the USB bus and hand it over to comedi */ + for (i = 0; i < cmd->chanlist_len; i++) { + /* transfer data, note first byte is the DIO state */ + val = be32_to_cpu(devpriv->in_buf[i+1]); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ + + if (!comedi_buf_write_samples(s, &val, 1)) + return; + } + + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; + } + + /* if command is still running, resubmit urb */ + if (!(async->events & COMEDI_CB_CANCEL_MASK)) { + urb->dev = comedi_to_usb_dev(dev); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(dev->class_dev, + "%s: urb resubmit failed (%d)\n", + __func__, ret); + if (ret == -EL2NSYNC) + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler\n"); + async->events |= COMEDI_CB_ERROR; + } + } +} + +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_async *async = s->async; + + /* exit if not running a command, do not resubmit urb */ + if (!devpriv->ai_cmd_running) + return; + switch (urb->status) { case 0: /* copy the result in the transfer buffer */ memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); + usbduxsigma_ai_handle_urb(dev, s, urb); break; + case -EILSEQ: /* * error in the ISOchronous data @@ -235,7 +284,7 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb) * and recycle the last data byte */ dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); - + usbduxsigma_ai_handle_urb(dev, s, urb); break; case -ECONNRESET: @@ -243,86 +292,24 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb) case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ - if (devpriv->ai_cmd_running) { - usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ - /* we are still running a command, tell comedi */ - s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); - comedi_event(dev, s); - } - return; + async->events |= COMEDI_CB_ERROR; + break; default: - /* - * a real error on the bus - * pass error to comedi if we are really running a command - */ - if (devpriv->ai_cmd_running) { - dev_err(dev->class_dev, - "%s: non-zero urb status (%d)\n", - __func__, urb->status); - usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ - s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); - comedi_event(dev, s); - } - return; - } - - if (unlikely(!devpriv->ai_cmd_running)) - return; - - urb->dev = comedi_to_usb_dev(dev); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(ret < 0)) { - dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", - __func__, ret); - if (ret == -EL2NSYNC) - dev_err(dev->class_dev, - "buggy USB host controller or bug in IRQ handler\n"); - usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ - s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); - comedi_event(dev, s); - return; - } - - /* get the state of the dio pins to allow external trigger */ - dio_state = be32_to_cpu(devpriv->in_buf[0]); - - devpriv->ai_counter--; - if (likely(devpriv->ai_counter > 0)) - return; - - /* timer zero, transfer measurements to comedi */ - devpriv->ai_counter = devpriv->ai_timer; - - if (cmd->stop_src == TRIG_COUNT) { - /* not continuous, fixed number of samples */ - devpriv->ai_sample_count--; - if (devpriv->ai_sample_count < 0) { - usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ - /* acquistion is over, tell comedi */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } + /* a real error */ + dev_err(dev->class_dev, "%s: non-zero urb status (%d)\n", + __func__, urb->status); + async->events |= COMEDI_CB_ERROR; + break; } - /* get the data from the USB bus and hand it over to comedi */ - for (i = 0; i < cmd->chanlist_len; i++) { - /* transfer data, note first byte is the DIO state */ - val = be32_to_cpu(devpriv->in_buf[i+1]); - val &= 0x00ffffff; /* strip status byte */ - val ^= 0x00800000; /* convert to unsigned */ + /* + * comedi_handle_events() cannot be used in this driver. The (*cancel) + * operation would unlink the urb. + */ + if (async->events & COMEDI_CB_CANCEL_MASK) + usbduxsigma_ai_stop(dev, 0); - ret = cfc_write_array_to_buffer(s, &val, sizeof(uint32_t)); - if (unlikely(ret == 0)) { - /* buffer overflow */ - usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ - return; - } - } - /* tell comedi that data is there */ - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); comedi_event(dev, s); } @@ -349,64 +336,25 @@ static int usbduxsigma_ao_cancel(struct comedi_device *dev, return 0; } -static void usbduxsigma_ao_urb_complete(struct urb *urb) +static void usbduxsigma_ao_handle_urb(struct comedi_device *dev, + struct comedi_subdevice *s, + 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; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; uint8_t *datap; int ret; int i; - switch (urb->status) { - case 0: - /* success */ - break; - - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - case -ECONNABORTED: - /* happens after an unlink command */ - if (devpriv->ao_cmd_running) { - usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - } - return; - - default: - /* a real error */ - if (devpriv->ao_cmd_running) { - dev_err(dev->class_dev, - "%s: non-zero urb status (%d)\n", - __func__, urb->status); - usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ - s->async->events |= (COMEDI_CB_ERROR | COMEDI_CB_EOA); - comedi_event(dev, s); - } - return; - } - - if (!devpriv->ao_cmd_running) - return; - devpriv->ao_counter--; - if ((int)devpriv->ao_counter <= 0) { - /* timer zero, transfer from comedi */ + if (devpriv->ao_counter == 0) { devpriv->ao_counter = devpriv->ao_timer; - if (cmd->stop_src == TRIG_COUNT) { - /* not continuous, fixed number of samples */ - devpriv->ao_sample_count--; - if (devpriv->ao_sample_count < 0) { - usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ - /* acquistion is over, tell comedi */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) { + async->events |= COMEDI_CB_EOA; + return; } /* transmit data to the USB bus */ @@ -416,46 +364,86 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb) unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned short val; - ret = comedi_buf_get(s, &val); - if (ret < 0) { + if (!comedi_buf_read_samples(s, &val, 1)) { dev_err(dev->class_dev, "buffer underflow\n"); - s->async->events |= (COMEDI_CB_EOA | - COMEDI_CB_OVERFLOW); + async->events |= COMEDI_CB_OVERFLOW; + return; } + *datap++ = val; *datap++ = chan; s->readback[chan] = val; - - s->async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); } } - urb->transfer_buffer_length = SIZEOUTBUF; - urb->dev = comedi_to_usb_dev(dev); - urb->status = 0; - if (devpriv->high_speed) - urb->interval = 8; /* uframes */ - else - urb->interval = 1; /* frames */ - urb->number_of_packets = 1; - urb->iso_frame_desc[0].offset = 0; - urb->iso_frame_desc[0].length = SIZEOUTBUF; - urb->iso_frame_desc[0].status = 0; - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - dev_err(dev->class_dev, - "%s: urb resubmit failed (%d)\n", - __func__, ret); - if (ret == -EL2NSYNC) + /* if command is still running, resubmit urb */ + if (!(async->events & COMEDI_CB_CANCEL_MASK)) { + urb->transfer_buffer_length = SIZEOUTBUF; + urb->dev = comedi_to_usb_dev(dev); + urb->status = 0; + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ + urb->number_of_packets = 1; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEOUTBUF; + urb->iso_frame_desc[0].status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { dev_err(dev->class_dev, - "buggy USB host controller or bug in IRQ handler\n"); - usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ - s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); - comedi_event(dev, s); + "%s: urb resubmit failed (%d)\n", + __func__, ret); + if (ret == -EL2NSYNC) + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler\n"); + async->events |= COMEDI_CB_ERROR; + } } } +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_async *async = s->async; + + /* exit if not running a command, do not resubmit urb */ + if (!devpriv->ao_cmd_running) + return; + + switch (urb->status) { + case 0: + usbduxsigma_ao_handle_urb(dev, s, urb); + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -ECONNABORTED: + /* happens after an unlink command */ + async->events |= COMEDI_CB_ERROR; + break; + + default: + /* a real error */ + dev_err(dev->class_dev, "%s: non-zero urb status (%d)\n", + __func__, urb->status); + async->events |= COMEDI_CB_ERROR; + break; + } + + /* + * comedi_handle_events() cannot be used in this driver. The (*cancel) + * operation would unlink the urb. + */ + if (async->events & COMEDI_CB_CANCEL_MASK) + usbduxsigma_ao_stop(dev, 0); + + comedi_event(dev, s); +} + static int usbduxsigma_submit_urbs(struct comedi_device *dev, struct urb **urbs, int num_urbs, int input_urb) @@ -584,14 +572,6 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, if (devpriv->ai_timer < 1) err |= -EINVAL; - if (cmd->stop_src == TRIG_COUNT) { - /* data arrives as one packet */ - devpriv->ai_sample_count = cmd->stop_arg; - } else { - /* continuous acquisition */ - devpriv->ai_sample_count = 0; - } - if (err) return 4; @@ -692,8 +672,6 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, down(&devpriv->sem); - /* set current channel of the running acquisition to zero */ - s->async->cur_chan = 0; for (i = 0; i < len; i++) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); @@ -957,25 +935,6 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, if (devpriv->ao_timer < 1) err |= -EINVAL; - if (cmd->stop_src == TRIG_COUNT) { - /* not continuous, use counter */ - if (high_speed) { - /* high speed also scans everything at once */ - devpriv->ao_sample_count = cmd->stop_arg * - cmd->scan_end_arg; - } else { - /* - * There's no scan as the scan has been - * handled inside the FX2. Data arrives as - * one packet. - */ - devpriv->ao_sample_count = cmd->stop_arg; - } - } else { - /* continuous acquisition */ - devpriv->ao_sample_count = 0; - } - if (err) return 4; @@ -991,9 +950,6 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, down(&devpriv->sem); - /* set current channel of the running acquisition to zero */ - s->async->cur_chan = 0; - devpriv->ao_counter = devpriv->ao_timer; if (cmd->start_src == TRIG_NOW) { diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 71003416edcf..a19a56ee0eef 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -797,7 +797,7 @@ static int vmk80xx_init_subdevices(struct comedi_device *dev) /* Analog output subdevice */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; s->n_chan = boardinfo->ao_nchans; s->maxdata = 0x00ff; s->range_table = boardinfo->range; @@ -819,7 +819,7 @@ static int vmk80xx_init_subdevices(struct comedi_device *dev) /* Digital output subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 8; s->maxdata = 1; s->range_table = &range_digital; @@ -834,7 +834,7 @@ static int vmk80xx_init_subdevices(struct comedi_device *dev) s->insn_read = vmk80xx_cnt_insn_read; s->insn_config = vmk80xx_cnt_insn_config; if (devpriv->model == VMK8055_MODEL) { - s->subdev_flags |= SDF_WRITEABLE; + s->subdev_flags |= SDF_WRITABLE; s->insn_write = vmk80xx_cnt_insn_write; } @@ -842,7 +842,7 @@ static int vmk80xx_init_subdevices(struct comedi_device *dev) if (devpriv->model == VMK8061_MODEL) { s = &dev->subdevices[5]; s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = boardinfo->pwm_nchans; s->maxdata = boardinfo->pwm_maxdata; s->insn_read = vmk80xx_pwm_insn_read; diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index b6849545b810..9a1dc56f21d1 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -97,39 +97,6 @@ int do_rangeinfo_ioctl(struct comedi_device *dev, return 0; } -static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec) -{ - unsigned int aref; - - /* disable reporting invalid arefs... maybe someday */ - return 0; - - aref = CR_AREF(chanspec); - switch (aref) { - case AREF_DIFF: - if (s->subdev_flags & SDF_DIFF) - return 0; - break; - case AREF_COMMON: - if (s->subdev_flags & SDF_COMMON) - return 0; - break; - case AREF_GROUND: - if (s->subdev_flags & SDF_GROUND) - return 0; - break; - case AREF_OTHER: - if (s->subdev_flags & SDF_OTHER) - return 0; - break; - default: - break; - } - dev_dbg(s->device->class_dev, "subdevice does not support aref %i", - aref); - return 1; -} - /** * comedi_check_chanlist() - Validate each element in a chanlist. * @s: comedi_subdevice struct @@ -153,8 +120,7 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n, else range_len = 0; if (chan >= s->n_chan || - CR_RANGE(chanspec) >= range_len || - aref_invalid(s, chanspec)) { + CR_RANGE(chanspec) >= range_len) { dev_warn(dev->class_dev, "bad chanlist[%d]=0x%08x chan=%d range length=%d\n", i, chanspec, chan, range_len); |