From b4b7ff4b08e691656c9d77c758fc355833128ac0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 20 Jan 2016 14:01:31 -0300 Subject: Linux-libre 4.4-gnu --- drivers/staging/comedi/Kconfig | 10 +- drivers/staging/comedi/comedi_buf.c | 125 ++- drivers/staging/comedi/comedi_fops.c | 180 +-- drivers/staging/comedi/comedi_internal.h | 1 + drivers/staging/comedi/comedi_pci.c | 108 +- drivers/staging/comedi/comedi_pcmcia.c | 104 +- drivers/staging/comedi/comedi_usb.c | 75 +- drivers/staging/comedi/comedidev.h | 635 +++++++++-- drivers/staging/comedi/drivers.c | 407 +++++-- drivers/staging/comedi/drivers/8255.h | 12 +- drivers/staging/comedi/drivers/8255_pci.c | 4 +- drivers/staging/comedi/drivers/Makefile | 1 - drivers/staging/comedi/drivers/addi_apci_1032.c | 7 +- drivers/staging/comedi/drivers/addi_apci_2032.c | 16 +- drivers/staging/comedi/drivers/addi_apci_3120.c | 59 +- drivers/staging/comedi/drivers/addi_apci_3xxx.c | 6 +- drivers/staging/comedi/drivers/adl_pci6208.c | 2 +- drivers/staging/comedi/drivers/adl_pci9111.c | 171 ++- drivers/staging/comedi/drivers/adl_pci9118.c | 289 +++-- drivers/staging/comedi/drivers/adq12b.c | 136 +-- drivers/staging/comedi/drivers/adv_pci1710.c | 304 +++-- drivers/staging/comedi/drivers/adv_pci1723.c | 33 +- drivers/staging/comedi/drivers/adv_pci1724.c | 15 +- drivers/staging/comedi/drivers/aio_aio12_8.c | 201 ++-- drivers/staging/comedi/drivers/amplc_pci230.c | 2 +- drivers/staging/comedi/drivers/cb_das16_cs.c | 284 +++-- drivers/staging/comedi/drivers/cb_pcidas.c | 1175 +++++++++----------- drivers/staging/comedi/drivers/comedi_test.c | 565 +++++++--- drivers/staging/comedi/drivers/daqboard2000.c | 8 +- drivers/staging/comedi/drivers/dt3000.c | 466 ++++---- drivers/staging/comedi/drivers/dt9812.c | 66 +- drivers/staging/comedi/drivers/fl512.c | 2 +- drivers/staging/comedi/drivers/gsc_hpdi.c | 28 +- drivers/staging/comedi/drivers/icp_multi.c | 517 +++------ drivers/staging/comedi/drivers/ii_pci20kc.c | 84 +- drivers/staging/comedi/drivers/jr3_pci.c | 6 +- drivers/staging/comedi/drivers/ke_counter.c | 7 +- drivers/staging/comedi/drivers/me_daq.c | 315 +++--- drivers/staging/comedi/drivers/mf6x4.c | 137 ++- drivers/staging/comedi/drivers/mpc624.c | 411 ++++--- drivers/staging/comedi/drivers/multiq3.c | 358 +++--- drivers/staging/comedi/drivers/ni_tio.c | 6 +- drivers/staging/comedi/drivers/ni_tiocmd.c | 6 - drivers/staging/comedi/drivers/ni_usb6501.c | 16 +- drivers/staging/comedi/drivers/pcl711.c | 19 +- drivers/staging/comedi/drivers/pcl812.c | 186 ++-- drivers/staging/comedi/drivers/pcl816.c | 109 +- drivers/staging/comedi/drivers/pcl818.c | 40 +- drivers/staging/comedi/drivers/pcm3724.c | 112 +- drivers/staging/comedi/drivers/quatech_daqp_cs.c | 684 ++++++------ drivers/staging/comedi/drivers/rtd520.c | 369 +++--- drivers/staging/comedi/drivers/rti800.c | 28 +- drivers/staging/comedi/drivers/s526.c | 560 +++++----- drivers/staging/comedi/drivers/serial2002.c | 51 +- drivers/staging/comedi/drivers/ssv_dnp.c | 57 +- drivers/staging/comedi/drivers/unioxx5.c | 506 --------- drivers/staging/comedi/drivers/usbdux.c | 164 ++- drivers/staging/comedi/drivers/usbduxfast.c | 310 ++---- drivers/staging/comedi/drivers/usbduxsigma.c | 142 ++- drivers/staging/comedi/drivers/vmk80xx.c | 127 +-- .../staging/comedi/kcomedilib/kcomedilib_main.c | 32 +- 61 files changed, 5541 insertions(+), 5315 deletions(-) delete mode 100644 drivers/staging/comedi/drivers/unioxx5.c (limited to 'drivers/staging/comedi') diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 57e71f9f1..ac0f01007 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -400,14 +400,6 @@ config COMEDI_DMM32AT To compile this driver as a module, choose M here: the module will be called dmm32at. -config COMEDI_UNIOXX5 - tristate "Fastwel UNIOxx-5 analog and digital io board support" - ---help--- - Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards - - To compile this driver as a module, choose M here: the module will be - called unioxx5. - config COMEDI_FL512 tristate "FL512 ISA card support" ---help--- @@ -418,6 +410,7 @@ config COMEDI_FL512 config COMEDI_AIO_AIO12_8 tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" + select COMEDI_8254 select COMEDI_8255 ---help--- Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board @@ -1072,6 +1065,7 @@ config COMEDI_NI_PCIMIO config COMEDI_RTD520 tristate "Real Time Devices PCI4520/DM7520 support" + select COMEDI_8254 ---help--- Enable support for Real Time Devices PCI4520/DM7520 diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index 19e7b229d..90c28016c 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -245,7 +245,7 @@ void comedi_buf_reset(struct comedi_subdevice *s) async->events = 0; } -static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) +static unsigned int comedi_buf_write_n_unalloc(struct comedi_subdevice *s) { struct comedi_async *async = s->async; unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; @@ -253,15 +253,33 @@ static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) return free_end - async->buf_write_alloc_count; } -/* allocates chunk for the writer from free buffer space */ +unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; + + return free_end - async->buf_write_count; +} + +/** + * comedi_buf_write_alloc() - Reserve buffer space for writing + * @s: COMEDI subdevice. + * @nbytes: Maximum space to reserve in bytes. + * + * Reserve up to @nbytes bytes of space to be written in the COMEDI acquisition + * data buffer associated with the subdevice. The amount reserved is limited + * by the space available. + * + * Return: The amount of space reserved in bytes. + */ 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); + unsigned int unalloc = comedi_buf_write_n_unalloc(s); - if (nbytes > available) - nbytes = available; + if (nbytes > unalloc) + nbytes = unalloc; async->buf_write_alloc_count += nbytes; @@ -329,7 +347,21 @@ unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s) return async->buf_write_alloc_count - async->buf_write_count; } -/* transfers a chunk from writer to filled buffer space */ +/** + * comedi_buf_write_free() - Free buffer space after it is written + * @s: COMEDI subdevice. + * @nbytes: Maximum space to free in bytes. + * + * Free up to @nbytes bytes of space previously reserved for writing in the + * COMEDI acquisition data buffer associated with the subdevice. The amount of + * space freed is limited to the amount that was reserved. The freed space is + * assumed to have been filled with sample data by the writer. + * + * If the samples in the freed space need to be "munged", do so here. The + * freed space becomes available for allocation by the reader. + * + * Return: The amount of space freed in bytes. + */ unsigned int comedi_buf_write_free(struct comedi_subdevice *s, unsigned int nbytes) { @@ -349,6 +381,17 @@ unsigned int comedi_buf_write_free(struct comedi_subdevice *s, } EXPORT_SYMBOL_GPL(comedi_buf_write_free); +/** + * comedi_buf_read_n_available() - Determine amount of readable buffer space + * @s: COMEDI subdevice. + * + * Determine the amount of readable buffer space in the COMEDI acquisition data + * buffer associated with the subdevice. The readable buffer space is that + * which has been freed by the writer and "munged" to the sample data format + * expected by COMEDI if necessary. + * + * Return: The amount of readable buffer space. + */ unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) { struct comedi_async *async = s->async; @@ -369,7 +412,21 @@ unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) } EXPORT_SYMBOL_GPL(comedi_buf_read_n_available); -/* allocates a chunk for the reader from filled (and munged) buffer space */ +/** + * comedi_buf_read_alloc() - Reserve buffer space for reading + * @s: COMEDI subdevice. + * @nbytes: Maximum space to reserve in bytes. + * + * Reserve up to @nbytes bytes of previously written and "munged" buffer space + * for reading in the COMEDI acquisition data buffer associated with the + * subdevice. The amount reserved is limited to the space available. The + * reader can read from the reserved space and then free it. A reader is also + * allowed to read from the space before reserving it as long as it determines + * the amount of readable data available, but the space needs to be marked as + * reserved before it can be freed. + * + * Return: The amount of space reserved in bytes. + */ unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, unsigned int nbytes) { @@ -397,7 +454,19 @@ static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async) return async->buf_read_alloc_count - async->buf_read_count; } -/* transfers control of a chunk from reader to free buffer space */ +/** + * comedi_buf_read_free() - Free buffer space after it has been read + * @s: COMEDI subdevice. + * @nbytes: Maximum space to free in bytes. + * + * Free up to @nbytes bytes of buffer space previously reserved for reading in + * the COMEDI acquisition data buffer associated with the subdevice. The + * amount of space freed is limited to the amount that was reserved. + * + * The freed space becomes available for allocation by the writer. + * + * Return: The amount of space freed in bytes. + */ unsigned int comedi_buf_read_free(struct comedi_subdevice *s, unsigned int nbytes) { @@ -469,15 +538,21 @@ static void comedi_buf_memcpy_from(struct comedi_subdevice *s, } /** - * comedi_buf_write_samples - write sample data to comedi buffer - * @s: comedi_subdevice struct - * @data: samples - * @nsamples: number of samples + * comedi_buf_write_samples() - Write sample data to COMEDI buffer + * @s: COMEDI subdevice. + * @data: Pointer to source samples. + * @nsamples: Number of samples to write. * - * Writes nsamples to the comedi buffer associated with the subdevice, marks - * it as written and updates the acquisition scan progress. + * Write up to @nsamples samples to the COMEDI acquisition data buffer + * associated with the subdevice, mark it as written and update the + * acquisition scan progress. If there is not enough room for the specified + * number of samples, the number of samples written is limited to the number + * that will fit and the %COMEDI_CB_OVERFLOW event flag is set to cause the + * acquisition to terminate with an overrun error. Set the %COMEDI_CB_BLOCK + * event flag if any samples are written to cause waiting tasks to be woken + * when the event flags are processed. * - * Returns the amount of data written in bytes. + * Return: The amount of data written in bytes. */ unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, const void *data, unsigned int nsamples) @@ -490,8 +565,7 @@ unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, * 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)); + max_samples = comedi_bytes_to_samples(s, comedi_buf_write_n_unalloc(s)); if (nsamples > max_samples) { dev_warn(s->device->class_dev, "buffer overrun\n"); s->async->events |= COMEDI_CB_OVERFLOW; @@ -513,15 +587,18 @@ unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, EXPORT_SYMBOL_GPL(comedi_buf_write_samples); /** - * comedi_buf_read_samples - read sample data from comedi buffer - * @s: comedi_subdevice struct - * @data: destination - * @nsamples: maximum number of samples to read + * comedi_buf_read_samples() - Read sample data from COMEDI buffer + * @s: COMEDI subdevice. + * @data: Pointer to destination. + * @nsamples: Maximum number of samples to read. * - * Reads up to nsamples from the comedi buffer associated with the subdevice, - * marks it as read and updates the acquisition scan progress. + * Read up to @nsamples samples from the COMEDI acquisition data buffer + * associated with the subdevice, mark it as read and update the acquisition + * scan progress. Limit the number of samples read to the number available. + * Set the %COMEDI_CB_BLOCK event flag if any samples are read to cause waiting + * tasks to be woken when the event flags are processed. * - * Returns the amount of data read in bytes. + * Return: The amount of data read in bytes. */ unsigned int comedi_buf_read_samples(struct comedi_subdevice *s, void *data, unsigned int nsamples) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 0e8a45102..7b4af519e 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -43,15 +43,15 @@ #include "comedi_internal.h" -/** +/* * comedi_subdevice "runflags" - * @COMEDI_SRF_RT: DEPRECATED: command is running real-time - * @COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred + * COMEDI_SRF_RT: DEPRECATED: command is running real-time + * COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred * since the last command was started - * @COMEDI_SRF_RUNNING: command is running - * @COMEDI_SRF_FREE_SPRIV: free s->private on detach + * COMEDI_SRF_RUNNING: command is running + * COMEDI_SRF_FREE_SPRIV: free s->private on detach * - * @COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy" + * COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy" */ #define COMEDI_SRF_RT BIT(1) #define COMEDI_SRF_ERROR BIT(2) @@ -61,12 +61,12 @@ #define COMEDI_SRF_BUSY_MASK (COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING) /** - * 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 - Per-file private data for COMEDI device + * @dev: COMEDI device. + * @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; @@ -131,15 +131,15 @@ static void comedi_dev_kref_release(struct kref *kref) } /** - * comedi_dev_put - release a use of a comedi device structure - * @dev: comedi_device struct + * comedi_dev_put() - Release a use of a COMEDI device + * @dev: COMEDI device. * - * Must be called when a user of a comedi device is finished with it. - * When the last user of the comedi device calls this function, the - * comedi device is destroyed. + * Must be called when a user of a COMEDI device is finished with it. + * When the last user of the COMEDI device calls this function, the + * COMEDI device is destroyed. * - * Return 1 if the comedi device is destroyed by this call or dev is - * NULL, otherwise return 0. Callers must not assume the comedi + * Return: 1 if the COMEDI device is destroyed by this call or @dev is + * NULL, otherwise return 0. Callers must not assume the COMEDI * device is still valid if this function returns 0. */ int comedi_dev_put(struct comedi_device *dev) @@ -247,15 +247,15 @@ static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor) } /** - * comedi_dev_get_from_minor - get comedi device by minor device number - * @minor: minor device number + * comedi_dev_get_from_minor() - Get COMEDI device by minor device number + * @minor: Minor device number. * - * Finds the comedi device associated by the minor device number, if any, - * and increments its reference count. The comedi device is prevented from + * Finds the COMEDI device associated with the minor device number, if any, + * and increments its reference count. The COMEDI device is prevented from * being freed until a matching call is made to comedi_dev_put(). * - * Return a pointer to the comedi device if it exists, with its usage - * reference incremented. Return NULL if no comedi device exists with the + * Return: A pointer to the COMEDI device if it exists, with its usage + * reference incremented. Return NULL if no COMEDI device exists with the * specified minor device number. */ struct comedi_device *comedi_dev_get_from_minor(unsigned minor) @@ -665,11 +665,11 @@ static bool comedi_is_runflags_in_error(unsigned runflags) } /** - * comedi_is_subdevice_running - check if async command running on subdevice - * @s: comedi_subdevice struct + * comedi_is_subdevice_running() - Check if async command running on subdevice + * @s: COMEDI subdevice. * - * Return true if an asynchronous comedi command is active on the comedi - * subdevice, else return false. + * Return: %true if an asynchronous COMEDI command is active on the + * subdevice, else %false. */ bool comedi_is_subdevice_running(struct comedi_subdevice *s) { @@ -701,11 +701,12 @@ bool comedi_can_auto_free_spriv(struct comedi_subdevice *s) } /** - * comedi_set_spriv_auto_free - mark subdevice private data as freeable - * @s: comedi_subdevice struct + * comedi_set_spriv_auto_free() - Mark subdevice private data as freeable + * @s: COMEDI subdevice. * * Mark the subdevice as having a pointer to private data that can be - * automatically freed by the comedi core during the detach. + * automatically freed when the COMEDI device is detached from the low-level + * driver. */ void comedi_set_spriv_auto_free(struct comedi_subdevice *s) { @@ -714,12 +715,16 @@ void comedi_set_spriv_auto_free(struct comedi_subdevice *s) EXPORT_SYMBOL_GPL(comedi_set_spriv_auto_free); /** - * comedi_alloc_spriv - Allocate memory for the subdevice private data. - * @s: comedi_subdevice struct - * @size: size of the memory to allocate + * comedi_alloc_spriv - Allocate memory for the subdevice private data + * @s: COMEDI subdevice. + * @size: Size of the memory to allocate. + * + * Allocate memory for the subdevice private data and point @s->private + * to it. The memory will be freed automatically when the COMEDI device + * is detached from the low-level driver. * - * This also sets the subdevice runflags to allow the core to automatically - * free the private data during the detach. + * Return: A pointer to the allocated memory @s->private on success. + * Return NULL on failure. */ void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size) { @@ -1141,7 +1146,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, comedi_buf_read_free(s, bi.bytes_read); if (comedi_is_subdevice_idle(s) && - comedi_buf_n_bytes_ready(s) == 0) { + comedi_buf_read_n_available(s) == 0) { do_become_nonbusy(dev, s); } } @@ -1336,7 +1341,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, goto out; } /* This looks arbitrary. It is. */ - s->busy = &parse_insn; + s->busy = parse_insn; switch (insn->insn) { case INSN_READ: ret = s->insn_read(dev, s, insn, data); @@ -2257,9 +2262,9 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) unsigned int mask = 0; struct comedi_file *cfp = file->private_data; struct comedi_device *dev = cfp->dev; - struct comedi_subdevice *s; + struct comedi_subdevice *s, *s_read; - mutex_lock(&dev->mutex); + down_read(&dev->attach_lock); if (!dev->attached) { dev_dbg(dev->class_dev, "no driver attached\n"); @@ -2267,9 +2272,10 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) } s = comedi_file_read_subdevice(file); + s_read = s; if (s && s->async) { poll_wait(file, &s->async->wait_head, wait); - if (!s->busy || !comedi_is_subdevice_running(s) || + if (s->busy != file || !comedi_is_subdevice_running(s) || (s->async->cmd.flags & CMDF_WRITE) || comedi_buf_read_n_available(s) > 0) mask |= POLLIN | POLLRDNORM; @@ -2279,16 +2285,16 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) if (s && s->async) { 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) || + if (s != s_read) + poll_wait(file, &s->async->wait_head, wait); + if (s->busy != file || !comedi_is_subdevice_running(s) || !(s->async->cmd.flags & CMDF_WRITE) || - comedi_buf_write_n_allocated(s) >= bps) + comedi_buf_write_n_available(s) >= bps) mask |= POLLOUT | POLLWRNORM; } done: - mutex_unlock(&dev->mutex); + up_read(&dev->attach_lock); return mask; } @@ -2444,7 +2450,9 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, { struct comedi_subdevice *s; struct comedi_async *async; - int n, m, count = 0, retval = 0; + unsigned int n, m; + ssize_t count = 0; + int retval = 0; DECLARE_WAITQUEUE(wait, current); struct comedi_file *cfp = file->private_data; struct comedi_device *dev = cfp->dev; @@ -2470,28 +2478,19 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, } async = s->async; - if (!s->busy || !nbytes) - goto out; - if (s->busy != file) { - retval = -EACCES; - goto out; - } - if (async->cmd.flags & CMDF_WRITE) { + if (s->busy != file || (async->cmd.flags & CMDF_WRITE)) { retval = -EINVAL; goto out; } add_wait_queue(&async->wait_head, &wait); - while (nbytes > 0 && !retval) { - set_current_state(TASK_INTERRUPTIBLE); + while (count == 0 && !retval) { + unsigned int rp, n1, n2; - n = nbytes; + set_current_state(TASK_INTERRUPTIBLE); m = comedi_buf_read_n_available(s); - if (async->buf_read_ptr + m > async->prealloc_bufsz) - m = async->prealloc_bufsz - async->buf_read_ptr; - if (m < n) - n = m; + n = min_t(size_t, m, nbytes); if (n == 0) { unsigned runflags = comedi_get_subdevice_runflags(s); @@ -2499,11 +2498,12 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, if (!comedi_is_runflags_running(runflags)) { if (comedi_is_runflags_in_error(runflags)) retval = -EPIPE; - else - retval = 0; - become_nonbusy = true; + if (retval || nbytes) + become_nonbusy = true; break; } + if (nbytes == 0) + break; if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; @@ -2513,22 +2513,21 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, retval = -ERESTARTSYS; break; } - if (!s->busy) { - retval = 0; - break; - } - if (s->busy != file) { - retval = -EACCES; - break; - } - if (async->cmd.flags & CMDF_WRITE) { + if (s->busy != file || + (async->cmd.flags & CMDF_WRITE)) { retval = -EINVAL; break; } continue; } - m = copy_to_user(buf, async->prealloc_buf + - async->buf_read_ptr, n); + rp = async->buf_read_ptr; + n1 = min(n, async->prealloc_bufsz - rp); + n2 = n - n1; + m = copy_to_user(buf, async->prealloc_buf + rp, n1); + if (m) + m += n2; + else if (n2) + m = copy_to_user(buf + n1, async->prealloc_buf, n2); if (m) { n -= m; retval = -EFAULT; @@ -2541,11 +2540,10 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, nbytes -= n; buf += n; - break; /* makes device work like a pipe */ } remove_wait_queue(&async->wait_head, &wait); set_current_state(TASK_RUNNING); - if (become_nonbusy || comedi_is_subdevice_idle(s)) { + if (become_nonbusy && count == 0) { struct comedi_subdevice *new_s; /* @@ -2561,13 +2559,17 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, * sufficient (unless there have been 2**32 detaches in the * meantime!), but check the subdevice pointer as well just in * case. + * + * Also check the subdevice is still in a suitable state to + * become non-busy in case it changed behind our back. */ 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) - do_become_nonbusy(dev, s); - } + s == new_s && new_s->async == async && s->busy == file && + !(async->cmd.flags & CMDF_WRITE) && + !comedi_is_subdevice_running(s) && + comedi_buf_read_n_available(s) == 0) + do_become_nonbusy(dev, s); mutex_unlock(&dev->mutex); } out: @@ -2686,15 +2688,15 @@ static const struct file_operations comedi_fops = { }; /** - * comedi_event - handle events for asynchronous comedi command - * @dev: comedi_device struct - * @s: comedi_subdevice struct associated with dev - * Context: interrupt (usually), s->spin_lock spin-lock not held + * comedi_event() - Handle events for asynchronous COMEDI command + * @dev: COMEDI device. + * @s: COMEDI subdevice. + * Context: in_interrupt() (usually), @s->spin_lock spin-lock not held. * - * If an asynchronous comedi command is active on the subdevice, process - * any COMEDI_CB_... event flags that have been set, usually by an + * If an asynchronous COMEDI command is active on the subdevice, process + * any %COMEDI_CB_... event flags that have been set, usually by an * interrupt handler. These may change the run state of the asynchronous - * command, wake a task, and/or send a SIGIO signal. + * command, wake a task, and/or send a %SIGIO signal. */ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) { diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h index cd9437f72..3f2c88ae6 100644 --- a/drivers/staging/comedi/comedi_internal.h +++ b/drivers/staging/comedi/comedi_internal.h @@ -31,6 +31,7 @@ void comedi_buf_map_get(struct comedi_buf_map *bm); int comedi_buf_map_put(struct comedi_buf_map *bm); struct comedi_buf_map *comedi_buf_map_from_subdev_get( struct comedi_subdevice *s); +unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s); unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s); void comedi_device_cancel_all(struct comedi_device *dev); bool comedi_can_auto_free_spriv(struct comedi_subdevice *s); diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/staging/comedi/comedi_pci.c index 027f0f4e5..51e023a1c 100644 --- a/drivers/staging/comedi/comedi_pci.c +++ b/drivers/staging/comedi/comedi_pci.c @@ -22,8 +22,14 @@ #include "comedi_pci.h" /** - * comedi_to_pci_dev() - comedi_device pointer to pci_dev pointer. - * @dev: comedi_device struct + * comedi_to_pci_dev() - Return PCI device attached to COMEDI device + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pci_dev. + * + * Return: Attached PCI device if @dev->hw_dev is non-%NULL. + * Return %NULL if @dev->hw_dev is %NULL. */ struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) { @@ -32,8 +38,22 @@ struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_to_pci_dev); /** - * comedi_pci_enable() - Enable the PCI device and request the regions. - * @dev: comedi_device struct + * comedi_pci_enable() - Enable the PCI device and request the regions + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pci_dev. Enable the PCI device + * and request its regions. Set @dev->ioenabled to %true if successful, + * otherwise undo what was done. + * + * Calls to comedi_pci_enable() and comedi_pci_disable() cannot be nested. + * + * Return: + * 0 on success, + * -%ENODEV if @dev->hw_dev is %NULL, + * -%EBUSY if regions busy, + * or some negative error number if failed to enable PCI device. + * */ int comedi_pci_enable(struct comedi_device *dev) { @@ -58,8 +78,13 @@ int comedi_pci_enable(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_pci_enable); /** - * comedi_pci_disable() - Release the regions and disable the PCI device. - * @dev: comedi_device struct + * comedi_pci_disable() - Release the regions and disable the PCI device + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pci_dev. If the earlier call + * to comedi_pci_enable() was successful, release the PCI device's regions + * and disable it. Reset @dev->ioenabled back to %false. */ void comedi_pci_disable(struct comedi_device *dev) { @@ -74,8 +99,18 @@ void comedi_pci_disable(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_pci_disable); /** - * comedi_pci_detach() - A generic (*detach) function for PCI drivers. - * @dev: comedi_device struct + * comedi_pci_detach() - A generic "detach" handler for PCI COMEDI drivers + * @dev: COMEDI device. + * + * COMEDI drivers for PCI devices that need no special clean-up of private data + * and have no ioremapped regions other than that pointed to by @dev->mmio may + * use this function as its "detach" handler called by the COMEDI core when a + * COMEDI device is being detached from the low-level driver. It may be also + * called from a more specific "detach" handler that does additional clean-up. + * + * Free the IRQ if @dev->irq is non-zero, iounmap @dev->mmio if it is + * non-%NULL, and call comedi_pci_disable() to release the PCI device's regions + * and disable it. */ void comedi_pci_detach(struct comedi_device *dev) { @@ -97,12 +132,19 @@ void comedi_pci_detach(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_pci_detach); /** - * comedi_pci_auto_config() - Configure/probe a comedi PCI driver. - * @pcidev: pci_dev struct - * @driver: comedi_driver struct - * @context: driver specific data, passed to comedi_auto_config() + * comedi_pci_auto_config() - Configure/probe a PCI COMEDI device + * @pcidev: PCI device. + * @driver: Registered COMEDI driver. + * @context: Driver specific data, passed to comedi_auto_config(). * - * Typically called from the pci_driver (*probe) function. + * Typically called from the pci_driver (*probe) function. Auto-configure + * a COMEDI device, using the &struct device embedded in *@pcidev as the + * hardware device. The @context value gets passed through to @driver's + * "auto_attach" handler. The "auto_attach" handler may call + * comedi_to_pci_dev() on the passed in COMEDI device to recover @pcidev. + * + * Return: The result of calling comedi_auto_config() (0 on success, or + * a negative error number on failure). */ int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver, @@ -113,10 +155,18 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, EXPORT_SYMBOL_GPL(comedi_pci_auto_config); /** - * comedi_pci_auto_unconfig() - Unconfigure/remove a comedi PCI driver. - * @pcidev: pci_dev struct + * comedi_pci_auto_unconfig() - Unconfigure/remove a PCI COMEDI device + * @pcidev: PCI device. + * + * Typically called from the pci_driver (*remove) function. Auto-unconfigure + * a COMEDI device attached to this PCI device, using a pointer to the + * &struct device embedded in *@pcidev as the hardware device. The COMEDI + * driver's "detach" handler will be called during unconfiguration of the + * COMEDI device. * - * Typically called from the pci_driver (*remove) function. + * Note that the COMEDI device may have already been unconfigured using the + * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it + * again should be ignored. */ void comedi_pci_auto_unconfig(struct pci_dev *pcidev) { @@ -125,13 +175,15 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev) EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); /** - * comedi_pci_driver_register() - Register a comedi PCI driver. - * @comedi_driver: comedi_driver struct - * @pci_driver: pci_driver struct + * comedi_pci_driver_register() - Register a PCI COMEDI driver + * @comedi_driver: COMEDI driver to be registered. + * @pci_driver: PCI driver to be registered. + * + * This function is called from the module_init() of PCI COMEDI driver modules + * to register the COMEDI driver and the PCI driver. Do not call it directly, + * use the module_comedi_pci_driver() helper macro instead. * - * This function is used for the module_init() of comedi PCI drivers. - * Do not call it directly, use the module_comedi_pci_driver() helper - * macro instead. + * Return: 0 on success, or a negative error number on failure. */ int comedi_pci_driver_register(struct comedi_driver *comedi_driver, struct pci_driver *pci_driver) @@ -153,13 +205,13 @@ int comedi_pci_driver_register(struct comedi_driver *comedi_driver, EXPORT_SYMBOL_GPL(comedi_pci_driver_register); /** - * comedi_pci_driver_unregister() - Unregister a comedi PCI driver. - * @comedi_driver: comedi_driver struct - * @pci_driver: pci_driver struct + * comedi_pci_driver_unregister() - Unregister a PCI COMEDI driver + * @comedi_driver: COMEDI driver to be unregistered. + * @pci_driver: PCI driver to be unregistered. * - * This function is used for the module_exit() of comedi PCI drivers. - * Do not call it directly, use the module_comedi_pci_driver() helper - * macro instead. + * This function is called from the module_exit() of PCI COMEDI driver modules + * to unregister the PCI driver and the COMEDI driver. Do not call it + * directly, use the module_comedi_pci_driver() helper macro instead. */ void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, struct pci_driver *pci_driver) diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/staging/comedi/comedi_pcmcia.c index 7e784399a..d7072a5c1 100644 --- a/drivers/staging/comedi/comedi_pcmcia.c +++ b/drivers/staging/comedi/comedi_pcmcia.c @@ -22,8 +22,14 @@ #include "comedi_pcmcia.h" /** - * comedi_to_pcmcia_dev() - comedi_device pointer to pcmcia_device pointer. - * @dev: comedi_device struct + * comedi_to_pcmcia_dev() - Return PCMCIA device attached to COMEDI device + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pcmcia_device. + * + * Return: Attached PCMCIA device if @dev->hw_dev is non-%NULL. + * Return %NULL if @dev->hw_dev is %NULL. */ struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *dev) { @@ -41,13 +47,35 @@ static int comedi_pcmcia_conf_check(struct pcmcia_device *link, } /** - * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device. - * @dev: comedi_device struct - * @conf_check: optional callback to check the pcmcia_device configuration + * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device + * @dev: COMEDI device. + * @conf_check: Optional callback to check each configuration option of the + * PCMCIA device and request I/O regions. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a a + * &struct device embedded in a &struct pcmcia_device. The comedi PCMCIA + * driver needs to set the 'config_flags' member in the &struct pcmcia_device, + * as appropriate for that driver, before calling this function in order to + * allow pcmcia_loop_config() to do its internal autoconfiguration. + * + * If @conf_check is %NULL it is set to a default function. If is + * passed to pcmcia_loop_config() and should return %0 if the configuration + * is valid and I/O regions requested successfully, otherwise it should return + * a negative error value. The default function returns -%EINVAL if the + * 'config_index' member is %0, otherwise it calls pcmcia_request_io() and + * returns the result. + * + * If the above configuration check passes, pcmcia_enable_device() is called + * to set up and activate the PCMCIA device. * - * The comedi PCMCIA driver needs to set the link->config_flags, as - * appropriate for that driver, before calling this function in order - * to allow pcmcia_loop_config() to do its internal autoconfiguration. + * If this function returns an error, comedi_pcmcia_disable() should be called + * to release requested resources. + * + * Return: + * 0 on success, + * -%ENODEV id @dev->hw_dev is %NULL, + * a negative error number from pcmcia_loop_config() if it fails, + * or a negative error number from pcmcia_enable_device() if it fails. */ int comedi_pcmcia_enable(struct comedi_device *dev, int (*conf_check)(struct pcmcia_device *, void *)) @@ -70,8 +98,12 @@ int comedi_pcmcia_enable(struct comedi_device *dev, EXPORT_SYMBOL_GPL(comedi_pcmcia_enable); /** - * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions. - * @dev: comedi_device struct + * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pcmcia_device. Call + * pcmcia_disable_device() to disable and clean up the PCMCIA device. */ void comedi_pcmcia_disable(struct comedi_device *dev) { @@ -83,11 +115,17 @@ void comedi_pcmcia_disable(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_pcmcia_disable); /** - * comedi_pcmcia_auto_config() - Configure/probe a comedi PCMCIA driver. - * @link: pcmcia_device struct - * @driver: comedi_driver struct + * comedi_pcmcia_auto_config() - Configure/probe a PCMCIA COMEDI device + * @link: PCMCIA device. + * @driver: Registered COMEDI driver. + * + * Typically called from the pcmcia_driver (*probe) function. Auto-configure + * a COMEDI device, using a pointer to the &struct device embedded in *@link + * as the hardware device. The @driver's "auto_attach" handler may call + * comedi_to_pcmcia_dev() on the passed in COMEDI device to recover @link. * - * Typically called from the pcmcia_driver (*probe) function. + * Return: The result of calling comedi_auto_config() (0 on success, or a + * negative error number on failure). */ int comedi_pcmcia_auto_config(struct pcmcia_device *link, struct comedi_driver *driver) @@ -97,10 +135,18 @@ int comedi_pcmcia_auto_config(struct pcmcia_device *link, EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_config); /** - * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a comedi PCMCIA driver. - * @link: pcmcia_device struct + * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a PCMCIA COMEDI device + * @link: PCMCIA device. * * Typically called from the pcmcia_driver (*remove) function. + * Auto-unconfigure a COMEDI device attached to this PCMCIA device, using a + * pointer to the &struct device embedded in *@link as the hardware device. + * The COMEDI driver's "detach" handler will be called during unconfiguration + * of the COMEDI device. + * + * Note that the COMEDI device may have already been unconfigured using the + * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it + * again should be ignored. */ void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) { @@ -109,13 +155,15 @@ void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_unconfig); /** - * comedi_pcmcia_driver_register() - Register a comedi PCMCIA driver. - * @comedi_driver: comedi_driver struct - * @pcmcia_driver: pcmcia_driver struct + * comedi_pcmcia_driver_register() - Register a PCMCIA COMEDI driver + * @comedi_driver: COMEDI driver to be registered. + * @pcmcia_driver: PCMCIA driver to be registered. + * + * This function is used for the module_init() of PCMCIA COMEDI driver modules + * to register the COMEDI driver and the PCMCIA driver. Do not call it + * directly, use the module_comedi_pcmcia_driver() helper macro instead. * - * This function is used for the module_init() of comedi USB drivers. - * Do not call it directly, use the module_comedi_pcmcia_driver() helper - * macro instead. + * Return: 0 on success, or a negative error number on failure. */ int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver, struct pcmcia_driver *pcmcia_driver) @@ -137,13 +185,13 @@ int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver, EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_register); /** - * comedi_pcmcia_driver_unregister() - Unregister a comedi PCMCIA driver. - * @comedi_driver: comedi_driver struct - * @pcmcia_driver: pcmcia_driver struct + * comedi_pcmcia_driver_unregister() - Unregister a PCMCIA COMEDI driver + * @comedi_driver: COMEDI driver to be registered. + * @pcmcia_driver: PCMCIA driver to be registered. * - * This function is used for the module_exit() of comedi PCMCIA drivers. - * Do not call it directly, use the module_comedi_pcmcia_driver() helper - * macro instead. + * This function is called from the module_exit() of PCMCIA COMEDI driver + * modules to unregister the PCMCIA driver and the COMEDI driver. Do not call + * it directly, use the module_comedi_pcmcia_driver() helper macro instead. */ void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver, struct pcmcia_driver *pcmcia_driver) diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/staging/comedi/comedi_usb.c index 68b75e8fe..9c946d40b 100644 --- a/drivers/staging/comedi/comedi_usb.c +++ b/drivers/staging/comedi/comedi_usb.c @@ -21,8 +21,14 @@ #include "comedi_usb.h" /** - * comedi_to_usb_interface() - comedi_device pointer to usb_interface pointer. - * @dev: comedi_device struct + * comedi_to_usb_interface() - Return USB interface attached to COMEDI device + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct usb_interface. + * + * Return: Attached USB interface if @dev->hw_dev is non-%NULL. + * Return %NULL if @dev->hw_dev is %NULL. */ struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev) { @@ -31,8 +37,14 @@ struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_to_usb_interface); /** - * comedi_to_usb_dev() - comedi_device pointer to usb_device pointer. - * @dev: comedi_device struct + * comedi_to_usb_dev() - Return USB device attached to COMEDI device + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct usb_interface. + * + * Return: USB device to which the USB interface belongs if @dev->hw_dev is + * non-%NULL. Return %NULL if @dev->hw_dev is %NULL. */ struct usb_device *comedi_to_usb_dev(struct comedi_device *dev) { @@ -43,12 +55,19 @@ struct usb_device *comedi_to_usb_dev(struct comedi_device *dev) EXPORT_SYMBOL_GPL(comedi_to_usb_dev); /** - * comedi_usb_auto_config() - Configure/probe a comedi USB driver. - * @intf: usb_interface struct - * @driver: comedi_driver struct - * @context: driver specific data, passed to comedi_auto_config() + * comedi_usb_auto_config() - Configure/probe a USB COMEDI driver + * @intf: USB interface. + * @driver: Registered COMEDI driver. + * @context: Driver specific data, passed to comedi_auto_config(). * - * Typically called from the usb_driver (*probe) function. + * Typically called from the usb_driver (*probe) function. Auto-configure a + * COMEDI device, using a pointer to the &struct device embedded in *@intf as + * the hardware device. The @context value gets passed through to @driver's + * "auto_attach" handler. The "auto_attach" handler may call + * comedi_to_usb_interface() on the passed in COMEDI device to recover @intf. + * + * Return: The result of calling comedi_auto_config() (%0 on success, or + * a negative error number on failure). */ int comedi_usb_auto_config(struct usb_interface *intf, struct comedi_driver *driver, @@ -59,10 +78,18 @@ int comedi_usb_auto_config(struct usb_interface *intf, EXPORT_SYMBOL_GPL(comedi_usb_auto_config); /** - * comedi_pci_auto_unconfig() - Unconfigure/disconnect a comedi USB driver. - * @intf: usb_interface struct + * comedi_usb_auto_unconfig() - Unconfigure/disconnect a USB COMEDI device + * @intf: USB interface. * * Typically called from the usb_driver (*disconnect) function. + * Auto-unconfigure a COMEDI device attached to this USB interface, using a + * pointer to the &struct device embedded in *@intf as the hardware device. + * The COMEDI driver's "detach" handler will be called during unconfiguration + * of the COMEDI device. + * + * Note that the COMEDI device may have already been unconfigured using the + * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it + * again should be ignored. */ void comedi_usb_auto_unconfig(struct usb_interface *intf) { @@ -71,13 +98,15 @@ void comedi_usb_auto_unconfig(struct usb_interface *intf) EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig); /** - * comedi_usb_driver_register() - Register a comedi USB driver. - * @comedi_driver: comedi_driver struct - * @usb_driver: usb_driver struct + * comedi_usb_driver_register() - Register a USB COMEDI driver + * @comedi_driver: COMEDI driver to be registered. + * @usb_driver: USB driver to be registered. + * + * This function is called from the module_init() of USB COMEDI driver modules + * to register the COMEDI driver and the USB driver. Do not call it directly, + * use the module_comedi_usb_driver() helper macro instead. * - * This function is used for the module_init() of comedi USB drivers. - * Do not call it directly, use the module_comedi_usb_driver() helper - * macro instead. + * Return: %0 on success, or a negative error number on failure. */ int comedi_usb_driver_register(struct comedi_driver *comedi_driver, struct usb_driver *usb_driver) @@ -99,13 +128,13 @@ int comedi_usb_driver_register(struct comedi_driver *comedi_driver, EXPORT_SYMBOL_GPL(comedi_usb_driver_register); /** - * comedi_usb_driver_unregister() - Unregister a comedi USB driver. - * @comedi_driver: comedi_driver struct - * @usb_driver: usb_driver struct + * comedi_usb_driver_unregister() - Unregister a USB COMEDI driver + * @comedi_driver: COMEDI driver to be registered. + * @usb_driver: USB driver to be registered. * - * This function is used for the module_exit() of comedi USB drivers. - * Do not call it directly, use the module_comedi_usb_driver() helper - * macro instead. + * This function is called from the module_exit() of USB COMEDI driver modules + * to unregister the USB driver and the COMEDI driver. Do not call it + * directly, use the module_comedi_usb_driver() helper macro instead. */ void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver, struct usb_driver *usb_driver) diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index 28a5d3a03..115807215 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -1,20 +1,20 @@ /* - include/linux/comedidev.h - header file for kernel-only structures, variables, and constants - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-2000 David A. Schleef - - 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. -*/ + * comedidev.h + * header file for kernel-only structures, variables, and constants + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #ifndef _COMEDIDEV_H #define _COMEDIDEV_H @@ -34,6 +34,131 @@ #define COMEDI_NUM_BOARD_MINORS 0x30 +/** + * struct comedi_subdevice - Working data for a COMEDI subdevice + * @device: COMEDI device to which this subdevice belongs. (Initialized by + * comedi_alloc_subdevices().) + * @index: Index of this subdevice within device's array of subdevices. + * (Initialized by comedi_alloc_subdevices().) + * @type: Type of subdevice from &enum comedi_subdevice_type. (Initialized by + * the low-level driver.) + * @n_chan: Number of channels the subdevice supports. (Initialized by the + * low-level driver.) + * @subdev_flags: Various "SDF" flags indicating aspects of the subdevice to + * the COMEDI core and user application. (Initialized by the low-level + * driver.) + * @len_chanlist: Maximum length of a channel list if the subdevice supports + * asynchronous acquisition commands. (Optionally initialized by the + * low-level driver, or changed from 0 to 1 during post-configuration.) + * @private: Private data pointer which is either set by the low-level driver + * itself, or by a call to comedi_alloc_spriv() which allocates storage. + * In the latter case, the storage is automatically freed after the + * low-level driver's "detach" handler is called for the device. + * (Initialized by the low-level driver.) + * @async: Pointer to &struct comedi_async id the subdevice supports + * asynchronous acquisition commands. (Allocated and initialized during + * post-configuration if needed.) + * @lock: Pointer to a file object that performed a %COMEDI_LOCK ioctl on the + * subdevice. (Initially NULL.) + * @busy: Pointer to a file object that is performing an asynchronous + * acquisition command on the subdevice. (Initially NULL.) + * @runflags: Internal flags for use by COMEDI core, mostly indicating whether + * an asynchronous acquisition command is running. + * @spin_lock: Generic spin-lock for use by the COMEDI core and the low-level + * driver. (Initialized by comedi_alloc_subdevices().) + * @io_bits: Bit-mask indicating the channel directions for a DIO subdevice + * with no more than 32 channels. A '1' at a bit position indicates the + * corresponding channel is configured as an output. (Initialized by the + * low-level driver for a DIO subdevice. Forced to all-outputs during + * post-configuration for a digital output subdevice.) + * @maxdata: If non-zero, this is the maximum raw data value of each channel. + * If zero, the maximum data value is channel-specific. (Initialized by + * the low-level driver.) + * @maxdata_list: If the maximum data value is channel-specific, this points + * to an array of maximum data values indexed by channel index. + * (Initialized by the low-level driver.) + * @range_table: If non-NULL, this points to a COMEDI range table for the + * subdevice. If NULL, the range table is channel-specific. (Initialized + * by the low-level driver, will be set to an "invalid" range table during + * post-configuration if @range_table and @range_table_list are both + * NULL.) + * @range_table_list: If the COMEDI range table is channel-specific, this + * points to an array of pointers to COMEDI range tables indexed by + * channel number. (Initialized by the low-level driver.) + * @chanlist: Not used. + * @insn_read: Optional pointer to a handler for the %INSN_READ instruction. + * (Initialized by the low-level driver, or set to a default handler + * during post-configuration.) + * @insn_write: Optional pointer to a handler for the %INSN_WRITE instruction. + * (Initialized by the low-level driver, or set to a default handler + * during post-configuration.) + * @insn_bits: Optional pointer to a handler for the %INSN_BITS instruction + * for a digital input, digital output or digital input/output subdevice. + * (Initialized by the low-level driver, or set to a default handler + * during post-configuration.) + * @insn_config: Optional pointer to a handler for the %INSN_CONFIG + * instruction. (Initialized by the low-level driver, or set to a default + * handler during post-configuration.) + * @do_cmd: If the subdevice supports asynchronous acquisition commands, this + * points to a handler to set it up in hardware. (Initialized by the + * low-level driver.) + * @do_cmdtest: If the subdevice supports asynchronous acquisition commands, + * this points to a handler used to check and possibly tweak a prospective + * acquisition command without setting it up in hardware. (Initialized by + * the low-level driver.) + * @poll: If the subdevice supports asynchronous acquisition commands, this + * is an optional pointer to a handler for the %COMEDI_POLL ioctl which + * instructs the low-level driver to synchronize buffers. (Initialized by + * the low-level driver if needed.) + * @cancel: If the subdevice supports asynchronous acquisition commands, this + * points to a handler used to terminate a running command. (Initialized + * by the low-level driver.) + * @buf_change: If the subdevice supports asynchronous acquisition commands, + * this is an optional pointer to a handler that is called when the data + * buffer for handling asynchronous commands is allocated or reallocated. + * (Initialized by the low-level driver if needed.) + * @munge: If the subdevice supports asynchronous acquisition commands and + * uses DMA to transfer data from the hardware to the acquisition buffer, + * this points to a function used to "munge" the data values from the + * hardware into the format expected by COMEDI. (Initialized by the + * low-level driver if needed.) + * @async_dma_dir: If the subdevice supports asynchronous acquisition commands + * and uses DMA to transfer data from the hardware to the acquisition + * buffer, this sets the DMA direction for the buffer. (initialized to + * %DMA_NONE by comedi_alloc_subdevices() and changed by the low-level + * driver if necessary.) + * @state: Handy bit-mask indicating the output states for a DIO or digital + * output subdevice with no more than 32 channels. (Initialized by the + * low-level driver.) + * @class_dev: If the subdevice supports asynchronous acquisition commands, + * this points to a sysfs comediX_subdY device where X is the minor device + * number of the COMEDI device and Y is the subdevice number. The minor + * device number for the sysfs device is allocated dynamically in the + * range 48 to 255. This is used to allow the COMEDI device to be opened + * with a different default read or write subdevice. (Allocated during + * post-configuration if needed.) + * @minor: If @class_dev is set, this is its dynamically allocated minor + * device number. (Set during post-configuration if necessary.) + * @readback: Optional pointer to memory allocated by + * comedi_alloc_subdev_readback() used to hold the values written to + * analog output channels so they can be read back. The storage is + * automatically freed after the low-level driver's "detach" handler is + * called for the device. (Initialized by the low-level driver.) + * + * This is the main control structure for a COMEDI subdevice. If the subdevice + * supports asynchronous acquisition commands, additional information is stored + * in the &struct comedi_async pointed to by @async. + * + * Most of the subdevice is initialized by the low-level driver's "attach" or + * "auto_attach" handlers but parts of it are initialized by + * comedi_alloc_subdevices(), and other parts are initialized during + * post-configuration on return from that handler. + * + * A low-level driver that sets @insn_bits for a digital input, digital output, + * or DIO subdevice may leave @insn_read and @insn_write uninitialized, in + * which case they will be set to a default handler during post-configuration + * that uses @insn_bits to emulate the %INSN_READ and %INSN_WRITE instructions. + */ struct comedi_subdevice { struct comedi_device *device; int index; @@ -49,7 +174,7 @@ struct comedi_subdevice { void *lock; void *busy; unsigned runflags; - spinlock_t spin_lock; + spinlock_t spin_lock; /* generic spin-lock for COMEDI and drivers */ unsigned int io_bits; @@ -92,11 +217,40 @@ struct comedi_subdevice { unsigned int *readback; }; +/** + * struct comedi_buf_page - Describe a page of a COMEDI buffer + * @virt_addr: Kernel address of page. + * @dma_addr: DMA address of page if in DMA coherent memory. + */ struct comedi_buf_page { void *virt_addr; dma_addr_t dma_addr; }; +/** + * struct comedi_buf_map - Describe pages in a COMEDI buffer + * @dma_hw_dev: Low-level hardware &struct device pointer copied from the + * COMEDI device's hw_dev member. + * @page_list: Pointer to array of &struct comedi_buf_page, one for each + * page in the buffer. + * @n_pages: Number of pages in the buffer. + * @dma_dir: DMA direction used to allocate pages of DMA coherent memory, + * or %DMA_NONE if pages allocated from regular memory. + * @refcount: &struct kref reference counter used to free the buffer. + * + * A COMEDI data buffer is allocated as individual pages, either in + * conventional memory or DMA coherent memory, depending on the attached, + * low-level hardware device. (The buffer pages also get mapped into the + * kernel's contiguous virtual address space pointed to by the 'prealloc_buf' + * member of &struct comedi_async.) + * + * The buffer is normally freed when the COMEDI device is detached from the + * low-level driver (which may happen due to device removal), but if it happens + * to be mmapped at the time, the pages cannot be freed until the buffer has + * been munmapped. That is what the reference counter is for. (The virtual + * address space pointed by 'prealloc_buf' is freed when the COMEDI device is + * detached.) + */ struct comedi_buf_map { struct device *dma_hw_dev; struct comedi_buf_page *page_list; @@ -106,61 +260,66 @@ struct comedi_buf_map { }; /** - * struct comedi_async - control data for asynchronous comedi commands - * @prealloc_buf: preallocated buffer - * @prealloc_bufsz: buffer size (in bytes) - * @buf_map: map of buffer pages - * @max_bufsize: maximum buffer size (in bytes) - * @buf_write_count: "write completed" count (in bytes, modulo 2**32) - * @buf_write_alloc_count: "allocated for writing" count (in bytes, - * modulo 2**32) - * @buf_read_count: "read completed" count (in bytes, modulo 2**32) - * @buf_read_alloc_count: "allocated for reading" count (in bytes, - * modulo 2**32) - * @buf_write_ptr: buffer position for writer - * @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) - * @munge_ptr: buffer position for "munging" - * @events: bit-vector of events that have occurred - * @cmd: details of comedi command in progress - * @wait_head: task wait queue for file reader or writer - * @cb_mask: bit-vector of events that should wake waiting tasks - * @inttrig: software trigger function for command, or NULL + * struct comedi_async - Control data for asynchronous COMEDI commands + * @prealloc_buf: Kernel virtual address of allocated acquisition buffer. + * @prealloc_bufsz: Buffer size (in bytes). + * @buf_map: Map of buffer pages. + * @max_bufsize: Maximum allowed buffer size (in bytes). + * @buf_write_count: "Write completed" count (in bytes, modulo 2**32). + * @buf_write_alloc_count: "Allocated for writing" count (in bytes, + * modulo 2**32). + * @buf_read_count: "Read completed" count (in bytes, modulo 2**32). + * @buf_read_alloc_count: "Allocated for reading" count (in bytes, + * modulo 2**32). + * @buf_write_ptr: Buffer position for writer. + * @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. + * @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). + * @munge_ptr: Buffer position for "munging". + * @events: Bit-vector of events that have occurred. + * @cmd: Details of comedi command in progress. + * @wait_head: Task wait queue for file reader or writer. + * @cb_mask: Bit-vector of events that should wake waiting tasks. + * @inttrig: Software trigger function for command, or NULL. * * Note about the ..._count and ..._ptr members: * * Think of the _Count values being integers of unlimited size, indexing * into a buffer of infinite length (though only an advancing portion - * of the buffer of fixed length prealloc_bufsz is accessible at any time). - * Then: + * of the buffer of fixed length prealloc_bufsz is accessible at any + * time). Then: * * Buf_Read_Count <= Buf_Read_Alloc_Count <= Munge_Count <= * Buf_Write_Count <= Buf_Write_Alloc_Count <= * (Buf_Read_Count + prealloc_bufsz) * - * (Those aren't the actual members, apart from prealloc_bufsz.) When - * the buffer is reset, those _Count values start at 0 and only increase - * in value, maintaining the above inequalities until the next time the - * buffer is reset. The buffer is divided into the following regions by - * the inequalities: + * (Those aren't the actual members, apart from prealloc_bufsz.) When the + * buffer is reset, those _Count values start at 0 and only increase in value, + * maintaining the above inequalities until the next time the buffer is + * reset. The buffer is divided into the following regions by the inequalities: * * [0, Buf_Read_Count): * old region no longer accessible + * * [Buf_Read_Count, Buf_Read_Alloc_Count): * filled and munged region allocated for reading but not yet read + * * [Buf_Read_Alloc_Count, Munge_Count): * filled and munged region not yet allocated for reading + * * [Munge_Count, Buf_Write_Count): * filled region not yet munged + * * [Buf_Write_Count, Buf_Write_Alloc_Count): * unfilled region allocated for writing but not yet written + * * [Buf_Write_Alloc_Count, Buf_Read_Count + prealloc_bufsz): * unfilled region not yet allocated for writing + * * [Buf_Read_Count + prealloc_bufsz, infinity): * unfilled region not yet accessible * @@ -216,43 +375,153 @@ struct comedi_async { }; /** - * comedi_async callback "events" + * enum comedi_cb - &struct 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 BIT(0) -#define COMEDI_CB_EOA BIT(1) -#define COMEDI_CB_BLOCK BIT(2) -#define COMEDI_CB_EOBUF BIT(3) -#define COMEDI_CB_ERROR BIT(4) -#define COMEDI_CB_OVERFLOW BIT(5) - -#define COMEDI_CB_ERROR_MASK (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW) -#define COMEDI_CB_CANCEL_MASK (COMEDI_CB_EOA | COMEDI_CB_ERROR_MASK) +enum comedi_cb { + COMEDI_CB_EOS = BIT(0), + COMEDI_CB_EOA = BIT(1), + COMEDI_CB_BLOCK = BIT(2), + COMEDI_CB_EOBUF = BIT(3), + COMEDI_CB_ERROR = BIT(4), + COMEDI_CB_OVERFLOW = BIT(5), + /* masks */ + COMEDI_CB_ERROR_MASK = (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW), + COMEDI_CB_CANCEL_MASK = (COMEDI_CB_EOA | COMEDI_CB_ERROR_MASK) +}; +/** + * struct comedi_driver - COMEDI driver registration + * @driver_name: Name of driver. + * @module: Owning module. + * @attach: The optional "attach" handler for manually configured COMEDI + * devices. + * @detach: The "detach" handler for deconfiguring COMEDI devices. + * @auto_attach: The optional "auto_attach" handler for automatically + * configured COMEDI devices. + * @num_names: Optional number of "board names" supported. + * @board_name: Optional pointer to a pointer to a board name. The pointer + * to a board name is embedded in an element of a driver-defined array + * of static, read-only board type information. + * @offset: Optional size of each element of the driver-defined array of + * static, read-only board type information, i.e. the offset between each + * pointer to a board name. + * + * This is used with comedi_driver_register() and comedi_driver_unregister() to + * register and unregister a low-level COMEDI driver with the COMEDI core. + * + * If @num_names is non-zero, @board_name should be non-NULL, and @offset + * should be at least sizeof(*board_name). These are used by the handler for + * the %COMEDI_DEVCONFIG ioctl to match a hardware device and its driver by + * board name. If @num_names is zero, the %COMEDI_DEVCONFIG ioctl matches a + * hardware device and its driver by driver name. This is only useful if the + * @attach handler is set. If @num_names is non-zero, the driver's @attach + * handler will be called with the COMEDI device structure's board_ptr member + * pointing to the matched pointer to a board name within the driver's private + * array of static, read-only board type information. + */ struct comedi_driver { - struct comedi_driver *next; - + /* private: */ + struct comedi_driver *next; /* Next in list of COMEDI drivers. */ + /* public: */ const char *driver_name; struct module *module; int (*attach)(struct comedi_device *, struct comedi_devconfig *); void (*detach)(struct comedi_device *); int (*auto_attach)(struct comedi_device *, unsigned long); - - /* number of elements in board_name and board_id arrays */ unsigned int num_names; const char *const *board_name; - /* offset in bytes from one board name pointer to the next */ int offset; }; +/** + * struct comedi_device - Working data for a COMEDI device + * @use_count: Number of open file objects. + * @driver: Low-level COMEDI driver attached to this COMEDI device. + * @pacer: Optional pointer to a dynamically allocated acquisition pacer + * control. It is freed automatically after the COMEDI device is + * detached from the low-level driver. + * @private: Optional pointer to private data allocated by the low-level + * driver. It is freed automatically after the COMEDI device is + * detached from the low-level driver. + * @class_dev: Sysfs comediX device. + * @minor: Minor device number of COMEDI char device (0-47). + * @detach_count: Counter incremented every time the COMEDI device is detached. + * Used for checking a previous attachment is still valid. + * @hw_dev: Optional pointer to the low-level hardware &struct device. It is + * required for automatically configured COMEDI devices and optional for + * COMEDI devices configured by the %COMEDI_DEVCONFIG ioctl, although + * the bus-specific COMEDI functions only work if it is set correctly. + * It is also passed to dma_alloc_coherent() for COMEDI subdevices that + * have their 'async_dma_dir' member set to something other than + * %DMA_NONE. + * @board_name: Pointer to a COMEDI board name or a COMEDI driver name. When + * the low-level driver's "attach" handler is called by the handler for + * the %COMEDI_DEVCONFIG ioctl, it either points to a matched board name + * string if the 'num_names' member of the &struct comedi_driver is + * non-zero, otherwise it points to the low-level driver name string. + * When the low-lever driver's "auto_attach" handler is called for an + * automatically configured COMEDI device, it points to the low-level + * driver name string. The low-level driver is free to change it in its + * "attach" or "auto_attach" handler if it wishes. + * @board_ptr: Optional pointer to private, read-only board type information in + * the low-level driver. If the 'num_names' member of the &struct + * comedi_driver is non-zero, the handler for the %COMEDI_DEVCONFIG ioctl + * will point it to a pointer to a matched board name string within the + * driver's private array of static, read-only board type information when + * calling the driver's "attach" handler. The low-level driver is free to + * change it. + * @attached: Flag indicating that the COMEDI device is attached to a low-level + * driver. + * @ioenabled: Flag used to indicate that a PCI device has been enabled and + * its regions requested. + * @spinlock: Generic spin-lock for use by the low-level driver. + * @mutex: Generic mutex for use by the COMEDI core module. + * @attach_lock: &struct rw_semaphore used to guard against the COMEDI device + * being detached while an operation is in progress. The down_write() + * operation is only allowed while @mutex is held and is used when + * changing @attached and @detach_count and calling the low-level driver's + * "detach" handler. The down_read() operation is generally used without + * holding @mutex. + * @refcount: &struct kref reference counter for freeing COMEDI device. + * @n_subdevices: Number of COMEDI subdevices allocated by the low-level + * driver for this device. + * @subdevices: Dynamically allocated array of COMEDI subdevices. + * @mmio: Optional pointer to a remapped MMIO region set by the low-level + * driver. + * @iobase: Optional base of an I/O port region requested by the low-level + * driver. + * @iolen: Length of I/O port region requested at @iobase. + * @irq: Optional IRQ number requested by the low-level driver. + * @read_subdev: Optional pointer to a default COMEDI subdevice operated on by + * the read() file operation. Set by the low-level driver. + * @write_subdev: Optional pointer to a default COMEDI subdevice operated on by + * the write() file operation. Set by the low-level driver. + * @async_queue: Storage for fasync_helper(). + * @open: Optional pointer to a function set by the low-level driver to be + * called when @use_count changes from 0 to 1. + * @close: Optional pointer to a function set by the low-level driver to be + * called when @use_count changed from 1 to 0. + * + * This is the main control data structure for a COMEDI device (as far as the + * COMEDI core is concerned). There are two groups of COMEDI devices - + * "legacy" devices that are configured by the handler for the + * %COMEDI_DEVCONFIG ioctl, and automatically configured devices resulting + * from a call to comedi_auto_config() as a result of a bus driver probe in + * a low-level COMEDI driver. The "legacy" COMEDI devices are allocated + * during module initialization if the "comedi_num_legacy_minors" module + * parameter is non-zero and use minor device numbers from 0 to + * comedi_num_legacy_minors minus one. The automatically configured COMEDI + * devices are allocated on demand and use minor device numbers from + * comedi_num_legacy_minors to 47. + */ struct comedi_device { int use_count; struct comedi_driver *driver; @@ -262,17 +531,14 @@ struct comedi_device { struct device *class_dev; int minor; unsigned int detach_count; - /* hw_dev is passed to dma_alloc_coherent when allocating async buffers - * for subdevices that have async_dma_dir set to something other than - * DMA_NONE */ struct device *hw_dev; const char *board_name; const void *board_ptr; bool attached:1; bool ioenabled:1; - spinlock_t spinlock; - struct mutex mutex; + spinlock_t spinlock; /* generic spin-lock for low-level driver */ + struct mutex mutex; /* generic mutex for COMEDI core */ struct rw_semaphore attach_lock; struct kref refcount; @@ -314,12 +580,12 @@ int comedi_check_chanlist(struct comedi_subdevice *s, /* range stuff */ -#define RANGE(a, b) {(a)*1e6, (b)*1e6, 0} -#define RANGE_ext(a, b) {(a)*1e6, (b)*1e6, RF_EXTERNAL} -#define RANGE_mA(a, b) {(a)*1e6, (b)*1e6, UNIT_mA} -#define RANGE_unitless(a, b) {(a)*1e6, (b)*1e6, 0} -#define BIP_RANGE(a) {-(a)*1e6, (a)*1e6, 0} -#define UNI_RANGE(a) {0, (a)*1e6, 0} +#define RANGE(a, b) {(a) * 1e6, (b) * 1e6, 0} +#define RANGE_ext(a, b) {(a) * 1e6, (b) * 1e6, RF_EXTERNAL} +#define RANGE_mA(a, b) {(a) * 1e6, (b) * 1e6, UNIT_mA} +#define RANGE_unitless(a, b) {(a) * 1e6, (b) * 1e6, 0} +#define BIP_RANGE(a) {-(a) * 1e6, (a) * 1e6, 0} +#define UNI_RANGE(a) {0, (a) * 1e6, 0} extern const struct comedi_lrange range_bipolar10; extern const struct comedi_lrange range_bipolar5; @@ -340,29 +606,101 @@ extern const struct comedi_lrange range_unknown; #define GCC_ZERO_LENGTH_ARRAY 0 #endif +/** + * struct comedi_lrange - Describes a COMEDI range table + * @length: Number of entries in the range table. + * @range: Array of &struct comedi_krange, one for each range. + * + * Each element of @range[] describes the minimum and maximum physical range + * range and the type of units. Typically, the type of unit is %UNIT_volt + * (i.e. volts) and the minimum and maximum are in millionths of a volt. + * There may also be a flag that indicates the minimum and maximum are merely + * scale factors for an unknown, external reference. + */ struct comedi_lrange { int length; struct comedi_krange range[GCC_ZERO_LENGTH_ARRAY]; }; +/** + * comedi_range_is_bipolar() - Test if subdevice range is bipolar + * @s: COMEDI subdevice. + * @range: Index of range within a range table. + * + * Tests whether a range is bipolar by checking whether its minimum value + * is negative. + * + * Assumes @range is valid. Does not work for subdevices using a + * channel-specific range table list. + * + * Return: + * %true if the range is bipolar. + * %false if the range is unipolar. + */ static inline bool comedi_range_is_bipolar(struct comedi_subdevice *s, unsigned int range) { return s->range_table->range[range].min < 0; } +/** + * comedi_range_is_unipolar() - Test if subdevice range is unipolar + * @s: COMEDI subdevice. + * @range: Index of range within a range table. + * + * Tests whether a range is unipolar by checking whether its minimum value + * is at least 0. + * + * Assumes @range is valid. Does not work for subdevices using a + * channel-specific range table list. + * + * Return: + * %true if the range is unipolar. + * %false if the range is bipolar. + */ static inline bool comedi_range_is_unipolar(struct comedi_subdevice *s, unsigned int range) { return s->range_table->range[range].min >= 0; } +/** + * comedi_range_is_external() - Test if subdevice range is external + * @s: COMEDI subdevice. + * @range: Index of range within a range table. + * + * Tests whether a range is externally reference by checking whether its + * %RF_EXTERNAL flag is set. + * + * Assumes @range is valid. Does not work for subdevices using a + * channel-specific range table list. + * + * Return: + * %true if the range is external. + * %false if the range is internal. + */ static inline bool comedi_range_is_external(struct comedi_subdevice *s, unsigned int range) { return !!(s->range_table->range[range].flags & RF_EXTERNAL); } +/** + * comedi_chan_range_is_bipolar() - Test if channel-specific range is bipolar + * @s: COMEDI subdevice. + * @chan: The channel number. + * @range: Index of range within a range table. + * + * Tests whether a range is bipolar by checking whether its minimum value + * is negative. + * + * Assumes @chan and @range are valid. Only works for subdevices with a + * channel-specific range table list. + * + * Return: + * %true if the range is bipolar. + * %false if the range is unipolar. + */ static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s, unsigned int chan, unsigned int range) @@ -370,6 +708,22 @@ static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s, return s->range_table_list[chan]->range[range].min < 0; } +/** + * comedi_chan_range_is_unipolar() - Test if channel-specific range is unipolar + * @s: COMEDI subdevice. + * @chan: The channel number. + * @range: Index of range within a range table. + * + * Tests whether a range is unipolar by checking whether its minimum value + * is at least 0. + * + * Assumes @chan and @range are valid. Only works for subdevices with a + * channel-specific range table list. + * + * Return: + * %true if the range is unipolar. + * %false if the range is bipolar. + */ static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s, unsigned int chan, unsigned int range) @@ -377,6 +731,22 @@ static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s, return s->range_table_list[chan]->range[range].min >= 0; } +/** + * comedi_chan_range_is_external() - Test if channel-specific range is external + * @s: COMEDI subdevice. + * @chan: The channel number. + * @range: Index of range within a range table. + * + * Tests whether a range is externally reference by checking whether its + * %RF_EXTERNAL flag is set. + * + * Assumes @chan and @range are valid. Only works for subdevices with a + * channel-specific range table list. + * + * Return: + * %true if the range is bipolar. + * %false if the range is unipolar. + */ static inline bool comedi_chan_range_is_external(struct comedi_subdevice *s, unsigned int chan, unsigned int range) @@ -384,7 +754,16 @@ static inline bool comedi_chan_range_is_external(struct comedi_subdevice *s, return !!(s->range_table_list[chan]->range[range].flags & RF_EXTERNAL); } -/* munge between offset binary and two's complement values */ +/** + * comedi_offset_munge() - Convert between offset binary and 2's complement + * @s: COMEDI subdevice. + * @val: Value to be converted. + * + * Toggles the highest bit of a sample value to toggle between offset binary + * and 2's complement. Assumes that @s->maxdata is a power of 2 minus 1. + * + * Return: The converted value. + */ static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, unsigned int val) { @@ -392,13 +771,13 @@ static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, } /** - * comedi_bytes_per_sample - determine subdevice sample size - * @s: comedi_subdevice struct + * comedi_bytes_per_sample() - Determine subdevice sample size + * @s: COMEDI subdevice. * * The sample size will be 4 (sizeof int) or 2 (sizeof short) depending on - * whether the SDF_LSAMPL subdevice flag is set or not. + * whether the %SDF_LSAMPL subdevice flag is set or not. * - * Returns the subdevice sample size. + * Return: The subdevice sample size. */ static inline unsigned int comedi_bytes_per_sample(struct comedi_subdevice *s) { @@ -406,15 +785,15 @@ static inline unsigned int comedi_bytes_per_sample(struct comedi_subdevice *s) } /** - * comedi_sample_shift - determine log2 of subdevice sample size - * @s: comedi_subdevice struct + * comedi_sample_shift() - Determine log2 of subdevice sample size + * @s: COMEDI subdevice. * * 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 + * 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. + * Return: log2 of the subdevice sample size. */ static inline unsigned int comedi_sample_shift(struct comedi_subdevice *s) { @@ -422,11 +801,11 @@ static inline unsigned int comedi_sample_shift(struct comedi_subdevice *s) } /** - * comedi_bytes_to_samples - converts a number of bytes to a number of samples - * @s: comedi_subdevice struct - * @nbytes: number of bytes + * comedi_bytes_to_samples() - Convert a number of bytes to a number of samples + * @s: COMEDI subdevice. + * @nbytes: Number of bytes * - * Returns the number of bytes divided by the subdevice sample size. + * Return: 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) @@ -435,12 +814,12 @@ static inline unsigned int comedi_bytes_to_samples(struct comedi_subdevice *s, } /** - * comedi_samples_to_bytes - converts a number of samples to a number of bytes - * @s: comedi_subdevice struct - * @nsamples: number of samples + * comedi_samples_to_bytes() - Convert a number of samples to a number of bytes + * @s: COMEDI subdevice. + * @nsamples: Number of samples. * - * Returns the number of samples multiplied by the subdevice sample size. - * Does not check for arithmetic overflow. + * Return: 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) @@ -449,14 +828,18 @@ static inline unsigned int comedi_samples_to_bytes(struct comedi_subdevice *s, } /** - * comedi_check_trigger_src() - trivially validate a comedi_cmd trigger source - * @src: pointer to the trigger source to validate - * @flags: bitmask of valid TRIG_* for the trigger + * comedi_check_trigger_src() - Trivially validate a comedi_cmd trigger source + * @src: Pointer to the trigger source to validate. + * @flags: Bitmask of valid %TRIG_* for the trigger. * * This is used in "step 1" of the do_cmdtest functions of comedi drivers - * to vaildate the comedi_cmd triggers. The mask of the @src against the + * to validate the comedi_cmd triggers. The mask of the @src against the * @flags allows the userspace comedilib to pass all the comedi_cmd - * triggers as TRIG_ANY and get back a bitmask of the valid trigger sources. + * triggers as %TRIG_ANY and get back a bitmask of the valid trigger sources. + * + * Return: + * 0 if trigger sources in *@src are all supported. + * -EINVAL if any trigger source in *@src is unsupported. */ static inline int comedi_check_trigger_src(unsigned int *src, unsigned int flags) @@ -470,8 +853,12 @@ static inline int comedi_check_trigger_src(unsigned int *src, } /** - * comedi_check_trigger_is_unique() - make sure a trigger source is unique - * @src: the trigger source to check + * comedi_check_trigger_is_unique() - Make sure a trigger source is unique + * @src: The trigger source to check. + * + * Return: + * 0 if no more than one trigger source is set. + * -EINVAL if more than one trigger source is set. */ static inline int comedi_check_trigger_is_unique(unsigned int src) { @@ -482,9 +869,15 @@ static inline int comedi_check_trigger_is_unique(unsigned int src) } /** - * comedi_check_trigger_arg_is() - trivially validate a trigger argument - * @arg: pointer to the trigger arg to validate - * @val: the value the argument should be + * comedi_check_trigger_arg_is() - Trivially validate a trigger argument + * @arg: Pointer to the trigger arg to validate. + * @val: The value the argument should be. + * + * Forces *@arg to be @val. + * + * Return: + * 0 if *@arg was already @val. + * -EINVAL if *@arg differed from @val. */ static inline int comedi_check_trigger_arg_is(unsigned int *arg, unsigned int val) @@ -497,9 +890,15 @@ static inline int comedi_check_trigger_arg_is(unsigned int *arg, } /** - * comedi_check_trigger_arg_min() - trivially validate a trigger argument - * @arg: pointer to the trigger arg to validate - * @val: the minimum value the argument should be + * comedi_check_trigger_arg_min() - Trivially validate a trigger argument min + * @arg: Pointer to the trigger arg to validate. + * @val: The minimum value the argument should be. + * + * Forces *@arg to be at least @val, setting it to @val if necessary. + * + * Return: + * 0 if *@arg was already at least @val. + * -EINVAL if *@arg was less than @val. */ static inline int comedi_check_trigger_arg_min(unsigned int *arg, unsigned int val) @@ -512,9 +911,15 @@ static inline int comedi_check_trigger_arg_min(unsigned int *arg, } /** - * comedi_check_trigger_arg_max() - trivially validate a trigger argument - * @arg: pointer to the trigger arg to validate - * @val: the maximum value the argument should be + * comedi_check_trigger_arg_max() - Trivially validate a trigger argument max + * @arg: Pointer to the trigger arg to validate. + * @val: The maximum value the argument should be. + * + * Forces *@arg to be no more than @val, setting it to @val if necessary. + * + * Return: + * 0 if*@arg was already no more than @val. + * -EINVAL if *@arg was greater than @val. */ static inline int comedi_check_trigger_arg_max(unsigned int *arg, unsigned int val) @@ -534,6 +939,16 @@ static inline int comedi_check_trigger_arg_max(unsigned int *arg, */ int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev); +/** + * comedi_buf_n_bytes_ready - Determine amount of unread data in buffer + * @s: COMEDI subdevice. + * + * Determines the number of bytes of unread data in the asynchronous + * acquisition data buffer for a subdevice. The data in question might not + * have been fully "munged" yet. + * + * Returns: The amount of unread data in bytes. + */ static inline unsigned int comedi_buf_n_bytes_ready(struct comedi_subdevice *s) { return s->async->buf_write_count - s->async->buf_read_count; diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 680cd2291..fc153c705 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -1,37 +1,29 @@ /* - module/drivers.c - functions for manipulating drivers - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-2000 David A. Schleef - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * module/drivers.c + * functions for manipulating drivers + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include #include #include -#include #include -#include -#include #include -#include #include -#include /* for SuSE brokenness */ -#include -#include -#include -#include +#include #include #include @@ -42,6 +34,28 @@ struct comedi_driver *comedi_drivers; /* protects access to comedi_drivers */ DEFINE_MUTEX(comedi_drivers_list_lock); +/** + * comedi_set_hw_dev() - Set hardware device associated with COMEDI device + * @dev: COMEDI device. + * @hw_dev: Hardware device. + * + * For automatically configured COMEDI devices (resulting from a call to + * comedi_auto_config() or one of its wrappers from the low-level COMEDI + * driver), comedi_set_hw_dev() is called automatically by the COMEDI core + * to associate the COMEDI device with the hardware device. It can also be + * called directly by "legacy" low-level COMEDI drivers that rely on the + * %COMEDI_DEVCONFIG ioctl to configure the hardware as long as the hardware + * has a &struct device. + * + * If @dev->hw_dev is NULL, it gets a reference to @hw_dev and sets + * @dev->hw_dev, otherwise, it does nothing. Calling it multiple times + * with the same hardware device is not considered an error. If it gets + * a reference to the hardware device, it will be automatically 'put' when + * the device is detached from COMEDI. + * + * Returns 0 if @dev->hw_dev was NULL or the same as @hw_dev, otherwise + * returns -EEXIST. + */ int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev) { if (hw_dev == dev->hw_dev) @@ -60,9 +74,15 @@ static void comedi_clear_hw_dev(struct comedi_device *dev) } /** - * comedi_alloc_devpriv() - Allocate memory for the device private data. - * @dev: comedi_device struct - * @size: size of the memory to allocate + * comedi_alloc_devpriv() - Allocate memory for the device private data + * @dev: COMEDI device. + * @size: Size of the memory to allocate. + * + * The allocated memory is zero-filled. @dev->private points to it on + * return. The memory will be automatically freed when the COMEDI device is + * "detached". + * + * Returns a pointer to the allocated memory, or NULL on failure. */ void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size) { @@ -71,6 +91,18 @@ void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size) } EXPORT_SYMBOL_GPL(comedi_alloc_devpriv); +/** + * comedi_alloc_subdevices() - Allocate subdevices for COMEDI device + * @dev: COMEDI device. + * @num_subdevices: Number of subdevices to allocate. + * + * Allocates and initializes an array of &struct comedi_subdevice for the + * COMEDI device. If successful, sets @dev->subdevices to point to the + * first one and @dev->n_subdevices to the number. + * + * Returns 0 on success, -EINVAL if @num_subdevices is < 1, or -ENOMEM if + * failed to allocate the memory. + */ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) { struct comedi_subdevice *s; @@ -98,8 +130,22 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) EXPORT_SYMBOL_GPL(comedi_alloc_subdevices); /** - * comedi_alloc_subdev_readback() - Allocate memory for the subdevice readback. - * @s: comedi_subdevice struct + * comedi_alloc_subdev_readback() - Allocate memory for the subdevice readback + * @s: COMEDI subdevice. + * + * This is called by low-level COMEDI drivers to allocate an array to record + * the last values written to a subdevice's analog output channels (at least + * by the %INSN_WRITE instruction), to allow them to be read back by an + * %INSN_READ instruction. It also provides a default handler for the + * %INSN_READ instruction unless one has already been set. + * + * On success, @s->readback points to the first element of the array, which + * is zero-filled. The low-level driver is responsible for updating its + * contents. @s->insn_read will be set to comedi_readback_insn_read() + * unless it is already non-NULL. + * + * Returns 0 on success, -EINVAL if the subdevice has no channels, or + * -ENOMEM on allocation failure. */ int comedi_alloc_subdev_readback(struct comedi_subdevice *s) { @@ -182,10 +228,20 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, /** * comedi_readback_insn_read() - A generic (*insn_read) for subdevice readback. - * @dev: comedi_device struct - * @s: comedi_subdevice struct - * @insn: comedi_insn struct - * @data: pointer to return the readback data + * @dev: COMEDI device. + * @s: COMEDI subdevice. + * @insn: COMEDI instruction. + * @data: Pointer to return the readback data. + * + * Handles the %INSN_READ instruction for subdevices that use the readback + * array allocated by comedi_alloc_subdev_readback(). It may be used + * directly as the subdevice's handler (@s->insn_read) or called via a + * wrapper. + * + * @insn->n is normally 1, which will read a single value. If higher, the + * same element of the readback array will be read multiple times. + * + * Returns @insn->n on success, or -EINVAL if @s->readback is NULL. */ int comedi_readback_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, @@ -206,12 +262,21 @@ int comedi_readback_insn_read(struct comedi_device *dev, EXPORT_SYMBOL_GPL(comedi_readback_insn_read); /** - * comedi_timeout() - busy-wait for a driver condition to occur. - * @dev: comedi_device struct - * @s: comedi_subdevice struct - * @insn: comedi_insn struct - * @cb: callback to check for the condition - * @context: private context from the driver + * comedi_timeout() - Busy-wait for a driver condition to occur + * @dev: COMEDI device. + * @s: COMEDI subdevice. + * @insn: COMEDI instruction. + * @cb: Callback to check for the condition. + * @context: Private context from the driver. + * + * Busy-waits for up to a second (%COMEDI_TIMEOUT_MS) for the condition or + * some error (other than -EBUSY) to occur. The parameters @dev, @s, @insn, + * and @context are passed to the callback function, which returns -EBUSY to + * continue waiting or some other value to stop waiting (generally 0 if the + * condition occurred, or some error value). + * + * Returns -ETIMEDOUT if timed out, otherwise the return value from the + * callback function. */ int comedi_timeout(struct comedi_device *dev, struct comedi_subdevice *s, @@ -236,12 +301,30 @@ int comedi_timeout(struct comedi_device *dev, EXPORT_SYMBOL_GPL(comedi_timeout); /** - * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices. - * @dev: comedi_device struct - * @s: comedi_subdevice struct - * @insn: comedi_insn struct - * @data: parameters for the @insn - * @mask: io_bits mask for grouped channels + * comedi_dio_insn_config() - Boilerplate (*insn_config) for DIO subdevices + * @dev: COMEDI device. + * @s: COMEDI subdevice. + * @insn: COMEDI instruction. + * @data: Instruction parameters and return data. + * @mask: io_bits mask for grouped channels, or 0 for single channel. + * + * If @mask is 0, it is replaced with a single-bit mask corresponding to the + * channel number specified by @insn->chanspec. Otherwise, @mask + * corresponds to a group of channels (which should include the specified + * channel) that are always configured together as inputs or outputs. + * + * Partially handles the %INSN_CONFIG_DIO_INPUT, %INSN_CONFIG_DIO_OUTPUTS, + * and %INSN_CONFIG_DIO_QUERY instructions. The first two update + * @s->io_bits to record the directions of the masked channels. The last + * one sets @data[1] to the current direction of the group of channels + * (%COMEDI_INPUT) or %COMEDI_OUTPUT) as recorded in @s->io_bits. + * + * The caller is responsible for updating the DIO direction in the hardware + * registers if this function returns 0. + * + * Returns 0 for a %INSN_CONFIG_DIO_INPUT or %INSN_CONFIG_DIO_OUTPUT + * instruction, @insn->n (> 0) for a %INSN_CONFIG_DIO_QUERY instruction, or + * -EINVAL for some other instruction. */ int comedi_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, @@ -276,9 +359,18 @@ int comedi_dio_insn_config(struct comedi_device *dev, EXPORT_SYMBOL_GPL(comedi_dio_insn_config); /** - * comedi_dio_update_state() - update the internal state of DIO subdevices. - * @s: comedi_subdevice struct - * @data: the channel mask and bits to update + * comedi_dio_update_state() - Update the internal state of DIO subdevices + * @s: COMEDI subdevice. + * @data: The channel mask and bits to update. + * + * Updates @s->state which holds the internal state of the outputs for DIO + * or DO subdevices (up to 32 channels). @data[0] contains a bit-mask of + * the channels to be updated. @data[1] contains a bit-mask of those + * channels to be set to '1'. The caller is responsible for updating the + * outputs in hardware according to @s->state. As a minimum, the channels + * in the returned bit-mask need to be updated. + * + * Returns @mask with non-existent channels removed. */ unsigned int comedi_dio_update_state(struct comedi_subdevice *s, unsigned int *data) @@ -298,17 +390,17 @@ unsigned int comedi_dio_update_state(struct comedi_subdevice *s, EXPORT_SYMBOL_GPL(comedi_dio_update_state); /** - * comedi_bytes_per_scan - get length of asynchronous command "scan" in bytes - * @s: comedi_subdevice struct + * comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes + * @s: COMEDI subdevice. * * Determines the overall scan length according to the subdevice type and the * number of channels in the scan. * - * For digital input, output or input/output subdevices, samples for multiple - * channels are assumed to be packed into one or more unsigned short or - * unsigned int values according to the subdevice's SDF_LSAMPL flag. For other - * types of subdevice, samples are assumed to occupy a whole unsigned short or - * unsigned int according to the SDF_LSAMPL flag. + * For digital input, output or input/output subdevices, samples for + * multiple channels are assumed to be packed into one or more unsigned + * short or unsigned int values according to the subdevice's %SDF_LSAMPL + * flag. For other types of subdevice, samples are assumed to occupy a + * whole unsigned short or unsigned int according to the %SDF_LSAMPL flag. * * Returns the overall scan length in bytes. */ @@ -333,32 +425,12 @@ unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s) } 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) +static 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; @@ -370,15 +442,40 @@ unsigned int comedi_nscans_left(struct comedi_subdevice *s, } return nscans; } + +/** + * comedi_nscans_left() - Return the number of scans left in the command + * @s: COMEDI subdevice. + * @nscans: The expected number of scans or 0 for all available scans. + * + * If @nscans is 0, it is set to the number of scans available in the + * async buffer. + * + * If the async command has a stop_src of %TRIG_COUNT, the @nscans will be + * checked against the number of scans remaining to complete the command. + * + * The return value will then be either the expected number of scans or the + * number of scans remaining to complete the command, whichever is fewer. + */ +unsigned int comedi_nscans_left(struct comedi_subdevice *s, + unsigned int nscans) +{ + if (nscans == 0) { + unsigned int nbytes = comedi_buf_read_n_available(s); + + nscans = nbytes / comedi_bytes_per_scan(s); + } + return __comedi_nscans_left(s, 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 + * comedi_nsamples_left() - Return the number of samples left in the command + * @s: COMEDI subdevice. + * @nsamples: The expected number of samples. * - * Returns the expected number of samples of the number of samples remaining - * in the command. + * Returns the number of samples remaining to complete the command, or the + * specified expected number of samples (@nsamples), whichever is fewer. */ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, unsigned int nsamples) @@ -387,9 +484,8 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, 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 nscans = nsamples / cmd->scan_end_arg; + 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; @@ -407,14 +503,14 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, 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 + * comedi_inc_scan_progress() - Update scan progress in asynchronous command + * @s: COMEDI subdevice. + * @num_bytes: Amount of data in bytes to increment scan progress. * - * Increments the scan progress by the number of bytes specified by num_bytes. + * Increments the scan progress by the number of bytes specified by @num_bytes. * If the scan progress reaches or exceeds the scan length in bytes, reduce * it modulo the scan length in bytes and set the "end of scan" asynchronous - * event flag to be processed later. + * event flag (%COMEDI_CB_EOS) to be processed later. */ void comedi_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes) @@ -445,12 +541,12 @@ void comedi_inc_scan_progress(struct comedi_subdevice *s, EXPORT_SYMBOL_GPL(comedi_inc_scan_progress); /** - * comedi_handle_events - handle events and possibly stop acquisition - * @dev: comedi_device struct - * @s: comedi_subdevice struct + * comedi_handle_events() - Handle events and possibly stop acquisition + * @dev: COMEDI device. + * @s: COMEDI subdevice. * * Handles outstanding asynchronous acquisition event flags associated - * with the subdevice. Call the subdevice's "->cancel()" handler if the + * with the subdevice. Call the subdevice's @s->cancel() handler if the * "end of acquisition", "error" or "overflow" event flags are set in order * to stop the acquisition at the driver level. * @@ -685,12 +781,19 @@ static void comedi_report_boards(struct comedi_driver *driv) } /** - * comedi_load_firmware() - Request and load firmware for a device. - * @dev: comedi_device struct - * @hw_device: device struct for the comedi_device - * @name: the name of the firmware image - * @cb: callback to the upload the firmware image - * @context: private context from the driver + * comedi_load_firmware() - Request and load firmware for a device + * @dev: COMEDI device. + * @device: Hardware device. + * @name: The name of the firmware image. + * @cb: Callback to the upload the firmware image. + * @context: Private context from the driver. + * + * Sends a firmware request for the hardware device and waits for it. Calls + * the callback function to upload the firmware to the device, them releases + * the firmware. + * + * Returns 0 on success, -EINVAL if @cb is NULL, or a negative error number + * from the firmware request or the callback function. */ int comedi_load_firmware(struct comedi_device *dev, struct device *device, @@ -717,10 +820,16 @@ int comedi_load_firmware(struct comedi_device *dev, EXPORT_SYMBOL_GPL(comedi_load_firmware); /** - * __comedi_request_region() - Request an I/O reqion for a legacy driver. - * @dev: comedi_device struct - * @start: base address of the I/O reqion - * @len: length of the I/O region + * __comedi_request_region() - Request an I/O region for a legacy driver + * @dev: COMEDI device. + * @start: Base address of the I/O region. + * @len: Length of the I/O region. + * + * Requests the specified I/O port region which must start at a non-zero + * address. + * + * Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request + * fails. */ int __comedi_request_region(struct comedi_device *dev, unsigned long start, unsigned long len) @@ -743,10 +852,19 @@ int __comedi_request_region(struct comedi_device *dev, EXPORT_SYMBOL_GPL(__comedi_request_region); /** - * comedi_request_region() - Request an I/O reqion for a legacy driver. - * @dev: comedi_device struct - * @start: base address of the I/O reqion - * @len: length of the I/O region + * comedi_request_region() - Request an I/O region for a legacy driver + * @dev: COMEDI device. + * @start: Base address of the I/O region. + * @len: Length of the I/O region. + * + * Requests the specified I/O port region which must start at a non-zero + * address. + * + * On success, @dev->iobase is set to the base address of the region and + * @dev->iolen is set to its length. + * + * Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request + * fails. */ int comedi_request_region(struct comedi_device *dev, unsigned long start, unsigned long len) @@ -764,8 +882,16 @@ int comedi_request_region(struct comedi_device *dev, EXPORT_SYMBOL_GPL(comedi_request_region); /** - * comedi_legacy_detach() - A generic (*detach) function for legacy drivers. - * @dev: comedi_device struct + * comedi_legacy_detach() - A generic (*detach) function for legacy drivers + * @dev: COMEDI device. + * + * This is a simple, generic 'detach' handler for legacy COMEDI devices that + * just use a single I/O port region and possibly an IRQ and that don't need + * any special clean-up for their private device or subdevice storage. It + * can also be called by a driver-specific 'detach' handler. + * + * If @dev->irq is non-zero, the IRQ will be freed. If @dev->iobase and + * @dev->iolen are both non-zero, the I/O port region will be released. */ void comedi_legacy_detach(struct comedi_device *dev) { @@ -839,6 +965,29 @@ out: return ret; } +/** + * comedi_auto_config() - Create a COMEDI device for a hardware device + * @hardware_device: Hardware device. + * @driver: COMEDI low-level driver for the hardware device. + * @context: Driver context for the auto_attach handler. + * + * Allocates a new COMEDI device for the hardware device and calls the + * low-level driver's 'auto_attach' handler to set-up the hardware and + * allocate the COMEDI subdevices. Additional "post-configuration" setting + * up is performed on successful return from the 'auto_attach' handler. + * If the 'auto_attach' handler fails, the low-level driver's 'detach' + * handler will be called as part of the clean-up. + * + * This is usually called from a wrapper function in a bus-specific COMEDI + * module, which in turn is usually called from a bus device 'probe' + * function in the low-level driver. + * + * Returns 0 on success, -EINVAL if the parameters are invalid or the + * post-configuration determines the driver has set the COMEDI device up + * incorrectly, -ENOMEM if failed to allocate memory, -EBUSY if run out of + * COMEDI minor device numbers, or some negative error number returned by + * the driver's 'auto_attach' handler. + */ int comedi_auto_config(struct device *hardware_device, struct comedi_driver *driver, unsigned long context) { @@ -896,6 +1045,22 @@ int comedi_auto_config(struct device *hardware_device, } EXPORT_SYMBOL_GPL(comedi_auto_config); +/** + * comedi_auto_unconfig() - Unconfigure auto-allocated COMEDI device + * @hardware_device: Hardware device previously passed to + * comedi_auto_config(). + * + * Cleans up and eventually destroys the COMEDI device allocated by + * comedi_auto_config() for the same hardware device. As part of this + * clean-up, the low-level COMEDI driver's 'detach' handler will be called. + * (The COMEDI device itself will persist in an unattached state if it is + * still open, until it is released, and any mmapped buffers will persist + * until they are munmapped.) + * + * This is usually called from a wrapper module in a bus-specific COMEDI + * module, which in turn is usually set as the bus device 'remove' function + * in the low-level COMEDI driver. + */ void comedi_auto_unconfig(struct device *hardware_device) { if (!hardware_device) @@ -904,6 +1069,17 @@ void comedi_auto_unconfig(struct device *hardware_device) } EXPORT_SYMBOL_GPL(comedi_auto_unconfig); +/** + * comedi_driver_register() - Register a low-level COMEDI driver + * @driver: Low-level COMEDI driver. + * + * The low-level COMEDI driver is added to the list of registered COMEDI + * drivers. This is used by the handler for the "/proc/comedi" file and is + * also used by the handler for the %COMEDI_DEVCONFIG ioctl to configure + * "legacy" COMEDI devices (for those low-level drivers that support it). + * + * Returns 0. + */ int comedi_driver_register(struct comedi_driver *driver) { mutex_lock(&comedi_drivers_list_lock); @@ -915,6 +1091,15 @@ int comedi_driver_register(struct comedi_driver *driver) } EXPORT_SYMBOL_GPL(comedi_driver_register); +/** + * comedi_driver_unregister() - Unregister a low-level COMEDI driver + * @driver: Low-level COMEDI driver. + * + * The low-level COMEDI driver is removed from the list of registered COMEDI + * drivers. Detaches any COMEDI devices attached to the driver, which will + * result in the low-level driver's 'detach' handler being called for those + * devices before this function returns. + */ void comedi_driver_unregister(struct comedi_driver *driver) { struct comedi_driver *prev; diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index 41823de69..55a67af51 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -25,13 +25,13 @@ #define I8255_DATA_B_REG 0x01 #define I8255_DATA_C_REG 0x02 #define I8255_CTRL_REG 0x03 -#define I8255_CTRL_C_LO_IO (1 << 0) -#define I8255_CTRL_B_IO (1 << 1) -#define I8255_CTRL_B_MODE (1 << 2) -#define I8255_CTRL_C_HI_IO (1 << 3) -#define I8255_CTRL_A_IO (1 << 4) +#define I8255_CTRL_C_LO_IO BIT(0) +#define I8255_CTRL_B_IO BIT(1) +#define I8255_CTRL_B_MODE BIT(2) +#define I8255_CTRL_C_HI_IO BIT(3) +#define I8255_CTRL_A_IO BIT(4) #define I8255_CTRL_A_MODE(x) ((x) << 5) -#define I8255_CTRL_CW (1 << 7) +#define I8255_CTRL_CW BIT(7) struct comedi_device; struct comedi_subdevice; diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index bb9854b56..38c05d1ec 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -178,8 +178,8 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { }; /* ripped from mite.h and mite_setup2() to avoid mite dependency */ -#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */ -#define WENAB (1 << 7) /* window enable */ +#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */ +#define WENAB BIT(7) /* window enable */ static int pci_8255_mite_init(struct pci_dev *pcidev) { diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 5764dc9a6..c3b8f2d76 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -90,7 +90,6 @@ obj-$(CONFIG_COMEDI_CONTEC_PCI_DIO) += contec_pci_dio.o obj-$(CONFIG_COMEDI_DAS08_PCI) += das08_pci.o obj-$(CONFIG_COMEDI_DT3000) += dt3000.o obj-$(CONFIG_COMEDI_DYNA_PCI10XX) += dyna_pci10xx.o -obj-$(CONFIG_COMEDI_UNIOXX5) += unioxx5.o obj-$(CONFIG_COMEDI_GSC_HPDI) += gsc_hpdi.o obj-$(CONFIG_COMEDI_ICP_MULTI) += icp_multi.o obj-$(CONFIG_COMEDI_DAQBOARD2000) += daqboard2000.o diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index b37166d57..ccd1a9129 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -84,9 +84,10 @@ #define APCI1032_MODE2_REG 0x08 #define APCI1032_STATUS_REG 0x0c #define APCI1032_CTRL_REG 0x10 -#define APCI1032_CTRL_INT_OR (0 << 1) -#define APCI1032_CTRL_INT_AND (1 << 1) -#define APCI1032_CTRL_INT_ENA (1 << 2) +#define APCI1032_CTRL_INT_MODE(x) (((x) & 0x1) << 1) +#define APCI1032_CTRL_INT_OR APCI1032_CTRL_INT_MODE(0) +#define APCI1032_CTRL_INT_AND APCI1032_CTRL_INT_MODE(1) +#define APCI1032_CTRL_INT_ENA BIT(2) struct apci1032_private { unsigned long amcc_iobase; /* base of AMCC I/O registers */ diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index ad715253b..50f9eb25d 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -34,19 +34,19 @@ */ #define APCI2032_DO_REG 0x00 #define APCI2032_INT_CTRL_REG 0x04 -#define APCI2032_INT_CTRL_VCC_ENA (1 << 0) -#define APCI2032_INT_CTRL_CC_ENA (1 << 1) +#define APCI2032_INT_CTRL_VCC_ENA BIT(0) +#define APCI2032_INT_CTRL_CC_ENA BIT(1) #define APCI2032_INT_STATUS_REG 0x08 -#define APCI2032_INT_STATUS_VCC (1 << 0) -#define APCI2032_INT_STATUS_CC (1 << 1) +#define APCI2032_INT_STATUS_VCC BIT(0) +#define APCI2032_INT_STATUS_CC BIT(1) #define APCI2032_STATUS_REG 0x0c -#define APCI2032_STATUS_IRQ (1 << 0) +#define APCI2032_STATUS_IRQ BIT(0) #define APCI2032_WDOG_REG 0x10 struct apci2032_int_private { - spinlock_t spinlock; - bool active; - unsigned char enabled_isns; + spinlock_t spinlock; /* protects the following members */ + bool active; /* an async command is running */ + unsigned char enabled_isns; /* mask of enabled interrupt channels */ }; static int apci2032_do_insn_bits(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 5bfd43d5c..3630d75e3 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -31,33 +31,33 @@ * 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) +#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 BIT(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_EXT_TRIG BIT(15) +#define APCI3120_CTRL_GATE(x) BIT(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_EOC_INT BIT(15) +#define APCI3120_STATUS_AMCC_INT BIT(14) +#define APCI3120_STATUS_EOS_INT BIT(13) +#define APCI3120_STATUS_TIMER2_INT BIT(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_STATUS_FIFO_FULL BIT(2) +#define APCI3120_STATUS_FIFO_EMPTY BIT(1) +#define APCI3120_STATUS_DA_READY BIT(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_UNIPOLAR BIT(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)) @@ -74,19 +74,21 @@ #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) +#define APCI3120_MODE_TIMER2_CLK(x) (((x) & 0x3) << 6) +#define APCI3120_MODE_TIMER2_CLK_OSC APCI3120_MODE_TIMER2_CLK(0) +#define APCI3120_MODE_TIMER2_CLK_OUT1 APCI3120_MODE_TIMER2_CLK(1) +#define APCI3120_MODE_TIMER2_CLK_EOC APCI3120_MODE_TIMER2_CLK(2) +#define APCI3120_MODE_TIMER2_CLK_EOS APCI3120_MODE_TIMER2_CLK(3) +#define APCI3120_MODE_TIMER2_CLK_MASK APCI3120_MODE_TIMER2_CLK(3) +#define APCI3120_MODE_TIMER2_AS(x) (((x) & 0x3) << 4) +#define APCI3120_MODE_TIMER2_AS_TIMER APCI3120_MODE_TIMER2_AS(0) +#define APCI3120_MODE_TIMER2_AS_COUNTER APCI3120_MODE_TIMER2_AS(1) +#define APCI3120_MODE_TIMER2_AS_WDOG APCI3120_MODE_TIMER2_AS(2) +#define APCI3120_MODE_TIMER2_AS_MASK APCI3120_MODE_TIMER2_AS(3) +#define APCI3120_MODE_SCAN_ENA BIT(3) +#define APCI3120_MODE_TIMER2_IRQ_ENA BIT(2) +#define APCI3120_MODE_EOS_IRQ_ENA BIT(1) +#define APCI3120_MODE_EOC_IRQ_ENA BIT(0) /* * PCI BAR 2 register map (devpriv->addon) @@ -94,8 +96,8 @@ #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) +#define APCI3120_ADDON_CTRL_AMWEN_ENA BIT(1) +#define APCI3120_ADDON_CTRL_A2P_FIFO_ENA BIT(0) /* * Board revisions @@ -502,11 +504,6 @@ static irqreturn_t apci3120_interrupt(int irq, void *d) 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; diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index bef6efc84..995096c78 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -27,9 +27,9 @@ #include "../comedi_pci.h" -#define CONV_UNIT_NS (1 << 0) -#define CONV_UNIT_US (1 << 1) -#define CONV_UNIT_MS (1 << 2) +#define CONV_UNIT_NS BIT(0) +#define CONV_UNIT_US BIT(1) +#define CONV_UNIT_MS BIT(2) static const struct comedi_lrange apci3xxx_ai_range = { 8, { diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 7ed3fd6fb..ad7e7c4a5 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -41,7 +41,7 @@ */ #define PCI6208_AO_CONTROL(x) (0x00 + (2 * (x))) #define PCI6208_AO_STATUS 0x00 -#define PCI6208_AO_STATUS_DATA_SEND (1 << 0) +#define PCI6208_AO_STATUS_DATA_SEND BIT(0) #define PCI6208_DIO 0x40 #define PCI6208_DIO_DO_MASK (0x0f) #define PCI6208_DIO_DO_SHIFT (0) diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index c9df3afe9..01d2ee931 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -1,68 +1,52 @@ /* - -comedi/drivers/adl_pci9111.c - -Hardware driver for PCI9111 ADLink cards: - -PCI-9111HR - -Copyright (C) 2002-2005 Emmanuel Pacaud - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -*/ + * adl_pci9111.c + * Hardware driver for PCI9111 ADLink cards: PCI-9111HR + * Copyright (C) 2002-2005 Emmanuel Pacaud + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: adl_pci9111 -Description: Adlink PCI-9111HR -Author: Emmanuel Pacaud -Devices: [ADLink] PCI-9111HR (adl_pci9111) -Status: experimental - -Supports: - - - ai_insn read - - ao_insn read/write - - di_insn read - - do_insn read/write - - ai_do_cmd mode with the following sources: - - - start_src TRIG_NOW - - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT - - convert_src TRIG_TIMER TRIG_EXT - - scan_end_src TRIG_COUNT - - stop_src TRIG_COUNT TRIG_NONE - -The scanned channels must be consecutive and start from 0. They must -all have the same range and aref. - -Configuration options: not applicable, uses PCI auto config -*/ + * Driver: adl_pci9111 + * Description: Adlink PCI-9111HR + * Devices: [ADLink] PCI-9111HR (adl_pci9111) + * Author: Emmanuel Pacaud + * Status: experimental + * + * Configuration options: not applicable, uses PCI auto config + * + * Supports: + * - ai_insn read + * - ao_insn read/write + * - di_insn read + * - do_insn read/write + * - ai_do_cmd mode with the following sources: + * - start_src TRIG_NOW + * - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT + * - convert_src TRIG_TIMER TRIG_EXT + * - scan_end_src TRIG_COUNT + * - stop_src TRIG_COUNT TRIG_NONE + * + * The scanned channels must be consecutive and start from 0. They must + * all have the same range and aref. + */ /* -CHANGELOG: - -2005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be -a multiple of chanlist_len*convert_arg. -2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data. -2002/02/18 Added external trigger support for analog input. - -TODO: - - - Really test implemented functionality. - - Add support for the PCI-9111DG with a probe routine to identify - the card type (perhaps with the help of the channel number readback - of the A/D Data register). - - Add external multiplexer support. - -*/ + * TODO: + * - Really test implemented functionality. + * - Add support for the PCI-9111DG with a probe routine to identify + * the card type (perhaps with the help of the channel number readback + * of the A/D Data register). + * - Add external multiplexer support. + */ #include #include @@ -89,23 +73,24 @@ TODO: #define PCI9111_EDIO_REG 0x04 #define PCI9111_AI_CHANNEL_REG 0x06 #define PCI9111_AI_RANGE_STAT_REG 0x08 -#define PCI9111_AI_STAT_AD_BUSY (1 << 7) -#define PCI9111_AI_STAT_FF_FF (1 << 6) -#define PCI9111_AI_STAT_FF_HF (1 << 5) -#define PCI9111_AI_STAT_FF_EF (1 << 4) -#define PCI9111_AI_RANGE_MASK (7 << 0) +#define PCI9111_AI_STAT_AD_BUSY BIT(7) +#define PCI9111_AI_STAT_FF_FF BIT(6) +#define PCI9111_AI_STAT_FF_HF BIT(5) +#define PCI9111_AI_STAT_FF_EF BIT(4) +#define PCI9111_AI_RANGE(x) (((x) & 0x7) << 0) +#define PCI9111_AI_RANGE_MASK PCI9111_AI_RANGE(7) #define PCI9111_AI_TRIG_CTRL_REG 0x0a -#define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5) -#define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4) -#define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3) -#define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2) -#define PCI9111_AI_TRIG_CTRL_TPST (1 << 1) -#define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0) +#define PCI9111_AI_TRIG_CTRL_TRGEVENT BIT(5) +#define PCI9111_AI_TRIG_CTRL_POTRG BIT(4) +#define PCI9111_AI_TRIG_CTRL_PTRG BIT(3) +#define PCI9111_AI_TRIG_CTRL_ETIS BIT(2) +#define PCI9111_AI_TRIG_CTRL_TPST BIT(1) +#define PCI9111_AI_TRIG_CTRL_ASCAN BIT(0) #define PCI9111_INT_CTRL_REG 0x0c -#define PCI9111_INT_CTRL_ISC2 (1 << 3) -#define PCI9111_INT_CTRL_FFEN (1 << 2) -#define PCI9111_INT_CTRL_ISC1 (1 << 1) -#define PCI9111_INT_CTRL_ISC0 (1 << 0) +#define PCI9111_INT_CTRL_ISC2 BIT(3) +#define PCI9111_INT_CTRL_FFEN BIT(2) +#define PCI9111_INT_CTRL_ISC1 BIT(1) +#define PCI9111_INT_CTRL_ISC0 BIT(0) #define PCI9111_SOFT_TRIG_REG 0x0e #define PCI9111_8254_BASE_REG 0x40 #define PCI9111_INT_CLR_REG 0x48 @@ -139,21 +124,21 @@ struct pci9111_private_data { }; static void plx9050_interrupt_control(unsigned long io_base, - bool LINTi1_enable, - bool LINTi1_active_high, - bool LINTi2_enable, - bool LINTi2_active_high, + bool int1_enable, + bool int1_active_high, + bool int2_enable, + bool int2_active_high, bool interrupt_enable) { int flags = 0; - if (LINTi1_enable) + if (int1_enable) flags |= PLX9052_INTCSR_LI1ENAB; - if (LINTi1_active_high) + if (int1_active_high) flags |= PLX9052_INTCSR_LI1POL; - if (LINTi2_enable) + if (int2_enable) flags |= PLX9052_INTCSR_LI2ENAB; - if (LINTi2_active_high) + if (int2_active_high) flags |= PLX9052_INTCSR_LI2POL; if (interrupt_enable) @@ -363,6 +348,7 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, struct pci9111_private_data *dev_private = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int last_chan = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); unsigned int trig = 0; /* Set channel scan limit */ @@ -374,11 +360,8 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, outb(last_chan, dev->iobase + PCI9111_AI_CHANNEL_REG); - /* Set gain */ - /* This is the same gain on every channel */ - - outb(CR_RANGE(cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, - dev->iobase + PCI9111_AI_RANGE_STAT_REG); + /* Set gain - all channels use the same range */ + outb(PCI9111_AI_RANGE(range0), dev->iobase + PCI9111_AI_RANGE_STAT_REG); /* Set timer pacer */ dev_private->scan_delay = 0; @@ -434,14 +417,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 short *buf = devpriv->ai_bounce_buffer; unsigned int samples; samples = comedi_nsamples_left(s, PCI9111_FIFO_HALF_SIZE); - insw(dev->iobase + PCI9111_AI_FIFO_REG, - devpriv->ai_bounce_buffer, samples); + insw(dev->iobase + PCI9111_AI_FIFO_REG, buf, samples); if (devpriv->scan_delay < 1) { - comedi_buf_write_samples(s, devpriv->ai_bounce_buffer, samples); + comedi_buf_write_samples(s, buf, samples); } else { unsigned int pos = 0; unsigned int to_read; @@ -454,9 +437,7 @@ static void pci9111_handle_fifo_half_full(struct comedi_device *dev, if (to_read > samples - pos) to_read = samples - pos; - comedi_buf_write_samples(s, - devpriv->ai_bounce_buffer + pos, - to_read); + comedi_buf_write_samples(s, buf + pos, to_read); } else { to_read = devpriv->chunk_num_samples - devpriv->chunk_counter; @@ -571,7 +552,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); if ((status & PCI9111_AI_RANGE_MASK) != range) { - outb(range & PCI9111_AI_RANGE_MASK, + outb(PCI9111_AI_RANGE(range), dev->iobase + PCI9111_AI_RANGE_STAT_REG); } diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index fb3043dcf..0dff1dbb5 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -83,12 +83,6 @@ #include "amcc_s5933.h" #include "comedi_8254.h" -#define IORANGE_9118 64 /* I hope */ -#define PCI9118_CHANLEN 255 /* - * len of chanlist, some source say 256, - * but reality looks like 255 :-( - */ - /* * PCI BAR2 Register map (dev->iobase) */ @@ -96,24 +90,24 @@ #define PCI9118_AI_FIFO_REG 0x10 #define PCI9118_AO_REG(x) (0x10 + ((x) * 4)) #define PCI9118_AI_STATUS_REG 0x18 -#define PCI9118_AI_STATUS_NFULL (1 << 8) /* 0=FIFO full (fatal) */ -#define PCI9118_AI_STATUS_NHFULL (1 << 7) /* 0=FIFO half full */ -#define PCI9118_AI_STATUS_NEPTY (1 << 6) /* 0=FIFO empty */ -#define PCI9118_AI_STATUS_ACMP (1 << 5) /* 1=about trigger complete */ -#define PCI9118_AI_STATUS_DTH (1 << 4) /* 1=ext. digital trigger */ -#define PCI9118_AI_STATUS_BOVER (1 << 3) /* 1=burst overrun (fatal) */ -#define PCI9118_AI_STATUS_ADOS (1 << 2) /* 1=A/D over speed (warn) */ -#define PCI9118_AI_STATUS_ADOR (1 << 1) /* 1=A/D overrun (fatal) */ -#define PCI9118_AI_STATUS_ADRDY (1 << 0) /* 1=A/D ready */ +#define PCI9118_AI_STATUS_NFULL BIT(8) /* 0=FIFO full (fatal) */ +#define PCI9118_AI_STATUS_NHFULL BIT(7) /* 0=FIFO half full */ +#define PCI9118_AI_STATUS_NEPTY BIT(6) /* 0=FIFO empty */ +#define PCI9118_AI_STATUS_ACMP BIT(5) /* 1=about trigger complete */ +#define PCI9118_AI_STATUS_DTH BIT(4) /* 1=ext. digital trigger */ +#define PCI9118_AI_STATUS_BOVER BIT(3) /* 1=burst overrun (fatal) */ +#define PCI9118_AI_STATUS_ADOS BIT(2) /* 1=A/D over speed (warn) */ +#define PCI9118_AI_STATUS_ADOR BIT(1) /* 1=A/D overrun (fatal) */ +#define PCI9118_AI_STATUS_ADRDY BIT(0) /* 1=A/D ready */ #define PCI9118_AI_CTRL_REG 0x18 -#define PCI9118_AI_CTRL_UNIP (1 << 7) /* 1=unipolar */ -#define PCI9118_AI_CTRL_DIFF (1 << 6) /* 1=differential inputs */ -#define PCI9118_AI_CTRL_SOFTG (1 << 5) /* 1=8254 software gate */ -#define PCI9118_AI_CTRL_EXTG (1 << 4) /* 1=8254 TGIN(pin 46) gate */ -#define PCI9118_AI_CTRL_EXTM (1 << 3) /* 1=ext. trigger (pin 44) */ -#define PCI9118_AI_CTRL_TMRTR (1 << 2) /* 1=8254 is trigger source */ -#define PCI9118_AI_CTRL_INT (1 << 1) /* 1=enable interrupt */ -#define PCI9118_AI_CTRL_DMA (1 << 0) /* 1=enable DMA */ +#define PCI9118_AI_CTRL_UNIP BIT(7) /* 1=unipolar */ +#define PCI9118_AI_CTRL_DIFF BIT(6) /* 1=differential inputs */ +#define PCI9118_AI_CTRL_SOFTG BIT(5) /* 1=8254 software gate */ +#define PCI9118_AI_CTRL_EXTG BIT(4) /* 1=8254 TGIN(pin 46) gate */ +#define PCI9118_AI_CTRL_EXTM BIT(3) /* 1=ext. trigger (pin 44) */ +#define PCI9118_AI_CTRL_TMRTR BIT(2) /* 1=8254 is trigger source */ +#define PCI9118_AI_CTRL_INT BIT(1) /* 1=enable interrupt */ +#define PCI9118_AI_CTRL_DMA BIT(0) /* 1=enable DMA */ #define PCI9118_DIO_REG 0x1c #define PCI9118_SOFTTRG_REG 0x20 #define PCI9118_AI_CHANLIST_REG 0x24 @@ -122,27 +116,25 @@ #define PCI9118_AI_BURST_NUM_REG 0x28 #define PCI9118_AI_AUTOSCAN_MODE_REG 0x2c #define PCI9118_AI_CFG_REG 0x30 -#define PCI9118_AI_CFG_PDTRG (1 << 7) /* 1=positive trigger */ -#define PCI9118_AI_CFG_PETRG (1 << 6) /* 1=positive ext. trigger */ -#define PCI9118_AI_CFG_BSSH (1 << 5) /* 1=with sample & hold */ -#define PCI9118_AI_CFG_BM (1 << 4) /* 1=burst mode */ -#define PCI9118_AI_CFG_BS (1 << 3) /* 1=burst mode start */ -#define PCI9118_AI_CFG_PM (1 << 2) /* 1=post trigger */ -#define PCI9118_AI_CFG_AM (1 << 1) /* 1=about trigger */ -#define PCI9118_AI_CFG_START (1 << 0) /* 1=trigger start */ +#define PCI9118_AI_CFG_PDTRG BIT(7) /* 1=positive trigger */ +#define PCI9118_AI_CFG_PETRG BIT(6) /* 1=positive ext. trigger */ +#define PCI9118_AI_CFG_BSSH BIT(5) /* 1=with sample & hold */ +#define PCI9118_AI_CFG_BM BIT(4) /* 1=burst mode */ +#define PCI9118_AI_CFG_BS BIT(3) /* 1=burst mode start */ +#define PCI9118_AI_CFG_PM BIT(2) /* 1=post trigger */ +#define PCI9118_AI_CFG_AM BIT(1) /* 1=about trigger */ +#define PCI9118_AI_CFG_START BIT(0) /* 1=trigger start */ #define PCI9118_FIFO_RESET_REG 0x34 #define PCI9118_INT_CTRL_REG 0x38 -#define PCI9118_INT_CTRL_TIMER (1 << 3) /* timer interrupt */ -#define PCI9118_INT_CTRL_ABOUT (1 << 2) /* about trigger complete */ -#define PCI9118_INT_CTRL_HFULL (1 << 1) /* A/D FIFO half full */ -#define PCI9118_INT_CTRL_DTRG (1 << 0) /* ext. digital trigger */ +#define PCI9118_INT_CTRL_TIMER BIT(3) /* timer interrupt */ +#define PCI9118_INT_CTRL_ABOUT BIT(2) /* about trigger complete */ +#define PCI9118_INT_CTRL_HFULL BIT(1) /* A/D FIFO half full */ +#define PCI9118_INT_CTRL_DTRG BIT(0) /* ext. digital trigger */ #define START_AI_EXT 0x01 /* start measure on external trigger */ #define STOP_AI_EXT 0x02 /* stop measure on external trigger */ #define STOP_AI_INT 0x08 /* stop measure on internal trigger */ -#define PCI9118_HALF_FIFO_SZ (1024 / 2) - static const struct comedi_lrange pci9118_ai_range = { 8, { BIP_RANGE(5), @@ -169,11 +161,6 @@ static const struct comedi_lrange pci9118hg_ai_range = { } }; -#define PCI9118_BIPOLAR_RANGES 4 /* - * used for test on mixture - * of BIP/UNI ranges - */ - enum pci9118_boardid { BOARD_PCI9118DG, BOARD_PCI9118HG, @@ -296,51 +283,44 @@ static void pci9118_ai_reset_fifo(struct comedi_device *dev) outl(0, dev->iobase + PCI9118_FIFO_RESET_REG); } -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, int n_chan, - unsigned int *chanlist, int frontadd, int backadd) +static int pci9118_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { struct pci9118_private *devpriv = dev->private; - unsigned int i, differencial = 0, bipolar = 0; + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - dev_err(dev->class_dev, "range/channel list is empty!\n"); + /* single channel scans are always ok */ + if (cmd->chanlist_len == 1) return 0; - } - if ((frontadd + n_chan + backadd) > s->len_chanlist) { - dev_err(dev->class_dev, - "range/channel list is too long for actual configuration!\n"); - return 0; - } - if (CR_AREF(chanlist[0]) == AREF_DIFF) - differencial = 1; /* all input must be diff */ - if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) - bipolar = 1; /* all input must be bipolar */ - if (n_chan > 1) - for (i = 1; i < n_chan; i++) { /* check S.E/diff */ - if ((CR_AREF(chanlist[i]) == AREF_DIFF) != - (differencial)) { - dev_err(dev->class_dev, - "Differential and single ended inputs can't be mixed!\n"); - return 0; - } - if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) != - (bipolar)) { - dev_err(dev->class_dev, - "Bipolar and unipolar ranges can't be mixed!\n"); - return 0; - } - if (!devpriv->usemux && differencial && - (CR_CHAN(chanlist[i]) >= (s->n_chan / 2))) { - dev_err(dev->class_dev, - "AREF_DIFF is only available for the first 8 channels!\n"); - return 0; - } + 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 (aref != aref0) { + dev_err(dev->class_dev, + "Differential and single ended inputs can't be mixed!\n"); + return -EINVAL; + } + if (comedi_range_is_bipolar(s, range) != + comedi_range_is_bipolar(s, range0)) { + dev_err(dev->class_dev, + "Bipolar and unipolar ranges can't be mixed!\n"); + return -EINVAL; } + if (!devpriv->usemux && aref == AREF_DIFF && + (chan >= (s->n_chan / 2))) { + dev_err(dev->class_dev, + "AREF_DIFF is only available for the first 8 channels!\n"); + return -EINVAL; + } + } - return 1; + return 0; } static void pci9118_set_chanlist(struct comedi_device *dev, @@ -406,8 +386,8 @@ static void pci9118_set_chanlist(struct comedi_device *dev, /* udelay(100); important delay, or first sample will be crippled */ } -static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev, - unsigned int next_buf) +static void pci9118_ai_mode4_switch(struct comedi_device *dev, + unsigned int next_buf) { struct pci9118_private *devpriv = dev->private; struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[next_buf]; @@ -421,9 +401,9 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev, outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); } -static unsigned int valid_samples_in_act_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int n_raw_samples) +static unsigned int pci9118_ai_samples_ready(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; @@ -477,7 +457,7 @@ static unsigned int valid_samples_in_act_dma_buf(struct comedi_device *dev, return n_samples; } -static void move_block_from_dma(struct comedi_device *dev, +static void pci9118_ai_dma_xfer(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short *dma_buffer, unsigned int n_raw_samples) @@ -634,8 +614,8 @@ static void pci9118_ai_munge(struct comedi_device *dev, } } -static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, - struct comedi_subdevice *s) +static void pci9118_ai_get_onesample(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -651,8 +631,8 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, } } -static void interrupt_pci9118_ai_dma(struct comedi_device *dev, - struct comedi_subdevice *s) +static void pci9118_ai_get_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -662,21 +642,19 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, bool more_dma; /* determine whether more DMA buffers to do after this one */ - n_valid = valid_samples_in_act_dma_buf(dev, s, n_all); + n_valid = pci9118_ai_samples_ready(dev, s, n_all); more_dma = n_valid < comedi_nsamples_left(s, n_valid + 1); /* 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 (devpriv->ai_do == 4) + pci9118_ai_mode4_switch(dev, devpriv->dma_actbuf); } if (n_all) - move_block_from_dma(dev, s, dmabuf->virt, n_all); + pci9118_ai_dma_xfer(dev, s, dmabuf->virt, n_all); if (!devpriv->ai_neverending) { if (s->async->scans_done >= cmd->stop_arg) @@ -690,7 +668,7 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, if (more_dma && !devpriv->dma_doublebuf) { pci9118_amcc_setup_dma(dev, 0); if (devpriv->ai_do == 4) - interrupt_pci9118_ai_mode4_switch(dev, 0); + pci9118_ai_mode4_switch(dev, 0); } } @@ -779,9 +757,9 @@ static irqreturn_t pci9118_interrupt(int irq, void *d) } if (devpriv->usedma) - interrupt_pci9118_ai_dma(dev, s); + pci9118_ai_get_dma(dev, s); else - interrupt_pci9118_ai_onesample(dev, s); + pci9118_ai_get_onesample(dev, s); interrupt_exit: comedi_handle_events(dev, s); @@ -816,17 +794,18 @@ static int pci9118_ai_inttrig(struct comedi_device *dev, return 1; } -static int Compute_and_setup_dma(struct comedi_device *dev, - struct comedi_subdevice *s) +static int pci9118_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; struct pci9118_dmabuf *dmabuf0 = &devpriv->dmabuf[0]; struct pci9118_dmabuf *dmabuf1 = &devpriv->dmabuf[1]; - unsigned int dmalen0, dmalen1, i; + unsigned int dmalen0 = dmabuf0->size; + unsigned int dmalen1 = dmabuf1->size; + unsigned int scan_bytes = devpriv->ai_n_realscanlen * + comedi_bytes_per_sample(s); - dmalen0 = dmabuf0->size; - dmalen1 = dmabuf1->size; /* isn't output buff smaller that our DMA buff? */ if (dmalen0 > s->async->prealloc_bufsz) { /* align to 32bit down */ @@ -839,15 +818,15 @@ static int Compute_and_setup_dma(struct comedi_device *dev, /* we want wake up every scan? */ if (devpriv->ai_flags & CMDF_WAKE_EOS) { - if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) { + if (dmalen0 < scan_bytes) { /* uff, too short DMA buffer, disable EOS support! */ devpriv->ai_flags &= (~CMDF_WAKE_EOS); dev_info(dev->class_dev, "WAR: DMA0 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n", - dmalen0, devpriv->ai_n_realscanlen << 1); + dmalen0, scan_bytes); } else { /* short first DMA buffer to one scan */ - dmalen0 = devpriv->ai_n_realscanlen << 1; + dmalen0 = scan_bytes; if (dmalen0 < 4) { dev_info(dev->class_dev, "ERR: DMA0 buf len bug? (%d<4)\n", @@ -857,15 +836,15 @@ static int Compute_and_setup_dma(struct comedi_device *dev, } } if (devpriv->ai_flags & CMDF_WAKE_EOS) { - if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) { + if (dmalen1 < scan_bytes) { /* uff, too short DMA buffer, disable EOS support! */ devpriv->ai_flags &= (~CMDF_WAKE_EOS); dev_info(dev->class_dev, "WAR: DMA1 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n", - dmalen1, devpriv->ai_n_realscanlen << 1); + dmalen1, scan_bytes); } else { /* short second DMA buffer to one scan */ - dmalen1 = devpriv->ai_n_realscanlen << 1; + dmalen1 = scan_bytes; if (dmalen1 < 4) { dev_info(dev->class_dev, "ERR: DMA1 buf len bug? (%d<4)\n", @@ -877,45 +856,39 @@ static int Compute_and_setup_dma(struct comedi_device *dev, /* transfer without CMDF_WAKE_EOS */ if (!(devpriv->ai_flags & CMDF_WAKE_EOS)) { + unsigned int tmp; + /* if it's possible then align DMA buffers to length of scan */ - i = dmalen0; - dmalen0 = - (dmalen0 / (devpriv->ai_n_realscanlen << 1)) * - (devpriv->ai_n_realscanlen << 1); + tmp = dmalen0; + dmalen0 = (dmalen0 / scan_bytes) * scan_bytes; dmalen0 &= ~3L; if (!dmalen0) - dmalen0 = i; /* uff. very long scan? */ - i = dmalen1; - dmalen1 = - (dmalen1 / (devpriv->ai_n_realscanlen << 1)) * - (devpriv->ai_n_realscanlen << 1); + dmalen0 = tmp; /* uff. very long scan? */ + tmp = dmalen1; + dmalen1 = (dmalen1 / scan_bytes) * scan_bytes; dmalen1 &= ~3L; if (!dmalen1) - dmalen1 = i; /* uff. very long scan? */ + dmalen1 = tmp; /* uff. very long scan? */ /* * if measure isn't neverending then test, if it fits whole * into one or two DMA buffers */ if (!devpriv->ai_neverending) { + unsigned long long scanlen; + + scanlen = (unsigned long long)scan_bytes * + cmd->stop_arg; + /* fits whole measure into one DMA buffer? */ - if (dmalen0 > - ((devpriv->ai_n_realscanlen << 1) * - cmd->stop_arg)) { - dmalen0 = - (devpriv->ai_n_realscanlen << 1) * - cmd->stop_arg; + if (dmalen0 > scanlen) { + dmalen0 = scanlen; dmalen0 &= ~3L; - } else { /* - * fits whole measure into - * two DMA buffer? - */ - if (dmalen1 > - ((devpriv->ai_n_realscanlen << 1) * - cmd->stop_arg - dmalen0)) - dmalen1 = - (devpriv->ai_n_realscanlen << 1) * - cmd->stop_arg - dmalen0; - dmalen1 &= ~3L; + } else { + /* fits whole measure into two DMA buffer? */ + if (dmalen1 > (scanlen - dmalen0)) { + dmalen1 = scanlen - dmalen0; + dmalen1 &= ~3L; + } } } } @@ -945,6 +918,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct comedi_8254 *pacer = dev->pacer; struct comedi_cmd *cmd = &s->async->cmd; unsigned int addchans = 0; + unsigned int scanlen; devpriv->ai12_startstop = 0; devpriv->ai_flags = cmd->flags; @@ -1030,19 +1004,20 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } } /* well, we now know what must be all added */ - devpriv->ai_n_realscanlen = /* - * what we must take from card in real - * to have cmd->scan_end_arg on output? - */ - (devpriv->ai_add_front + cmd->chanlist_len + - devpriv->ai_add_back) * (cmd->scan_end_arg / - cmd->chanlist_len); - - /* check and setup channel list */ - if (!check_channel_list(dev, s, cmd->chanlist_len, - cmd->chanlist, devpriv->ai_add_front, - devpriv->ai_add_back)) + scanlen = devpriv->ai_add_front + cmd->chanlist_len + + devpriv->ai_add_back; + /* + * what we must take from card in real to have cmd->scan_end_arg + * on output? + */ + devpriv->ai_n_realscanlen = scanlen * + (cmd->scan_end_arg / cmd->chanlist_len); + + if (scanlen > s->len_chanlist) { + dev_err(dev->class_dev, + "range/channel list is too long for actual configuration!\n"); return -EINVAL; + } /* * Configure analog input and load the chanlist. @@ -1141,7 +1116,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_act_dmapos = 0; if (devpriv->usedma) { - Compute_and_setup_dma(dev, s); + pci9118_ai_setup_dma(dev, s); outl(0x02000000 | AINT_WRITE_COMPL, devpriv->iobase_a + AMCC_OP_REG_INTCSR); @@ -1205,9 +1180,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) err |= -EINVAL; - if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT) - err |= -EINVAL; - if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) && (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) err |= -EINVAL; @@ -1315,10 +1287,13 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, if (err) return 4; + /* Step 5: check channel list if it exists */ + if (cmd->chanlist) - if (!check_channel_list(dev, s, cmd->chanlist_len, - cmd->chanlist, 0, 0)) - return 5; /* incorrect channels list */ + err |= pci9118_ai_check_chanlist(dev, s, cmd); + + if (err) + return 5; return 0; } @@ -1608,7 +1583,7 @@ static int pci9118_common_attach(struct comedi_device *dev, if (dev->irq) { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = PCI9118_CHANLEN; + s->len_chanlist = 255; s->do_cmdtest = pci9118_ai_cmdtest; s->do_cmd = pci9118_ai_cmd; s->cancel = pci9118_ai_cancel; diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index bc5f97f50..315050454 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -1,75 +1,59 @@ /* - comedi/drivers/adq12b.c - driver for MicroAxial ADQ12-B data acquisition and control card - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - 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: adq12b -Description: driver for MicroAxial ADQ12-B data acquisition and control card -Devices: [MicroAxial] ADQ12-B (adq12b) -Author: jeremy theler -Updated: Thu, 21 Feb 2008 02:56:27 -0300 -Status: works - -Driver for the acquisition card ADQ12-B (without any add-on). - - - Analog input is subdevice 0 (16 channels single-ended or 8 differential) - - Digital input is subdevice 1 (5 channels) - - Digital output is subdevice 1 (8 channels) - - The PACER is not supported in this version - -If you do not specify any options, they will default to - - # comedi_config /dev/comedi0 adq12b 0x300,0,0 - - option 1: I/O base address. The following table is provided as a help - of the hardware jumpers. - - address jumper JADR - 0x300 1 (factory default) - 0x320 2 - 0x340 3 - 0x360 4 - 0x380 5 - 0x3A0 6 - - option 2: unipolar/bipolar ADC selection: 0 -> bipolar, 1 -> unipolar + * adq12b.c + * Driver for MicroAxial ADQ12-B data acquisition and control card + * written by jeremy theler + * instituto balseiro + * commission nacional de energia atomica + * universidad nacional de cuyo + * argentina + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * 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. + */ - selection comedi_config option JUB - bipolar 0 2-3 (factory default) - unipolar 1 1-2 - - option 3: single-ended/differential AI selection: 0 -> SE, 1 -> differential - - selection comedi_config option JCHA JCHB - single-ended 0 1-2 1-2 (factory default) - differential 1 2-3 2-3 - - written by jeremy theler - - instituto balseiro - commission nacional de energia atomica - universidad nacional de cuyo - argentina - - 21-feb-2008 - + changed supported devices string (missused the [] and ()) - - 13-oct-2007 - + first try -*/ +/* + * Driver: adq12b + * Description: Driver for MicroAxial ADQ12-B data acquisition and control card + * Devices: [MicroAxial] ADQ12-B (adq12b) + * Author: jeremy theler + * Updated: Thu, 21 Feb 2008 02:56:27 -0300 + * Status: works + * + * Configuration options: + * [0] - I/O base address (set with hardware jumpers) + * address jumper JADR + * 0x300 1 (factory default) + * 0x320 2 + * 0x340 3 + * 0x360 4 + * 0x380 5 + * 0x3A0 6 + * [1] - Analog Input unipolar/bipolar selection + * selection option JUB + * bipolar 0 2-3 (factory default) + * unipolar 1 1-2 + * [2] - Analog Input single-ended/differential selection + * selection option JCHA JCHB + * single-ended 0 1-2 1-2 (factory default) + * differential 1 2-3 2-3 + * + * Driver for the acquisition card ADQ12-B (without any add-on). + * + * - Analog input is subdevice 0 (16 channels single-ended or 8 differential) + * - Digital input is subdevice 1 (5 channels) + * - Digital output is subdevice 1 (8 channels) + * - The PACER is not supported in this version + */ #include #include @@ -78,14 +62,14 @@ If you do not specify any options, they will default to /* address scheme (page 2.17 of the manual) */ #define ADQ12B_CTREG 0x00 -#define ADQ12B_CTREG_MSKP (1 << 7) /* enable pacer interrupt */ -#define ADQ12B_CTREG_GTP (1 << 6) /* enable pacer */ +#define ADQ12B_CTREG_MSKP BIT(7) /* enable pacer interrupt */ +#define ADQ12B_CTREG_GTP BIT(6) /* enable pacer */ #define ADQ12B_CTREG_RANGE(x) ((x) << 4) #define ADQ12B_CTREG_CHAN(x) ((x) << 0) #define ADQ12B_STINR 0x00 -#define ADQ12B_STINR_OUT2 (1 << 7) /* timer 2 output state */ -#define ADQ12B_STINR_OUTP (1 << 6) /* pacer output state */ -#define ADQ12B_STINR_EOC (1 << 5) /* A/D end-of-conversion */ +#define ADQ12B_STINR_OUT2 BIT(7) /* timer 2 output state */ +#define ADQ12B_STINR_OUTP BIT(6) /* pacer output state */ +#define ADQ12B_STINR_EOC BIT(5) /* A/D end-of-conversion */ #define ADQ12B_STINR_IN_MASK (0x1f << 0) #define ADQ12B_OUTBR 0x04 #define ADQ12B_ADLOW 0x08 @@ -145,7 +129,7 @@ static int adq12b_ai_insn_read(struct comedi_device *dev, if (val != devpriv->last_ctreg) { outb(val, dev->iobase + ADQ12B_CTREG); devpriv->last_ctreg = val; - udelay(50); /* wait for the mux to settle */ + usleep_range(50, 100); /* wait for the mux to settle */ } val = inb(dev->iobase + ADQ12B_ADLOW); /* trigger A/D */ diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 0c6aa964c..399c511cf 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -1,45 +1,30 @@ /* - * comedi/drivers/adv_pci1710.c - * + * adv_pci1710.c + * Comedi driver for Advantech PCI-1710 series boards * Author: Michal Dobes * * Thanks to ZhenGang Shang * for testing and information. + */ + +/* + * Driver: adv_pci1710 + * Description: Comedi driver for Advantech PCI-1710 series boards + * Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG, PCI-1711, + * PCI-1713, PCI-1720, PCI-1731 + * Author: Michal Dobes + * Status: works * - * hardware driver for Advantech cards: - * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731 - * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731 + * Configuration options: not applicable, uses PCI auto config * - * Options: - * [0] - PCI bus number - if bus number and slot number are 0, - * then driver search for first unused card - * [1] - PCI slot number + * This driver supports AI, AO, DI and DO subdevices. + * AI subdevice supports cmd and insn interface, + * other subdevices support only insn interface. * -*/ -/* -Driver: adv_pci1710 -Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, - Advantech PCI-1720, PCI-1731 -Author: Michal Dobes -Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg), - PCI-1711 (adv_pci1710), PCI-1713, PCI-1720, - PCI-1731 -Status: works - -This driver supports AI, AO, DI and DO subdevices. -AI subdevice supports cmd and insn interface, -other subdevices support only insn interface. - -The PCI-1710 and PCI-1710HG have the same PCI device ID, so the -driver cannot distinguish between them, as would be normal for a -PCI driver. - -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first available PCI - device will be used. -*/ + * The PCI-1710 and PCI-1710HG have the same PCI device ID, so the + * driver cannot distinguish between them, as would be normal for a + * PCI driver. + */ #include #include @@ -49,48 +34,43 @@ Configuration options: #include "comedi_8254.h" #include "amcc_s5933.h" -#define PCI171x_AD_DATA 0 /* R: A/D data */ -#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */ -#define PCI171x_RANGE 2 /* W: A/D gain/range register */ -#define PCI171x_MUX 4 /* W: A/D multiplexor control */ -#define PCI171x_STATUS 6 /* R: status register */ -#define PCI171x_CONTROL 6 /* W: control register */ -#define PCI171x_CLRINT 8 /* W: clear interrupts request */ -#define PCI171x_CLRFIFO 9 /* W: clear FIFO */ -#define PCI171x_DA1 10 /* W: D/A register */ -#define PCI171x_DA2 12 /* W: D/A register */ -#define PCI171x_DAREF 14 /* W: D/A reference control */ -#define PCI171x_DI 16 /* R: digi inputs */ -#define PCI171x_DO 16 /* R: digi inputs */ - -#define PCI171X_TIMER_BASE 0x18 - -/* upper bits from status register (PCI171x_STATUS) (lower is same with control - * reg) */ -#define Status_FE 0x0100 /* 1=FIFO is empty */ -#define Status_FH 0x0200 /* 1=FIFO is half full */ -#define Status_FF 0x0400 /* 1=FIFO is full, fatal error */ -#define Status_IRQ 0x0800 /* 1=IRQ occurred */ -/* bits from control register (PCI171x_CONTROL) */ -#define Control_CNT0 0x0040 /* 1=CNT0 have external source, - * 0=have internal 100kHz source */ -#define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */ -#define Control_IRQEN 0x0010 /* 1=enable IRQ */ -#define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */ -#define Control_EXT 0x0004 /* 1=external trigger source */ -#define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */ -#define Control_SW 0x0001 /* 1=enable software trigger source */ - -#define PCI1720_DA0 0 /* W: D/A register 0 */ -#define PCI1720_DA1 2 /* W: D/A register 1 */ -#define PCI1720_DA2 4 /* W: D/A register 2 */ -#define PCI1720_DA3 6 /* W: D/A register 3 */ -#define PCI1720_RANGE 8 /* R/W: D/A range register */ -#define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */ -#define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */ - -/* D/A synchronized control (PCI1720_SYNCONT) */ -#define Syncont_SC0 1 /* set synchronous output mode */ +/* + * PCI BAR2 Register map (dev->iobase) + */ +#define PCI171X_AD_DATA_REG 0x00 /* R: A/D data */ +#define PCI171X_SOFTTRG_REG 0x00 /* W: soft trigger for A/D */ +#define PCI171X_RANGE_REG 0x02 /* W: A/D gain/range register */ +#define PCI171X_MUX_REG 0x04 /* W: A/D multiplexor control */ +#define PCI171X_STATUS_REG 0x06 /* R: status register */ +#define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */ +#define PCI171X_STATUS_FF BIT(10) /* 1=FIFO is full, fatal error */ +#define PCI171X_STATUS_FH BIT(9) /* 1=FIFO is half full */ +#define PCI171X_STATUS_FE BIT(8) /* 1=FIFO is empty */ +#define PCI171X_CTRL_REG 0x06 /* W: control register */ +#define PCI171X_CTRL_CNT0 BIT(6) /* 1=ext. clk, 0=int. 100kHz clk */ +#define PCI171X_CTRL_ONEFH BIT(5) /* 1=on FIFO half full, 0=on sample */ +#define PCI171X_CTRL_IRQEN BIT(4) /* 1=enable IRQ */ +#define PCI171X_CTRL_GATE BIT(3) /* 1=enable ext. trigger GATE (8254?) */ +#define PCI171X_CTRL_EXT BIT(2) /* 1=enable ext. trigger source */ +#define PCI171X_CTRL_PACER BIT(1) /* 1=enable int. 8254 trigger source */ +#define PCI171X_CTRL_SW BIT(0) /* 1=enable software trigger source */ +#define PCI171X_CLRINT_REG 0x08 /* W: clear interrupts request */ +#define PCI171X_CLRFIFO_REG 0x09 /* W: clear FIFO */ +#define PCI171X_DA_REG(x) (0x0a + ((x) * 2)) /* W: D/A register */ +#define PCI171X_DAREF_REG 0x0e /* W: D/A reference control */ +#define PCI171X_DI_REG 0x10 /* R: digital inputs */ +#define PCI171X_DO_REG 0x10 /* W: digital outputs */ +#define PCI171X_TIMER_BASE 0x18 /* R/W: 8254 timer */ + +/* + * PCI-1720 only has analog outputs and has a different + * register map (dev->iobase) + */ +#define PCI1720_DA_REG(x) (0x00 + ((x) * 2)) /* W: D/A registers */ +#define PCI1720_RANGE_REG 0x08 /* R/W: D/A range register */ +#define PCI1720_SYNC_REG 0x09 /* W: D/A synchronized output */ +#define PCI1720_SYNC_CTRL_REG 0x0f /* R/W: D/A synchronized control */ +#define PCI1720_SYNC_CTRL_SC0 BIT(0) /* set synchronous output mode */ static const struct comedi_lrange range_pci1710_3 = { 9, { @@ -244,10 +224,10 @@ static const struct boardtype boardtypes[] = { struct pci1710_private { unsigned int max_samples; - unsigned int CntrlReg; /* Control register */ + unsigned int ctrl; /* control register value */ + unsigned int ctrl_ext; /* used to switch from TRIG_EXT to TRIG_xxx */ + unsigned int mux_ext; /* used to set the channel interval to scan */ unsigned char ai_et; - unsigned int ai_et_CntrlReg; - unsigned int ai_et_MuxVal; unsigned int act_chanlist[32]; /* list of scanned channel */ unsigned char saved_seglen; /* len of the non-repeating chanlist */ unsigned char da_ranges; /* copy of D/A outpit range register */ @@ -342,8 +322,8 @@ static void pci171x_ai_setup_chanlist(struct comedi_device *dev, rangeval |= 0x0020; /* select channel and set range */ - outw(chan | (chan << 8), dev->iobase + PCI171x_MUX); - outw(rangeval, dev->iobase + PCI171x_RANGE); + outw(chan | (chan << 8), dev->iobase + PCI171X_MUX_REG); + outw(rangeval, dev->iobase + PCI171X_RANGE_REG); devpriv->act_chanlist[i] = chan; } @@ -351,8 +331,8 @@ static void pci171x_ai_setup_chanlist(struct comedi_device *dev, devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); /* select channel interval to scan */ - devpriv->ai_et_MuxVal = first_chan | (last_chan << 8); - outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); + devpriv->mux_ext = first_chan | (last_chan << 8); + outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG); } static int pci171x_ai_eoc(struct comedi_device *dev, @@ -362,8 +342,8 @@ static int pci171x_ai_eoc(struct comedi_device *dev, { unsigned int status; - status = inw(dev->iobase + PCI171x_STATUS); - if ((status & Status_FE) == 0) + status = inw(dev->iobase + PCI171X_STATUS_REG); + if ((status & PCI171X_STATUS_FE) == 0) return 0; return -EBUSY; } @@ -378,7 +358,7 @@ static int pci171x_ai_read_sample(struct comedi_device *dev, unsigned int sample; unsigned int chan; - sample = inw(dev->iobase + PCI171x_AD_DATA); + sample = inw(dev->iobase + PCI171X_AD_DATA_REG); if (!board->is_pci1713) { /* * The upper 4 bits of the 16-bit sample are the channel number @@ -406,18 +386,19 @@ static int pci171x_ai_insn_read(struct comedi_device *dev, int ret = 0; int i; - devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; /* set software trigger */ - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); + devpriv->ctrl &= PCI171X_CTRL_CNT0; + devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */ + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); + outb(0, dev->iobase + PCI171X_CLRINT_REG); pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1); for (i = 0; i < insn->n; i++) { unsigned int val; - outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ + /* start conversion */ + outw(0, dev->iobase + PCI171X_SOFTTRG_REG); ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); if (ret) @@ -430,8 +411,8 @@ static int pci171x_ai_insn_read(struct comedi_device *dev, data[i] = val; } - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); + outb(0, dev->iobase + PCI171X_CLRINT_REG); return ret ? ret : insn->n; } @@ -444,17 +425,16 @@ static int pci171x_ao_insn_write(struct comedi_device *dev, struct pci1710_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1; unsigned int val = s->readback[chan]; int i; devpriv->da_ranges &= ~(1 << (chan << 1)); devpriv->da_ranges |= (range << (chan << 1)); - outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); + outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG); for (i = 0; i < insn->n; i++) { val = data[i]; - outw(val, dev->iobase + reg); + outw(val, dev->iobase + PCI171X_DA_REG(chan)); } s->readback[chan] = val; @@ -467,7 +447,7 @@ static int pci171x_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - data[1] = inw(dev->iobase + PCI171x_DI); + data[1] = inw(dev->iobase + PCI171X_DI_REG); return insn->n; } @@ -478,7 +458,7 @@ static int pci171x_do_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outw(s->state, dev->iobase + PCI171x_DO); + outw(s->state, dev->iobase + PCI171X_DO_REG); data[1] = s->state; @@ -499,15 +479,15 @@ static int pci1720_ao_insn_write(struct comedi_device *dev, val = devpriv->da_ranges & (~(0x03 << (chan << 1))); val |= (range << (chan << 1)); if (val != devpriv->da_ranges) { - outb(val, dev->iobase + PCI1720_RANGE); + outb(val, dev->iobase + PCI1720_RANGE_REG); devpriv->da_ranges = val; } val = s->readback[chan]; for (i = 0; i < insn->n; i++) { val = data[i]; - outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); - outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ + outw(val, dev->iobase + PCI1720_DA_REG(chan)); + outb(0, dev->iobase + PCI1720_SYNC_REG); /* update outputs */ } s->readback[chan] = val; @@ -520,13 +500,13 @@ static int pci171x_ai_cancel(struct comedi_device *dev, { struct pci1710_private *devpriv = dev->private; - devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; + devpriv->ctrl &= PCI171X_CTRL_CNT0; + devpriv->ctrl |= PCI171X_CTRL_SW; /* reset any operations */ - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); comedi_8254_pacer_enable(dev->pacer, 1, 2, false); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); + outb(0, dev->iobase + PCI171X_CLRINT_REG); return 0; } @@ -539,22 +519,22 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, unsigned int val; int ret; - status = inw(dev->iobase + PCI171x_STATUS); - if (status & Status_FE) { + status = inw(dev->iobase + PCI171X_STATUS_REG); + if (status & PCI171X_STATUS_FE) { dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); s->async->events |= COMEDI_CB_ERROR; return; } - if (status & Status_FF) { + if (status & PCI171X_STATUS_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); s->async->events |= COMEDI_CB_ERROR; return; } - outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ + outb(0, dev->iobase + PCI171X_CLRINT_REG); - for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { + for (; !(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_FE);) { ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val); if (ret) { s->async->events |= COMEDI_CB_ERROR; @@ -570,7 +550,7 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, } } - outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ + outb(0, dev->iobase + PCI171X_CLRINT_REG); } static void pci1710_handle_fifo(struct comedi_device *dev, @@ -582,13 +562,13 @@ static void pci1710_handle_fifo(struct comedi_device *dev, unsigned int status; int i; - status = inw(dev->iobase + PCI171x_STATUS); - if (!(status & Status_FH)) { + status = inw(dev->iobase + PCI171X_STATUS_REG); + if (!(status & PCI171X_STATUS_FH)) { dev_dbg(dev->class_dev, "A/D FIFO not half full!\n"); async->events |= COMEDI_CB_ERROR; return; } - if (status & Status_FF) { + if (status & PCI171X_STATUS_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!)\n"); async->events |= COMEDI_CB_ERROR; @@ -615,7 +595,7 @@ static void pci1710_handle_fifo(struct comedi_device *dev, } } - outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ + outb(0, dev->iobase + PCI171X_CLRINT_REG); } static irqreturn_t interrupt_service_pci1710(int irq, void *d) @@ -632,19 +612,20 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) cmd = &s->async->cmd; /* is this interrupt from our board? */ - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) + if (!(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_IRQ)) return IRQ_NONE; /* no, exit */ if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ devpriv->ai_et = 0; - devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; /* set software trigger */ - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - devpriv->CntrlReg = devpriv->ai_et_CntrlReg; - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); + devpriv->ctrl &= PCI171X_CTRL_CNT0; + devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */ + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); + devpriv->ctrl = devpriv->ctrl_ext; + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); + outb(0, dev->iobase + PCI171X_CLRINT_REG); + /* no sample on this interrupt; reset the channel interval */ + outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG); + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); comedi_8254_pacer_enable(dev->pacer, 1, 2, true); return IRQ_HANDLED; } @@ -667,33 +648,34 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, devpriv->saved_seglen); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); + outb(0, dev->iobase + PCI171X_CLRINT_REG); - devpriv->CntrlReg &= Control_CNT0; + devpriv->ctrl &= PCI171X_CTRL_CNT0; if ((cmd->flags & CMDF_WAKE_EOS) == 0) - devpriv->CntrlReg |= Control_ONEFH; + devpriv->ctrl |= PCI171X_CTRL_ONEFH; if (cmd->convert_src == TRIG_TIMER) { comedi_8254_update_divisors(dev->pacer); - devpriv->CntrlReg |= Control_PACER | Control_IRQEN; + devpriv->ctrl |= PCI171X_CTRL_PACER | PCI171X_CTRL_IRQEN; if (cmd->start_src == TRIG_EXT) { - devpriv->ai_et_CntrlReg = devpriv->CntrlReg; - devpriv->CntrlReg &= - ~(Control_PACER | Control_ONEFH | Control_GATE); - devpriv->CntrlReg |= Control_EXT; + devpriv->ctrl_ext = devpriv->ctrl; + devpriv->ctrl &= ~(PCI171X_CTRL_PACER | + PCI171X_CTRL_ONEFH | + PCI171X_CTRL_GATE); + devpriv->ctrl |= PCI171X_CTRL_EXT; devpriv->ai_et = 1; } else { /* TRIG_NOW */ devpriv->ai_et = 0; } - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); if (cmd->start_src == TRIG_NOW) comedi_8254_pacer_enable(dev->pacer, 1, 2, true); } else { /* TRIG_EXT */ - devpriv->CntrlReg |= Control_EXT | Control_IRQEN; - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); + devpriv->ctrl |= PCI171X_CTRL_EXT | PCI171X_CTRL_IRQEN; + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); } return 0; @@ -782,18 +764,18 @@ static int pci171x_insn_counter_config(struct comedi_device *dev, case INSN_CONFIG_SET_CLOCK_SRC: switch (data[1]) { case 0: /* internal */ - devpriv->ai_et_CntrlReg &= ~Control_CNT0; + devpriv->ctrl_ext &= ~PCI171X_CTRL_CNT0; break; case 1: /* external */ - devpriv->ai_et_CntrlReg |= Control_CNT0; + devpriv->ctrl_ext |= PCI171X_CTRL_CNT0; break; default: return -EINVAL; } - outw(devpriv->ai_et_CntrlReg, dev->iobase + PCI171x_CONTROL); + outw(devpriv->ctrl_ext, dev->iobase + PCI171X_CTRL_REG); break; case INSN_CONFIG_GET_CLOCK_SRC: - if (devpriv->ai_et_CntrlReg & Control_CNT0) { + if (devpriv->ctrl_ext & PCI171X_CTRL_CNT0) { data[1] = 1; data[2] = 0; } else { @@ -814,21 +796,21 @@ static int pci171x_reset(struct comedi_device *dev) struct pci1710_private *devpriv = dev->private; /* Software trigger, CNT0=external */ - devpriv->CntrlReg = Control_SW | Control_CNT0; + devpriv->ctrl = PCI171X_CTRL_SW | PCI171X_CTRL_CNT0; /* reset any operations */ - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ - outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); + outb(0, dev->iobase + PCI171X_CLRINT_REG); devpriv->da_ranges = 0; if (board->has_ao) { - /* set DACs to 0..5V */ - outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); - outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */ - outw(0, dev->iobase + PCI171x_DA2); + /* set DACs to 0..5V and outputs to 0V */ + outb(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG); + outw(0, dev->iobase + PCI171X_DA_REG(0)); + outw(0, dev->iobase + PCI171X_DA_REG(1)); } - outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */ - outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ - outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ + outw(0, dev->iobase + PCI171X_DO_REG); /* digital outputs to 0 */ + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); + outb(0, dev->iobase + PCI171X_CLRINT_REG); return 0; } @@ -837,15 +819,15 @@ static int pci1720_reset(struct comedi_device *dev) { struct pci1710_private *devpriv = dev->private; /* set synchronous output mode */ - outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); + outb(PCI1720_SYNC_CTRL_SC0, dev->iobase + PCI1720_SYNC_CTRL_REG); devpriv->da_ranges = 0xAA; - /* set all ranges to +/-5V */ - outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); - outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */ - outw(0x0800, dev->iobase + PCI1720_DA1); - outw(0x0800, dev->iobase + PCI1720_DA2); - outw(0x0800, dev->iobase + PCI1720_DA3); - outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ + /* set all ranges to +/-5V and outputs to 0V */ + outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE_REG); + outw(0x0800, dev->iobase + PCI1720_DA_REG(0)); + outw(0x0800, dev->iobase + PCI1720_DA_REG(1)); + outw(0x0800, dev->iobase + PCI1720_DA_REG(2)); + outw(0x0800, dev->iobase + PCI1720_DA_REG(3)); + outb(0, dev->iobase + PCI1720_SYNC_REG); /* update outputs */ return 0; } diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 1921a97cc..f82afd947 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -51,25 +51,27 @@ #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_SYNC_CTRL(x) (((x) & 0x1) << 0) +#define PCI1723_SYNC_CTRL_ASYNC PCI1723_SYNC_CTRL(0) +#define PCI1723_SYNC_CTRL_SYNC PCI1723_SYNC_CTRL(1) #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_BUSY BIT(15) +#define PCI1723_CTRL_INIT BIT(14) +#define PCI1723_CTRL_SELF BIT(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_SEL(x) (((x) & 0x1) << 3) +#define PCI1723_CTRL_GAIN PCI1723_CTRL_SEL(0) +#define PCI1723_CTRL_OFFSET PCI1723_CTRL_SEL(1) #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_CTRL_CS BIT(2) +#define PCI1723_CALIB_CTRL_DAT BIT(1) +#define PCI1723_CALIB_CTRL_CLK BIT(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_CTRL_HDIO BIT(1) +#define PCI1723_DIO_CTRL_LDIO BIT(0) #define PCI1723_DIO_DATA_REG 0x1c #define PCI1723_CALIB_DATA_REG 0x1e #define PCI1723_SYNC_STROBE_REG 0x20 @@ -77,9 +79,10 @@ #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) +#define PCI1723_VREF(x) (((x) & 0x3) << 0) +#define PCI1723_VREF_NEG10V PCI1723_VREF(0) +#define PCI1723_VREF_0V PCI1723_VREF(1) +#define PCI1723_VREF_POS10V PCI1723_VREF(3) static int pci1723_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c index 9677111f9..bf6a8f101 100644 --- a/drivers/staging/comedi/drivers/adv_pci1724.c +++ b/drivers/staging/comedi/drivers/adv_pci1724.c @@ -54,16 +54,17 @@ * 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_GX(x) BIT(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_MODE(x) (((x) & 0x3) << 14) +#define PCI1724_DAC_CTRL_MODE_GAIN PCI1724_DAC_CTRL_MODE(1) +#define PCI1724_DAC_CTRL_MODE_OFFSET PCI1724_DAC_CTRL_MODE(2) +#define PCI1724_DAC_CTRL_MODE_NORMAL PCI1724_DAC_CTRL_MODE(3) +#define PCI1724_DAC_CTRL_MODE_MASK PCI1724_DAC_CTRL_MODE(3) #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_SYNC_CTRL_DACSTAT BIT(1) +#define PCI1724_SYNC_CTRL_SYN BIT(0) #define PCI1724_EEPROM_CTRL_REG 0x08 #define PCI1724_SYNC_TRIG_REG 0x0c /* any value works */ #define PCI1724_BOARD_ID_REG 0x10 diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index fbc3e5aa9..43a0ce572 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -1,99 +1,107 @@ /* - - comedi/drivers/aio_aio12_8.c - - Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board - Copyright (C) 2006 C&C Technologies, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * aio_aio12_8.c + * Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board + * Copyright (C) 2006 C&C Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* - -Driver: aio_aio12_8 -Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board -Author: Pablo Mejia -Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8) - [Access I/O] PC-104 AI12-8 (aio_ai12_8) - [Access I/O] PC-104 AO12-8 (aio_ao12_8) -Status: experimental - -Configuration Options: - [0] - I/O port base address - -Notes: - - Only synchronous operations are supported. - -*/ + * Driver: aio_aio12_8 + * Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board + * Author: Pablo Mejia + * Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8), + * [Access I/O] PC-104 AI12-8 (aio_ai12_8), + * [Access I/O] PC-104 AO12-4 (aio_ao12_4) + * Status: experimental + * + * Configuration Options: + * [0] - I/O port base address + * + * Notes: + * Only synchronous operations are supported. + */ #include #include "../comedidev.h" + +#include "comedi_8254.h" #include "8255.h" /* * Register map */ #define AIO12_8_STATUS_REG 0x00 -#define AIO12_8_STATUS_ADC_EOC (1 << 7) -#define AIO12_8_STATUS_PORT_C_COS (1 << 6) -#define AIO12_8_STATUS_IRQ_ENA (1 << 2) +#define AIO12_8_STATUS_ADC_EOC BIT(7) +#define AIO12_8_STATUS_PORT_C_COS BIT(6) +#define AIO12_8_STATUS_IRQ_ENA BIT(2) #define AIO12_8_INTERRUPT_REG 0x01 -#define AIO12_8_INTERRUPT_ADC (1 << 7) -#define AIO12_8_INTERRUPT_COS (1 << 6) -#define AIO12_8_INTERRUPT_COUNTER1 (1 << 5) -#define AIO12_8_INTERRUPT_PORT_C3 (1 << 4) -#define AIO12_8_INTERRUPT_PORT_C0 (1 << 3) -#define AIO12_8_INTERRUPT_ENA (1 << 2) +#define AIO12_8_INTERRUPT_ADC BIT(7) +#define AIO12_8_INTERRUPT_COS BIT(6) +#define AIO12_8_INTERRUPT_COUNTER1 BIT(5) +#define AIO12_8_INTERRUPT_PORT_C3 BIT(4) +#define AIO12_8_INTERRUPT_PORT_C0 BIT(3) +#define AIO12_8_INTERRUPT_ENA BIT(2) #define AIO12_8_ADC_REG 0x02 -#define AIO12_8_ADC_MODE_NORMAL (0 << 6) -#define AIO12_8_ADC_MODE_INT_CLK (1 << 6) -#define AIO12_8_ADC_MODE_STANDBY (2 << 6) -#define AIO12_8_ADC_MODE_POWERDOWN (3 << 6) -#define AIO12_8_ADC_ACQ_3USEC (0 << 5) -#define AIO12_8_ADC_ACQ_PROGRAM (1 << 5) +#define AIO12_8_ADC_MODE(x) (((x) & 0x3) << 6) +#define AIO12_8_ADC_MODE_NORMAL AIO12_8_ADC_MODE(0) +#define AIO12_8_ADC_MODE_INT_CLK AIO12_8_ADC_MODE(1) +#define AIO12_8_ADC_MODE_STANDBY AIO12_8_ADC_MODE(2) +#define AIO12_8_ADC_MODE_POWERDOWN AIO12_8_ADC_MODE(3) +#define AIO12_8_ADC_ACQ(x) (((x) & 0x1) << 5) +#define AIO12_8_ADC_ACQ_3USEC AIO12_8_ADC_ACQ(0) +#define AIO12_8_ADC_ACQ_PROGRAM AIO12_8_ADC_ACQ(1) #define AIO12_8_ADC_RANGE(x) ((x) << 3) #define AIO12_8_ADC_CHAN(x) ((x) << 0) #define AIO12_8_DAC_REG(x) (0x04 + (x) * 2) #define AIO12_8_8254_BASE_REG 0x0c #define AIO12_8_8255_BASE_REG 0x10 #define AIO12_8_DIO_CONTROL_REG 0x14 -#define AIO12_8_DIO_CONTROL_TST (1 << 0) +#define AIO12_8_DIO_CONTROL_TST BIT(0) #define AIO12_8_ADC_TRIGGER_REG 0x15 #define AIO12_8_ADC_TRIGGER_RANGE(x) ((x) << 3) #define AIO12_8_ADC_TRIGGER_CHAN(x) ((x) << 0) #define AIO12_8_TRIGGER_REG 0x16 -#define AIO12_8_TRIGGER_ADTRIG (1 << 1) -#define AIO12_8_TRIGGER_DACTRIG (1 << 0) +#define AIO12_8_TRIGGER_ADTRIG BIT(1) +#define AIO12_8_TRIGGER_DACTRIG BIT(0) #define AIO12_8_COS_REG 0x17 #define AIO12_8_DAC_ENABLE_REG 0x18 -#define AIO12_8_DAC_ENABLE_REF_ENA (1 << 0) +#define AIO12_8_DAC_ENABLE_REF_ENA BIT(0) + +static const struct comedi_lrange aio_aio12_8_range = { + 4, { + UNI_RANGE(5), + BIP_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(10) + } +}; struct aio12_8_boardtype { const char *name; - int ai_nchan; - int ao_nchan; + unsigned int has_ai:1; + unsigned int has_ao:1; }; static const struct aio12_8_boardtype board_types[] = { { .name = "aio_aio12_8", - .ai_nchan = 8, - .ao_nchan = 4, + .has_ai = 1, + .has_ao = 1, }, { .name = "aio_ai12_8", - .ai_nchan = 8, + .has_ai = 1, }, { - .name = "aio_ao12_8", - .ao_nchan = 4, + .name = "aio_ao12_4", + .has_ao = 1, }, }; @@ -112,13 +120,15 @@ static int aio_aio12_8_ai_eoc(struct comedi_device *dev, static int aio_aio12_8_ai_read(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 range = CR_RANGE(insn->chanspec); + unsigned int val; unsigned char control; int ret; - int n; + int i; /* * Setup the control byte for internal 2MHz clock, 3uS conversion, @@ -130,7 +140,7 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, /* Read status to clear EOC latch */ inb(dev->iobase + AIO12_8_STATUS_REG); - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { /* Setup and start conversion */ outb(control, dev->iobase + AIO12_8_ADC_REG); @@ -139,7 +149,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, if (ret) return ret; - data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; + val = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; + + /* munge bipolar 2's complement data to offset binary */ + if (comedi_range_is_bipolar(s, range)) + val = comedi_offset_munge(s, val); + + data[i] = val; } return insn->n; @@ -166,14 +182,28 @@ static int aio_aio12_8_ao_insn_write(struct comedi_device *dev, return insn->n; } -static const struct comedi_lrange range_aio_aio12_8 = { - 4, { - UNI_RANGE(5), - BIP_RANGE(5), - UNI_RANGE(10), - BIP_RANGE(10) +static int aio_aio12_8_counter_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + + switch (data[0]) { + case INSN_CONFIG_GET_CLOCK_SRC: + /* + * Channels 0 and 2 have external clock sources. + * Channel 1 has a fixed 1 MHz clock source. + */ + data[0] = 0; + data[1] = (chan == 1) ? I8254_OSC_BASE_1MHZ : 0; + break; + default: + return -EINVAL; } -}; + + return insn->n; +} static int aio_aio12_8_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -186,31 +216,36 @@ static int aio_aio12_8_attach(struct comedi_device *dev, if (ret) return ret; + dev->pacer = comedi_8254_init(dev->iobase + AIO12_8_8254_BASE_REG, + 0, I8254_IO8, 0); + if (!dev->pacer) + return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - if (board->ai_nchan) { - /* Analog input subdevice */ + if (board->has_ai) { s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = board->ai_nchan; + s->n_chan = 8; s->maxdata = 0x0fff; - s->range_table = &range_aio_aio12_8; + s->range_table = &aio_aio12_8_range; s->insn_read = aio_aio12_8_ai_read; } else { s->type = COMEDI_SUBD_UNUSED; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (board->ao_nchan) { - /* Analog output subdevice */ + if (board->has_ao) { s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; s->n_chan = 4; s->maxdata = 0x0fff; - s->range_table = &range_aio_aio12_8; + s->range_table = &aio_aio12_8_range; s->insn_write = aio_aio12_8_ao_insn_write; ret = comedi_alloc_subdev_readback(s); @@ -220,15 +255,17 @@ static int aio_aio12_8_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } + /* Digital I/O subdevice (8255) */ s = &dev->subdevices[2]; - /* 8255 Digital i/o subdevice */ ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG); if (ret) return ret; + /* Counter subdevice (8254) */ s = &dev->subdevices[3]; - /* 8254 counter/timer subdevice */ - s->type = COMEDI_SUBD_UNUSED; + comedi_8254_subdevice_init(s, dev->pacer); + + dev->pacer->insn_config = aio_aio12_8_counter_insn_config; return 0; } @@ -245,5 +282,5 @@ static struct comedi_driver aio_aio12_8_driver = { module_comedi_driver(aio_aio12_8_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Access I/O AIO12-8 Analog I/O Board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 5c5c4e2ec..4b39f6960 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -2275,7 +2275,7 @@ static int pci230_ai_cancel(struct comedi_device *dev, 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 comedi_device *dev = d; struct pci230_private *devpriv = dev->private; struct comedi_subdevice *s_ao = dev->write_subdev; struct comedi_subdevice *s_ai = dev->read_subdev; diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index ae84f2c0c..78d098f9e 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -1,36 +1,37 @@ /* - comedi/drivers/das16cs.c - Driver for Computer Boards PC-CARD DAS16/16. + * cb_das16_cs.c + * Driver for Computer Boards PC-CARD DAS16/16. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000, 2001, 2002 David A. Schleef + * + * 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. + * + * PCMCIA support code for this driver is adapted from the dummy_cs.c + * driver of the Linux PCMCIA Card Services package. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + */ - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000, 2001, 2002 David A. Schleef - - 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. - - PCMCIA support code for this driver is adapted from the dummy_cs.c - driver of the Linux PCMCIA Card Services package. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - -*/ /* -Driver: cb_das16_cs -Description: Computer Boards PC-CARD DAS16/16 -Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO -Author: ds -Updated: Mon, 04 Nov 2002 20:04:21 -0800 -Status: experimental -*/ + * Driver: cb_das16_cs + * Description: Computer Boards PC-CARD DAS16/16 + * Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), + * PC-CARD DAS16/16-AO + * Author: ds + * Updated: Mon, 04 Nov 2002 20:04:21 -0800 + * Status: experimental + */ #include #include @@ -40,38 +41,86 @@ Status: experimental #include "comedi_8254.h" -#define DAS16CS_ADC_DATA 0 -#define DAS16CS_DIO_MUX 2 -#define DAS16CS_MISC1 4 -#define DAS16CS_MISC2 6 -#define DAS16CS_TIMER_BASE 8 -#define DAS16CS_DIO 16 +/* + * Register I/O map + */ +#define DAS16CS_AI_DATA_REG 0x00 +#define DAS16CS_AI_MUX_REG 0x02 +#define DAS16CS_AI_MUX_HI_CHAN(x) (((x) & 0xf) << 4) +#define DAS16CS_AI_MUX_LO_CHAN(x) (((x) & 0xf) << 0) +#define DAS16CS_AI_MUX_SINGLE_CHAN(x) (DAS16CS_AI_MUX_HI_CHAN(x) | \ + DAS16CS_AI_MUX_LO_CHAN(x)) +#define DAS16CS_MISC1_REG 0x04 +#define DAS16CS_MISC1_INTE BIT(15) /* 1=enable; 0=disable */ +#define DAS16CS_MISC1_INT_SRC(x) (((x) & 0x7) << 12) /* interrupt src */ +#define DAS16CS_MISC1_INT_SRC_NONE DAS16CS_MISC1_INT_SRC(0) +#define DAS16CS_MISC1_INT_SRC_PACER DAS16CS_MISC1_INT_SRC(1) +#define DAS16CS_MISC1_INT_SRC_EXT DAS16CS_MISC1_INT_SRC(2) +#define DAS16CS_MISC1_INT_SRC_FNE DAS16CS_MISC1_INT_SRC(3) +#define DAS16CS_MISC1_INT_SRC_FHF DAS16CS_MISC1_INT_SRC(4) +#define DAS16CS_MISC1_INT_SRC_EOS DAS16CS_MISC1_INT_SRC(5) +#define DAS16CS_MISC1_INT_SRC_MASK DAS16CS_MISC1_INT_SRC(7) +#define DAS16CS_MISC1_OVR BIT(10) /* ro - 1=FIFO overflow */ +#define DAS16CS_MISC1_AI_CONV(x) (((x) & 0x3) << 8) /* AI convert src */ +#define DAS16CS_MISC1_AI_CONV_SW DAS16CS_MISC1_AI_CONV(0) +#define DAS16CS_MISC1_AI_CONV_EXT_NEG DAS16CS_MISC1_AI_CONV(1) +#define DAS16CS_MISC1_AI_CONV_EXT_POS DAS16CS_MISC1_AI_CONV(2) +#define DAS16CS_MISC1_AI_CONV_PACER DAS16CS_MISC1_AI_CONV(3) +#define DAS16CS_MISC1_AI_CONV_MASK DAS16CS_MISC1_AI_CONV(3) +#define DAS16CS_MISC1_EOC BIT(7) /* ro - 0=busy; 1=ready */ +#define DAS16CS_MISC1_SEDIFF BIT(5) /* 0=diff; 1=se */ +#define DAS16CS_MISC1_INTB BIT(4) /* ro - 0=latched; 1=cleared */ +#define DAS16CS_MISC1_MA_MASK (0xf << 0) /* ro - current ai mux */ +#define DAS16CS_MISC1_DAC1CS BIT(3) /* wo - DAC1 chip select */ +#define DAS16CS_MISC1_DACCLK BIT(2) /* wo - Serial DAC clock */ +#define DAS16CS_MISC1_DACSD BIT(1) /* wo - Serial DAC data */ +#define DAS16CS_MISC1_DAC0CS BIT(0) /* wo - DAC0 chip select */ +#define DAS16CS_MISC1_DAC_MASK (0x0f << 0) +#define DAS16CS_MISC2_REG 0x06 +#define DAS16CS_MISC2_BME BIT(14) /* 1=burst enable; 0=disable */ +#define DAS16CS_MISC2_AI_GAIN(x) (((x) & 0xf) << 8) /* AI gain */ +#define DAS16CS_MISC2_AI_GAIN_1 DAS16CS_MISC2_AI_GAIN(4) /* +/-10V */ +#define DAS16CS_MISC2_AI_GAIN_2 DAS16CS_MISC2_AI_GAIN(0) /* +/-5V */ +#define DAS16CS_MISC2_AI_GAIN_4 DAS16CS_MISC2_AI_GAIN(1) /* +/-2.5V */ +#define DAS16CS_MISC2_AI_GAIN_8 DAS16CS_MISC2_AI_GAIN(2) /* +-1.25V */ +#define DAS16CS_MISC2_AI_GAIN_MASK DAS16CS_MISC2_AI_GAIN(0xf) +#define DAS16CS_MISC2_UDIR BIT(7) /* 1=dio7:4 output; 0=input */ +#define DAS16CS_MISC2_LDIR BIT(6) /* 1=dio3:0 output; 0=input */ +#define DAS16CS_MISC2_TRGPOL BIT(5) /* 1=active lo; 0=hi */ +#define DAS16CS_MISC2_TRGSEL BIT(4) /* 1=edge; 0=level */ +#define DAS16CS_MISC2_FFNE BIT(3) /* ro - 1=FIFO not empty */ +#define DAS16CS_MISC2_TRGCLR BIT(3) /* wo - 1=clr (monstable) */ +#define DAS16CS_MISC2_CLK2 BIT(2) /* 1=10 MHz; 0=1 MHz */ +#define DAS16CS_MISC2_CTR1 BIT(1) /* 1=int. 100 kHz; 0=ext. clk */ +#define DAS16CS_MISC2_TRG0 BIT(0) /* 1=enable; 0=disable */ +#define DAS16CS_TIMER_BASE 0x08 +#define DAS16CS_DIO_REG 0x10 struct das16cs_board { const char *name; int device_id; - int n_ao_chans; + unsigned int has_ao:1; + unsigned int has_4dio:1; }; static const struct das16cs_board das16cs_boards[] = { { .name = "PC-CARD DAS16/16-AO", .device_id = 0x0039, - .n_ao_chans = 2, + .has_ao = 1, + .has_4dio = 1, }, { .name = "PCM-DAS16s/16", .device_id = 0x4009, - .n_ao_chans = 0, }, { .name = "PC-CARD DAS16/16", .device_id = 0x0000, /* unknown */ - .n_ao_chans = 0, }, }; struct das16cs_private { - unsigned short status1; - unsigned short status2; + unsigned short misc1; + unsigned short misc2; }; static const struct comedi_lrange das16cs_ai_range = { @@ -90,15 +139,16 @@ static int das16cs_ai_eoc(struct comedi_device *dev, { unsigned int status; - status = inw(dev->iobase + DAS16CS_MISC1); - if (status & 0x0080) + status = inw(dev->iobase + DAS16CS_MISC1_REG); + if (status & DAS16CS_MISC1_EOC) return 0; return -EBUSY; } -static int das16cs_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16cs_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das16cs_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); @@ -107,37 +157,43 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, int ret; int i; - outw(chan, dev->iobase + DAS16CS_DIO_MUX); + outw(DAS16CS_AI_MUX_SINGLE_CHAN(chan), + dev->iobase + DAS16CS_AI_MUX_REG); - devpriv->status1 &= ~0xf320; - devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020; - outw(devpriv->status1, dev->iobase + DAS16CS_MISC1); + /* disable interrupts, software convert */ + devpriv->misc1 &= ~(DAS16CS_MISC1_INTE | DAS16CS_MISC1_INT_SRC_MASK | + DAS16CS_MISC1_AI_CONV_MASK); + if (aref == AREF_DIFF) + devpriv->misc1 &= ~DAS16CS_MISC1_SEDIFF; + else + devpriv->misc1 |= DAS16CS_MISC1_SEDIFF; + outw(devpriv->misc1, dev->iobase + DAS16CS_MISC1_REG); - devpriv->status2 &= ~0xff00; + devpriv->misc2 &= ~(DAS16CS_MISC2_BME | DAS16CS_MISC2_AI_GAIN_MASK); switch (range) { case 0: - devpriv->status2 |= 0x800; + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_1; break; case 1: - devpriv->status2 |= 0x000; + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_2; break; case 2: - devpriv->status2 |= 0x100; + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_4; break; case 3: - devpriv->status2 |= 0x200; + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_8; break; } - outw(devpriv->status2, dev->iobase + DAS16CS_MISC2); + outw(devpriv->misc2, dev->iobase + DAS16CS_MISC2_REG); for (i = 0; i < insn->n; i++) { - outw(0, dev->iobase + DAS16CS_ADC_DATA); + outw(0, dev->iobase + DAS16CS_AI_DATA_REG); ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0); if (ret) return ret; - data[i] = inw(dev->iobase + DAS16CS_ADC_DATA); + data[i] = inw(dev->iobase + DAS16CS_AI_DATA_REG); } return i; @@ -151,39 +207,43 @@ static int das16cs_ao_insn_write(struct comedi_device *dev, struct das16cs_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int val = s->readback[chan]; - unsigned short status1; + unsigned short misc1; int bit; int i; for (i = 0; i < insn->n; i++) { val = data[i]; - outw(devpriv->status1, dev->iobase + DAS16CS_MISC1); + outw(devpriv->misc1, dev->iobase + DAS16CS_MISC1_REG); udelay(1); - status1 = devpriv->status1 & ~0xf; + /* raise the DACxCS line for the non-selected channel */ + misc1 = devpriv->misc1 & ~DAS16CS_MISC1_DAC_MASK; if (chan) - status1 |= 0x0001; + misc1 |= DAS16CS_MISC1_DAC0CS; else - status1 |= 0x0008; + misc1 |= DAS16CS_MISC1_DAC1CS; - outw(status1, dev->iobase + DAS16CS_MISC1); + outw(misc1, dev->iobase + DAS16CS_MISC1_REG); udelay(1); for (bit = 15; bit >= 0; bit--) { - int b = (val >> bit) & 0x1; - - b <<= 1; - outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1); + if ((val >> bit) & 0x1) + misc1 |= DAS16CS_MISC1_DACSD; + else + misc1 &= ~DAS16CS_MISC1_DACSD; + outw(misc1, dev->iobase + DAS16CS_MISC1_REG); udelay(1); - outw(status1 | b | 0x0004, dev->iobase + DAS16CS_MISC1); + outw(misc1 | DAS16CS_MISC1_DACCLK, + dev->iobase + DAS16CS_MISC1_REG); udelay(1); } /* * Make both DAC0CS and DAC1CS high to load * the new data and update analog the output */ - outw(status1 | 0x9, dev->iobase + DAS16CS_MISC1); + outw(misc1 | DAS16CS_MISC1_DAC0CS | DAS16CS_MISC1_DAC1CS, + dev->iobase + DAS16CS_MISC1_REG); } s->readback[chan] = val; @@ -196,9 +256,9 @@ static int das16cs_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outw(s->state, dev->iobase + DAS16CS_DIO); + outw(s->state, dev->iobase + DAS16CS_DIO_REG); - data[1] = inw(dev->iobase + DAS16CS_DIO); + data[1] = inw(dev->iobase + DAS16CS_DIO_REG); return insn->n; } @@ -222,11 +282,52 @@ static int das16cs_dio_insn_config(struct comedi_device *dev, if (ret) return ret; - devpriv->status2 &= ~0x00c0; - devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0; - devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0; + if (s->io_bits & 0xf0) + devpriv->misc2 |= DAS16CS_MISC2_UDIR; + else + devpriv->misc2 &= ~DAS16CS_MISC2_UDIR; + if (s->io_bits & 0x0f) + devpriv->misc2 |= DAS16CS_MISC2_LDIR; + else + devpriv->misc2 &= ~DAS16CS_MISC2_LDIR; + outw(devpriv->misc2, dev->iobase + DAS16CS_MISC2_REG); + + return insn->n; +} + +static int das16cs_counter_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct das16cs_private *devpriv = dev->private; - outw(devpriv->status2, dev->iobase + DAS16CS_MISC2); + switch (data[0]) { + case INSN_CONFIG_SET_CLOCK_SRC: + switch (data[1]) { + case 0: /* internal 100 kHz */ + devpriv->misc2 |= DAS16CS_MISC2_CTR1; + break; + case 1: /* external */ + devpriv->misc2 &= ~DAS16CS_MISC2_CTR1; + break; + default: + return -EINVAL; + } + outw(devpriv->misc2, dev->iobase + DAS16CS_MISC2_REG); + break; + case INSN_CONFIG_GET_CLOCK_SRC: + if (devpriv->misc2 & DAS16CS_MISC2_CTR1) { + data[1] = 0; + data[2] = I8254_OSC_BASE_100KHZ; + } else { + data[1] = 1; + data[2] = 0; /* unknown */ + } + break; + default: + return -EINVAL; + } return insn->n; } @@ -278,26 +379,25 @@ static int das16cs_auto_attach(struct comedi_device *dev, if (!dev->pacer) return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 3); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* analog input subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; s->n_chan = 16; s->maxdata = 0xffff; s->range_table = &das16cs_ai_range; - s->len_chanlist = 16; - s->insn_read = das16cs_ai_rinsn; + s->insn_read = das16cs_ai_insn_read; + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* analog output subdevice */ - if (board->n_ao_chans) { + if (board->has_ao) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_ao_chans; + s->n_chan = 2; s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = &das16cs_ao_insn_write; @@ -309,16 +409,26 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } + /* Digital I/O subdevice */ s = &dev->subdevices[2]; - /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; + s->n_chan = board->has_4dio ? 4 : 8; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = das16cs_dio_insn_bits; s->insn_config = das16cs_dio_insn_config; + /* Counter subdevice (8254) */ + s = &dev->subdevices[3]; + comedi_8254_subdevice_init(s, dev->pacer); + + dev->pacer->insn_config = das16cs_counter_insn_config; + + /* counters 1 and 2 are used internally for the pacer */ + comedi_8254_set_busy(dev->pacer, 1, true); + comedi_8254_set_busy(dev->pacer, 2, true); + return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index b43e83657..3cd008acb 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -1,65 +1,64 @@ /* - comedi/drivers/cb_pcidas.c + * cb_pcidas.c + * Developed by Ivan Martinez and Frank Mori Hess, with valuable help from + * David Schleef and the rest of the Comedi developers comunity. + * + * Copyright (C) 2001-2003 Ivan Martinez + * Copyright (C) 2001,2002 Frank Mori Hess + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-8 David A. Schleef + * + * 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. + */ - Developed by Ivan Martinez and Frank Mori Hess, with valuable help from - David Schleef and the rest of the Comedi developers comunity. - - Copyright (C) 2001-2003 Ivan Martinez - Copyright (C) 2001,2002 Frank Mori Hess - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-8 David A. Schleef - - 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_pcidas -Description: MeasurementComputing PCI-DAS series - with the AMCC S5933 PCI controller -Author: Ivan Martinez , - Frank Mori Hess -Updated: 2003-3-11 -Devices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas), - PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr, - PCI-DAS1000, PCI-DAS1001, PCI_DAS1002 - -Status: - There are many reports of the driver being used with most of the - supported cards. Despite no detailed log is maintained, it can - be said that the driver is quite tested and stable. - - The boards may be autocalibrated using the comedi_calibrate - utility. - -Configuration options: not applicable, uses PCI auto config - -For commands, the scanned channels must be consecutive -(i.e. 4-5-6-7, 2-3-4,...), and must all have the same -range and aref. - -AI Triggering: - For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used. - For 1602 series, the start_arg is interpreted as follows: - start_arg == 0 => gated trigger (level high) - start_arg == CR_INVERT => gated trigger (level low) - start_arg == CR_EDGE => Rising edge - start_arg == CR_EDGE | CR_INVERT => Falling edge - For the other boards the trigger will be done on rising edge -*/ /* + * Driver: cb_pcidas + * Description: MeasurementComputing PCI-DAS series + * with the AMCC S5933 PCI controller + * Devices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas), + * PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr, + * PCI-DAS1000, PCI-DAS1001, PCI_DAS1002 + * Author: Ivan Martinez , + * Frank Mori Hess + * Updated: 2003-3-11 + * + * Status: + * There are many reports of the driver being used with most of the + * supported cards. Despite no detailed log is maintained, it can + * be said that the driver is quite tested and stable. + * + * The boards may be autocalibrated using the comedi_calibrate + * utility. + * + * Configuration options: not applicable, uses PCI auto config + * + * For commands, the scanned channels must be consecutive + * (i.e. 4-5-6-7, 2-3-4,...), and must all have the same + * range and aref. + * + * AI Triggering: + * For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used. + * For 1602 series, the start_arg is interpreted as follows: + * start_arg == 0 => gated trigger (level high) + * start_arg == CR_INVERT => gated trigger (level low) + * start_arg == CR_EDGE => Rising edge + * start_arg == CR_EDGE | CR_INVERT => Falling edge + * For the other boards the trigger will be done on rising edge + */ -TODO: - -analog triggering on 1602 series -*/ +/* + * TODO: + * analog triggering on 1602 series + */ #include #include @@ -73,109 +72,107 @@ analog triggering on 1602 series #define AI_BUFFER_SIZE 1024 /* max ai fifo size */ #define AO_BUFFER_SIZE 1024 /* max ao fifo size */ -#define NUM_CHANNELS_8800 8 -#define NUM_CHANNELS_7376 1 -#define NUM_CHANNELS_8402 2 -#define NUM_CHANNELS_DAC08 1 - -/* Control/Status registers */ -#define INT_ADCFIFO 0 /* INTERRUPT / ADC FIFO register */ -#define INT_EOS 0x1 /* int end of scan */ -#define INT_FHF 0x2 /* int fifo half full */ -#define INT_FNE 0x3 /* int fifo not empty */ -#define INT_MASK 0x3 /* mask of int select bits */ -#define INTE 0x4 /* int enable */ -#define DAHFIE 0x8 /* dac half full int enable */ -#define EOAIE 0x10 /* end of acq. int enable */ -#define DAHFI 0x20 /* dac half full status / clear */ -#define EOAI 0x40 /* end of acq. int status / clear */ -#define INT 0x80 /* int status / clear */ -#define EOBI 0x200 /* end of burst int status */ -#define ADHFI 0x400 /* half-full int status */ -#define ADNEI 0x800 /* fifo not empty int status (latch) */ -#define ADNE 0x1000 /* fifo not empty status (realtime) */ -#define DAEMIE 0x1000 /* dac empty int enable */ -#define LADFUL 0x2000 /* fifo overflow / clear */ -#define DAEMI 0x4000 /* dac fifo empty int status / clear */ - -#define ADCMUX_CONT 2 /* ADC CHANNEL MUX AND CONTROL reg */ -#define BEGIN_SCAN(x) ((x) & 0xf) -#define END_SCAN(x) (((x) & 0xf) << 4) -#define GAIN_BITS(x) (((x) & 0x3) << 8) -#define UNIP 0x800 /* Analog front-end unipolar mode */ -#define SE 0x400 /* Inputs in single-ended mode */ -#define PACER_MASK 0x3000 /* pacer source bits */ -#define PACER_INT 0x1000 /* int. pacer */ -#define PACER_EXT_FALL 0x2000 /* ext. falling edge */ -#define PACER_EXT_RISE 0x3000 /* ext. rising edge */ -#define EOC 0x4000 /* adc not busy */ - -#define TRIG_CONTSTAT 4 /* TRIGGER CONTROL/STATUS register */ -#define SW_TRIGGER 0x1 /* software start trigger */ -#define EXT_TRIGGER 0x2 /* ext. start trigger */ -#define ANALOG_TRIGGER 0x3 /* ext. analog trigger */ -#define TRIGGER_MASK 0x3 /* start trigger mask */ -#define TGPOL 0x04 /* invert trigger (1602 only) */ -#define TGSEL 0x08 /* edge/level trigerred (1602 only) */ -#define TGEN 0x10 /* enable external start trigger */ -#define BURSTE 0x20 /* burst mode enable */ -#define XTRCL 0x80 /* clear external trigger */ - -#define CALIBRATION_REG 6 /* CALIBRATION register */ -#define SELECT_8800_BIT 0x100 /* select 8800 caldac */ -#define SELECT_TRIMPOT_BIT 0x200 /* select ad7376 trim pot */ -#define SELECT_DAC08_BIT 0x400 /* select dac08 caldac */ -#define CAL_SRC_BITS(x) (((x) & 0x7) << 11) -#define CAL_EN_BIT 0x4000 /* calibration source enable */ -#define SERIAL_DATA_IN_BIT 0x8000 /* serial data bit going to caldac */ - -#define DAC_CSR 0x8 /* dac control and status register */ -#define DACEN 0x02 /* dac enable */ -#define DAC_MODE_UPDATE_BOTH 0x80 /* update both dacs */ - -static inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range) -{ - return (range & 0x3) << (8 + 2 * (channel & 0x1)); -} - -static inline unsigned int DAC_RANGE_MASK(unsigned int channel) -{ - return 0x3 << (8 + 2 * (channel & 0x1)); -}; - -/* bits for 1602 series only */ -#define DAC_EMPTY 0x1 /* fifo empty, read, write clear */ -#define DAC_START 0x4 /* start/arm fifo operations */ -#define DAC_PACER_MASK 0x18 /* bits that set pacer source */ -#define DAC_PACER_INT 0x8 /* int. pacing */ -#define DAC_PACER_EXT_FALL 0x10 /* ext. pacing, falling edge */ -#define DAC_PACER_EXT_RISE 0x18 /* ext. pacing, rising edge */ - -static inline unsigned int DAC_CHAN_EN(unsigned int channel) -{ - return 1 << (5 + (channel & 0x1)); /* enable channel 0 or 1 */ -}; - -/* analog input fifo */ -#define ADCDATA 0 /* ADC DATA register */ -#define ADCFIFOCLR 2 /* ADC FIFO CLEAR */ -/* pacer, counter, dio registers */ -#define ADC8254 0 -#define DIO_8255 4 -#define DAC8254 8 +/* + * PCI BAR1 Register map (devpriv->pcibar1) + */ +#define PCIDAS_CTRL_REG 0x00 /* INTERRUPT / ADC FIFO register */ +#define PCIDAS_CTRL_INT(x) (((x) & 0x3) << 0) +#define PCIDAS_CTRL_INT_NONE PCIDAS_CTRL_INT(0) /* no int selected */ +#define PCIDAS_CTRL_INT_EOS PCIDAS_CTRL_INT(1) /* int on end of scan */ +#define PCIDAS_CTRL_INT_FHF PCIDAS_CTRL_INT(2) /* int on fifo half full */ +#define PCIDAS_CTRL_INT_FNE PCIDAS_CTRL_INT(3) /* int on fifo not empty */ +#define PCIDAS_CTRL_INT_MASK PCIDAS_CTRL_INT(3) /* mask of int select bits */ +#define PCIDAS_CTRL_INTE BIT(2) /* int enable */ +#define PCIDAS_CTRL_DAHFIE BIT(3) /* dac half full int enable */ +#define PCIDAS_CTRL_EOAIE BIT(4) /* end of acq. int enable */ +#define PCIDAS_CTRL_DAHFI BIT(5) /* dac half full status / clear */ +#define PCIDAS_CTRL_EOAI BIT(6) /* end of acq. int status / clear */ +#define PCIDAS_CTRL_INT_CLR BIT(7) /* int status / clear */ +#define PCIDAS_CTRL_EOBI BIT(9) /* end of burst int status */ +#define PCIDAS_CTRL_ADHFI BIT(10) /* half-full int status */ +#define PCIDAS_CTRL_ADNEI BIT(11) /* fifo not empty int status (latch) */ +#define PCIDAS_CTRL_ADNE BIT(12) /* fifo not empty status (realtime) */ +#define PCIDAS_CTRL_DAEMIE BIT(12) /* dac empty int enable */ +#define PCIDAS_CTRL_LADFUL BIT(13) /* fifo overflow / clear */ +#define PCIDAS_CTRL_DAEMI BIT(14) /* dac fifo empty int status / clear */ + +#define PCIDAS_CTRL_AI_INT (PCIDAS_CTRL_EOAI | PCIDAS_CTRL_EOBI | \ + PCIDAS_CTRL_ADHFI | PCIDAS_CTRL_ADNEI | \ + PCIDAS_CTRL_LADFUL) +#define PCIDAS_CTRL_AO_INT (PCIDAS_CTRL_DAHFI | PCIDAS_CTRL_DAEMI) + +#define PCIDAS_AI_REG 0x02 /* ADC CHANNEL MUX AND CONTROL reg */ +#define PCIDAS_AI_FIRST(x) ((x) & 0xf) +#define PCIDAS_AI_LAST(x) (((x) & 0xf) << 4) +#define PCIDAS_AI_CHAN(x) (PCIDAS_AI_FIRST(x) | PCIDAS_AI_LAST(x)) +#define PCIDAS_AI_GAIN(x) (((x) & 0x3) << 8) +#define PCIDAS_AI_SE BIT(10) /* Inputs in single-ended mode */ +#define PCIDAS_AI_UNIP BIT(11) /* Analog front-end unipolar mode */ +#define PCIDAS_AI_PACER(x) (((x) & 0x3) << 12) +#define PCIDAS_AI_PACER_SW PCIDAS_AI_PACER(0) /* software pacer */ +#define PCIDAS_AI_PACER_INT PCIDAS_AI_PACER(1) /* int. pacer */ +#define PCIDAS_AI_PACER_EXTN PCIDAS_AI_PACER(2) /* ext. falling edge */ +#define PCIDAS_AI_PACER_EXTP PCIDAS_AI_PACER(3) /* ext. rising edge */ +#define PCIDAS_AI_PACER_MASK PCIDAS_AI_PACER(3) /* pacer source bits */ +#define PCIDAS_AI_EOC BIT(14) /* adc not busy */ + +#define PCIDAS_TRIG_REG 0x04 /* TRIGGER CONTROL/STATUS register */ +#define PCIDAS_TRIG_SEL(x) (((x) & 0x3) << 0) +#define PCIDAS_TRIG_SEL_NONE PCIDAS_TRIG_SEL(0) /* no start trigger */ +#define PCIDAS_TRIG_SEL_SW PCIDAS_TRIG_SEL(1) /* software start trigger */ +#define PCIDAS_TRIG_SEL_EXT PCIDAS_TRIG_SEL(2) /* ext. start trigger */ +#define PCIDAS_TRIG_SEL_ANALOG PCIDAS_TRIG_SEL(3) /* ext. analog trigger */ +#define PCIDAS_TRIG_SEL_MASK PCIDAS_TRIG_SEL(3) /* start trigger mask */ +#define PCIDAS_TRIG_POL BIT(2) /* invert trigger (1602 only) */ +#define PCIDAS_TRIG_MODE BIT(3) /* edge/level trigerred (1602 only) */ +#define PCIDAS_TRIG_EN BIT(4) /* enable external start trigger */ +#define PCIDAS_TRIG_BURSTE BIT(5) /* burst mode enable */ +#define PCIDAS_TRIG_CLR BIT(7) /* clear external trigger */ + +#define PCIDAS_CALIB_REG 0x06 /* CALIBRATION register */ +#define PCIDAS_CALIB_8800_SEL BIT(8) /* select 8800 caldac */ +#define PCIDAS_CALIB_TRIM_SEL BIT(9) /* select ad7376 trim pot */ +#define PCIDAS_CALIB_DAC08_SEL BIT(10) /* select dac08 caldac */ +#define PCIDAS_CALIB_SRC(x) (((x) & 0x7) << 11) +#define PCIDAS_CALIB_EN BIT(14) /* calibration source enable */ +#define PCIDAS_CALIB_DATA BIT(15) /* serial data bit going to caldac */ + +#define PCIDAS_AO_REG 0x08 /* dac control and status register */ +#define PCIDAS_AO_EMPTY BIT(0) /* fifo empty, write clear (1602) */ +#define PCIDAS_AO_DACEN BIT(1) /* dac enable */ +#define PCIDAS_AO_START BIT(2) /* start/arm fifo (1602) */ +#define PCIDAS_AO_PACER(x) (((x) & 0x3) << 3) /* (1602) */ +#define PCIDAS_AO_PACER_SW PCIDAS_AO_PACER(0) /* software pacer */ +#define PCIDAS_AO_PACER_INT PCIDAS_AO_PACER(1) /* int. pacer */ +#define PCIDAS_AO_PACER_EXTN PCIDAS_AO_PACER(2) /* ext. falling edge */ +#define PCIDAS_AO_PACER_EXTP PCIDAS_AO_PACER(3) /* ext. rising edge */ +#define PCIDAS_AO_PACER_MASK PCIDAS_AO_PACER(3) /* pacer source bits */ +#define PCIDAS_AO_CHAN_EN(c) BIT(5 + ((c) & 0x1)) +#define PCIDAS_AO_CHAN_MASK (PCIDAS_AO_CHAN_EN(0) | PCIDAS_AO_CHAN_EN(1)) +#define PCIDAS_AO_UPDATE_BOTH BIT(7) /* update both dacs */ +#define PCIDAS_AO_RANGE(c, r) (((r) & 0x3) << (8 + 2 * ((c) & 0x1))) +#define PCIDAS_AO_RANGE_MASK(c) PCIDAS_AO_RANGE((c), 0x3) -/* analog output registers for 100x, 1200 series */ -static inline unsigned int DAC_DATA_REG(unsigned int channel) -{ - return 2 * (channel & 0x1); -} +/* + * PCI BAR2 Register map (devpriv->pcibar2) + */ +#define PCIDAS_AI_DATA_REG 0x00 +#define PCIDAS_AI_FIFO_CLR_REG 0x02 -/* analog output registers for 1602 series*/ -#define DACDATA 0 /* DAC DATA register */ -#define DACFIFOCLR 2 /* DAC FIFO CLEAR */ +/* + * PCI BAR3 Register map (dev->iobase) + */ +#define PCIDAS_AI_8254_BASE 0x00 +#define PCIDAS_8255_BASE 0x04 +#define PCIDAS_AO_8254_BASE 0x08 -#define IS_UNIPOLAR 0x4 /* unipolar range mask */ +/* + * PCI BAR4 Register map (devpriv->pcibar4) + */ +#define PCIDAS_AO_DATA_REG(x) (0x00 + ((x) * 2)) +#define PCIDAS_AO_FIFO_REG 0x00 +#define PCIDAS_AO_FIFO_CLR_REG 0x02 /* analog input ranges for most boards */ static const struct comedi_lrange cb_pcidas_ranges = { @@ -215,11 +212,6 @@ static const struct comedi_lrange cb_pcidas_ao_ranges = { } }; -enum trimpot_model { - AD7376, - AD8402, -}; - enum cb_pcidas_boardid { BOARD_PCIDAS1602_16, BOARD_PCIDAS1200, @@ -233,132 +225,97 @@ enum cb_pcidas_boardid { struct cb_pcidas_board { const char *name; - int ai_nchan; /* Inputs in single-ended mode */ - int ai_bits; /* analog input resolution */ int ai_speed; /* fastest conversion period in ns */ - int ao_nchan; /* number of analog out channels */ - int has_ao_fifo; /* analog output has fifo */ int ao_scan_speed; /* analog output scan speed for 1602 series */ int fifo_size; /* number of samples fifo can hold */ - const struct comedi_lrange *ranges; - enum trimpot_model trimpot; - unsigned has_dac08:1; - unsigned is_1602:1; + unsigned int is_16bit; /* ai/ao is 1=16-bit; 0=12-bit */ + unsigned int use_alt_range:1; /* use alternate ai range table */ + unsigned int has_ao:1; /* has 2 analog output channels */ + unsigned int has_ao_fifo:1; /* analog output has fifo */ + unsigned int has_ad8402:1; /* trimpot type 1=AD8402; 0=AD7376 */ + unsigned int has_dac08:1; + unsigned int is_1602:1; }; static const struct cb_pcidas_board cb_pcidas_boards[] = { [BOARD_PCIDAS1602_16] = { .name = "pci-das1602/16", - .ai_nchan = 16, - .ai_bits = 16, .ai_speed = 5000, - .ao_nchan = 2, - .has_ao_fifo = 1, .ao_scan_speed = 10000, .fifo_size = 512, - .ranges = &cb_pcidas_ranges, - .trimpot = AD8402, + .is_16bit = 1, + .has_ao = 1, + .has_ao_fifo = 1, + .has_ad8402 = 1, .has_dac08 = 1, .is_1602 = 1, }, [BOARD_PCIDAS1200] = { .name = "pci-das1200", - .ai_nchan = 16, - .ai_bits = 12, .ai_speed = 3200, - .ao_nchan = 2, .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, + .has_ao = 1, }, [BOARD_PCIDAS1602_12] = { .name = "pci-das1602/12", - .ai_nchan = 16, - .ai_bits = 12, .ai_speed = 3200, - .ao_nchan = 2, - .has_ao_fifo = 1, .ao_scan_speed = 4000, .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, + .has_ao = 1, + .has_ao_fifo = 1, .is_1602 = 1, }, [BOARD_PCIDAS1200_JR] = { .name = "pci-das1200/jr", - .ai_nchan = 16, - .ai_bits = 12, .ai_speed = 3200, .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, }, [BOARD_PCIDAS1602_16_JR] = { .name = "pci-das1602/16/jr", - .ai_nchan = 16, - .ai_bits = 16, .ai_speed = 5000, .fifo_size = 512, - .ranges = &cb_pcidas_ranges, - .trimpot = AD8402, + .is_16bit = 1, + .has_ad8402 = 1, .has_dac08 = 1, .is_1602 = 1, }, [BOARD_PCIDAS1000] = { .name = "pci-das1000", - .ai_nchan = 16, - .ai_bits = 12, .ai_speed = 4000, .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, }, [BOARD_PCIDAS1001] = { .name = "pci-das1001", - .ai_nchan = 16, - .ai_bits = 12, .ai_speed = 6800, - .ao_nchan = 2, .fifo_size = 1024, - .ranges = &cb_pcidas_alt_ranges, - .trimpot = AD7376, + .use_alt_range = 1, + .has_ao = 1, }, [BOARD_PCIDAS1002] = { .name = "pci-das1002", - .ai_nchan = 16, - .ai_bits = 12, .ai_speed = 6800, - .ao_nchan = 2, .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, + .has_ao = 1, }, }; struct cb_pcidas_private { struct comedi_8254 *ao_pacer; /* base addresses */ - unsigned long s5933_config; - unsigned long control_status; - unsigned long adc_fifo; - unsigned long ao_registers; + unsigned long amcc; /* pcibar0 */ + unsigned long pcibar1; + unsigned long pcibar2; + unsigned long pcibar4; /* bits to write to registers */ - unsigned int adc_fifo_bits; - unsigned int s5933_intcsr_bits; - unsigned int ao_control_bits; + unsigned int ctrl; + unsigned int amcc_intcsr; + unsigned int ao_ctrl; /* fifo buffers */ unsigned short ai_buffer[AI_BUFFER_SIZE]; unsigned short ao_buffer[AO_BUFFER_SIZE]; - unsigned int calibration_source; + unsigned int calib_src; }; -static inline unsigned int cal_enable_bits(struct comedi_device *dev) -{ - struct cb_pcidas_private *devpriv = dev->private; - - return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); -} - static int cb_pcidas_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -367,15 +324,16 @@ static int cb_pcidas_ai_eoc(struct comedi_device *dev, struct cb_pcidas_private *devpriv = dev->private; unsigned int status; - status = inw(devpriv->control_status + ADCMUX_CONT); - if (status & EOC) + status = inw(devpriv->pcibar1 + PCIDAS_AI_REG); + if (status & PCIDAS_AI_EOC) return 0; return -EBUSY; } -static int cb_pcidas_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct cb_pcidas_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); @@ -387,30 +345,30 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, /* enable calibration input if appropriate */ if (insn->chanspec & CR_ALT_SOURCE) { - outw(cal_enable_bits(dev), - devpriv->control_status + CALIBRATION_REG); + outw(PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src), + devpriv->pcibar1 + PCIDAS_CALIB_REG); chan = 0; } else { - outw(0, devpriv->control_status + CALIBRATION_REG); + outw(0, devpriv->pcibar1 + PCIDAS_CALIB_REG); } /* set mux limits and gain */ - bits = BEGIN_SCAN(chan) | END_SCAN(chan) | GAIN_BITS(range); + bits = PCIDAS_AI_CHAN(chan) | PCIDAS_AI_GAIN(range); /* set unipolar/bipolar */ - if (range & IS_UNIPOLAR) - bits |= UNIP; + if (comedi_range_is_unipolar(s, range)) + bits |= PCIDAS_AI_UNIP; /* set single-ended/differential */ if (aref != AREF_DIFF) - bits |= SE; - outw(bits, devpriv->control_status + ADCMUX_CONT); + bits |= PCIDAS_AI_SE; + outw(bits, devpriv->pcibar1 + PCIDAS_AI_REG); /* clear fifo */ - outw(0, devpriv->adc_fifo + ADCFIFOCLR); + outw(0, devpriv->pcibar2 + PCIDAS_AI_FIFO_CLR_REG); /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ - outw(0, devpriv->adc_fifo + ADCDATA); + outw(0, devpriv->pcibar2 + PCIDAS_AI_DATA_REG); /* wait for conversion to end */ ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0); @@ -418,15 +376,17 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, return ret; /* read data */ - data[n] = inw(devpriv->adc_fifo + ADCDATA); + data[n] = inw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG); } /* return the number of samples read/written */ return n; } -static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas_ai_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct cb_pcidas_private *devpriv = dev->private; int id = data[0]; @@ -440,7 +400,7 @@ static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, source); return -EINVAL; } - devpriv->calibration_source = source; + devpriv->calib_src = source; break; default: return -EINVAL; @@ -449,155 +409,160 @@ static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, } /* analog output insn for pcidas-1000 and 1200 series */ -static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int cb_pcidas_ao_nofifo_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct cb_pcidas_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = s->readback[chan]; unsigned long flags; + int i; /* set channel and range */ spin_lock_irqsave(&dev->spinlock, flags); - devpriv->ao_control_bits &= (~DAC_MODE_UPDATE_BOTH & - ~DAC_RANGE_MASK(chan)); - devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range)); - outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); + devpriv->ao_ctrl &= ~(PCIDAS_AO_UPDATE_BOTH | + PCIDAS_AO_RANGE_MASK(chan)); + devpriv->ao_ctrl |= PCIDAS_AO_DACEN | PCIDAS_AO_RANGE(chan, range); + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); spin_unlock_irqrestore(&dev->spinlock, flags); - /* remember value for readback */ - s->readback[chan] = data[0]; + for (i = 0; i < insn->n; i++) { + val = data[i]; + outw(val, devpriv->pcibar4 + PCIDAS_AO_DATA_REG(chan)); + } - /* send data */ - outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan)); + s->readback[chan] = val; return insn->n; } /* analog output insn for pcidas-1602 series */ -static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcidas_ao_fifo_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct cb_pcidas_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = s->readback[chan]; unsigned long flags; + int i; /* clear dac fifo */ - outw(0, devpriv->ao_registers + DACFIFOCLR); + outw(0, devpriv->pcibar4 + PCIDAS_AO_FIFO_CLR_REG); /* set channel and range */ spin_lock_irqsave(&dev->spinlock, flags); - devpriv->ao_control_bits &= (~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) & - ~DAC_RANGE_MASK(chan) & ~DAC_PACER_MASK); - devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range) | - DAC_CHAN_EN(chan) | DAC_START); - outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); + devpriv->ao_ctrl &= ~(PCIDAS_AO_CHAN_MASK | PCIDAS_AO_RANGE_MASK(chan) | + PCIDAS_AO_PACER_MASK); + devpriv->ao_ctrl |= PCIDAS_AO_DACEN | PCIDAS_AO_RANGE(chan, range) | + PCIDAS_AO_CHAN_EN(chan) | PCIDAS_AO_START; + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); spin_unlock_irqrestore(&dev->spinlock, flags); - /* remember value for readback */ - s->readback[chan] = data[0]; + for (i = 0; i < insn->n; i++) { + val = data[i]; + outw(val, devpriv->pcibar4 + PCIDAS_AO_FIFO_REG); + } - /* send data */ - outw(data[0], devpriv->ao_registers + DACDATA); + s->readback[chan] = val; return insn->n; } -static int wait_for_nvram_ready(unsigned long s5933_base_addr) +static int cb_pcidas_eeprom_ready(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - static const int timeout = 1000; - unsigned int i; + struct cb_pcidas_private *devpriv = dev->private; + unsigned int status; - for (i = 0; i < timeout; i++) { - if ((inb(s5933_base_addr + - AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY) - == 0) - return 0; - udelay(1); - } - return -1; + status = inb(devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); + if ((status & MCSR_NV_BUSY) == 0) + return 0; + return -EBUSY; } -static int nvram_read(struct comedi_device *dev, unsigned int address, - uint8_t *data) +static int cb_pcidas_eeprom_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct cb_pcidas_private *devpriv = dev->private; - unsigned long iobase = devpriv->s5933_config; - - if (wait_for_nvram_ready(iobase) < 0) - return -ETIMEDOUT; - - outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, - iobase + AMCC_OP_REG_MCSR_NVCMD); - outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); - outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, - iobase + AMCC_OP_REG_MCSR_NVCMD); - outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); - outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); - - if (wait_for_nvram_ready(iobase) < 0) - return -ETIMEDOUT; - - *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); - - return 0; -} + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; + int i; -static int eeprom_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - uint8_t nvram_data; - int retval; + for (i = 0; i < insn->n; i++) { + /* make sure eeprom is ready */ + ret = comedi_timeout(dev, s, insn, cb_pcidas_eeprom_ready, 0); + if (ret) + return ret; - retval = nvram_read(dev, CR_CHAN(insn->chanspec), &nvram_data); - if (retval < 0) - return retval; + /* set address (chan) and read operation */ + outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, + devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); + outb(chan & 0xff, devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA); + outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, + devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); + outb((chan >> 8) & 0xff, + devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA); + outb(MCSR_NV_ENABLE | MCSR_NV_READ, + devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); + + /* wait for data to be returned */ + ret = comedi_timeout(dev, s, insn, cb_pcidas_eeprom_ready, 0); + if (ret) + return ret; - data[0] = nvram_data; + data[i] = inb(devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA); + } - return 1; + return insn->n; } -static void write_calibration_bitstream(struct comedi_device *dev, - unsigned int register_bits, - unsigned int bitstream, - unsigned int bitstream_length) +static void cb_pcidas_calib_write(struct comedi_device *dev, + unsigned int val, unsigned int len, + bool trimpot) { struct cb_pcidas_private *devpriv = dev->private; - static const int write_delay = 1; + unsigned int calib_bits; unsigned int bit; - for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { - if (bitstream & bit) - register_bits |= SERIAL_DATA_IN_BIT; + calib_bits = PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src); + if (trimpot) { + /* select trimpot */ + calib_bits |= PCIDAS_CALIB_TRIM_SEL; + outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG); + } + + /* write bitstream to calibration device */ + for (bit = 1 << (len - 1); bit; bit >>= 1) { + if (val & bit) + calib_bits |= PCIDAS_CALIB_DATA; else - register_bits &= ~SERIAL_DATA_IN_BIT; - udelay(write_delay); - outw(register_bits, devpriv->control_status + CALIBRATION_REG); + calib_bits &= ~PCIDAS_CALIB_DATA; + udelay(1); + outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG); } -} + udelay(1); -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 bitstream_length = 11; - unsigned int bitstream = ((chan & 0x7) << 8) | val; - static const int caldac_8800_udelay = 1; - - write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream, - bitstream_length); - - udelay(caldac_8800_udelay); - outw(cal_enable_bits(dev) | SELECT_8800_BIT, - devpriv->control_status + CALIBRATION_REG); - udelay(caldac_8800_udelay); - outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); + calib_bits = PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src); + + if (!trimpot) { + /* select caldac */ + outw(calib_bits | PCIDAS_CALIB_8800_SEL, + devpriv->pcibar1 + PCIDAS_CALIB_REG); + udelay(1); + } + + /* latch value to trimpot/caldac */ + outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG); } static int cb_pcidas_caldac_insn_write(struct comedi_device *dev, @@ -611,7 +576,9 @@ static int cb_pcidas_caldac_insn_write(struct comedi_device *dev, unsigned int val = data[insn->n - 1]; if (s->readback[chan] != val) { - caldac_8800_write(dev, chan, val); + /* write 11-bit channel/value to caldac */ + cb_pcidas_calib_write(dev, (chan << 8) | val, 11, + false); s->readback[chan] = val; } } @@ -619,21 +586,19 @@ static int cb_pcidas_caldac_insn_write(struct comedi_device *dev, return insn->n; } -/* 1602/16 pregain offset */ -static void dac08_write(struct comedi_device *dev, unsigned int value) +static void cb_pcidas_dac08_write(struct comedi_device *dev, unsigned int val) { struct cb_pcidas_private *devpriv = dev->private; - value &= 0xff; - value |= cal_enable_bits(dev); + val |= PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src); /* latch the new value into the caldac */ - outw(value, devpriv->control_status + CALIBRATION_REG); + outw(val, devpriv->pcibar1 + PCIDAS_CALIB_REG); udelay(1); - outw(value | SELECT_DAC08_BIT, - devpriv->control_status + CALIBRATION_REG); + outw(val | PCIDAS_CALIB_DAC08_SEL, + devpriv->pcibar1 + PCIDAS_CALIB_REG); udelay(1); - outw(value, devpriv->control_status + CALIBRATION_REG); + outw(val, devpriv->pcibar1 + PCIDAS_CALIB_REG); udelay(1); } @@ -648,7 +613,7 @@ static int cb_pcidas_dac08_insn_write(struct comedi_device *dev, unsigned int val = data[insn->n - 1]; if (s->readback[chan] != val) { - dac08_write(dev, val); + cb_pcidas_dac08_write(dev, val); s->readback[chan] = val; } } @@ -656,67 +621,17 @@ static int cb_pcidas_dac08_insn_write(struct comedi_device *dev, return insn->n; } -static int trimpot_7376_write(struct comedi_device *dev, uint8_t value) -{ - struct cb_pcidas_private *devpriv = dev->private; - static const int bitstream_length = 7; - unsigned int bitstream = value & 0x7f; - unsigned int register_bits; - static const int ad7376_udelay = 1; - - register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; - udelay(ad7376_udelay); - outw(register_bits, devpriv->control_status + CALIBRATION_REG); - - write_calibration_bitstream(dev, register_bits, bitstream, - bitstream_length); - - udelay(ad7376_udelay); - outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); - - return 0; -} - -/* For 1602/16 only - * ch 0 : adc gain - * ch 1 : adc postgain offset */ -static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, - uint8_t value) -{ - struct cb_pcidas_private *devpriv = dev->private; - static const int bitstream_length = 10; - unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); - unsigned int register_bits; - static const int ad8402_udelay = 1; - - register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; - udelay(ad8402_udelay); - outw(register_bits, devpriv->control_status + CALIBRATION_REG); - - write_calibration_bitstream(dev, register_bits, bitstream, - bitstream_length); - - udelay(ad8402_udelay); - outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); - - return 0; -} - static void cb_pcidas_trimpot_write(struct comedi_device *dev, unsigned int chan, unsigned int val) { const struct cb_pcidas_board *board = dev->board_ptr; - switch (board->trimpot) { - case AD7376: - trimpot_7376_write(dev, val); - break; - case AD8402: - trimpot_8402_write(dev, chan, val); - break; - default: - dev_err(dev->class_dev, "driver bug?\n"); - break; + if (board->has_ad8402) { + /* write 10-bit channel/value to AD8402 trimpot */ + cb_pcidas_calib_write(dev, (chan << 8) | val, 10, true); + } else { + /* write 7-bit value to AD7376 trimpot */ + cb_pcidas_calib_write(dev, val, 7, true); } } @@ -883,32 +798,33 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, struct cb_pcidas_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); unsigned int bits; unsigned long flags; - /* make sure CAL_EN_BIT is disabled */ - outw(0, devpriv->control_status + CALIBRATION_REG); + /* make sure PCIDAS_CALIB_EN is disabled */ + outw(0, devpriv->pcibar1 + PCIDAS_CALIB_REG); /* initialize before settings pacer source and count values */ - outw(0, devpriv->control_status + TRIG_CONTSTAT); + outw(PCIDAS_TRIG_SEL_NONE, devpriv->pcibar1 + PCIDAS_TRIG_REG); /* clear fifo */ - outw(0, devpriv->adc_fifo + ADCFIFOCLR); + outw(0, devpriv->pcibar2 + PCIDAS_AI_FIFO_CLR_REG); /* set mux limits, gain and pacer source */ - bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) | - END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) | - GAIN_BITS(CR_RANGE(cmd->chanlist[0])); + bits = PCIDAS_AI_FIRST(CR_CHAN(cmd->chanlist[0])) | + PCIDAS_AI_LAST(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) | + PCIDAS_AI_GAIN(range0); /* set unipolar/bipolar */ - if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR) - bits |= UNIP; + if (comedi_range_is_unipolar(s, range0)) + bits |= PCIDAS_AI_UNIP; /* set singleended/differential */ if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF) - bits |= SE; + bits |= PCIDAS_AI_SE; /* set pacer source */ if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT) - bits |= PACER_EXT_RISE; + bits |= PCIDAS_AI_PACER_EXTP; else - bits |= PACER_INT; - outw(bits, devpriv->control_status + ADCMUX_CONT); + bits |= PCIDAS_AI_PACER_INT; + outw(bits, devpriv->pcibar1 + PCIDAS_AI_REG); /* load counters */ if (cmd->scan_begin_src == TRIG_TIMER || @@ -919,42 +835,43 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, /* enable interrupts */ spin_lock_irqsave(&dev->spinlock, flags); - devpriv->adc_fifo_bits |= INTE; - devpriv->adc_fifo_bits &= ~INT_MASK; + devpriv->ctrl |= PCIDAS_CTRL_INTE; + devpriv->ctrl &= ~PCIDAS_CTRL_INT_MASK; if (cmd->flags & CMDF_WAKE_EOS) { if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) { /* interrupt end of burst */ - devpriv->adc_fifo_bits |= INT_EOS; + devpriv->ctrl |= PCIDAS_CTRL_INT_EOS; } else { /* interrupt fifo not empty */ - devpriv->adc_fifo_bits |= INT_FNE; + devpriv->ctrl |= PCIDAS_CTRL_INT_FNE; } } else { /* interrupt fifo half full */ - devpriv->adc_fifo_bits |= INT_FHF; + devpriv->ctrl |= PCIDAS_CTRL_INT_FHF; } /* enable (and clear) interrupts */ - outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL, - devpriv->control_status + INT_ADCFIFO); + outw(devpriv->ctrl | + PCIDAS_CTRL_EOAI | PCIDAS_CTRL_INT_CLR | PCIDAS_CTRL_LADFUL, + devpriv->pcibar1 + PCIDAS_CTRL_REG); spin_unlock_irqrestore(&dev->spinlock, flags); /* set start trigger and burst mode */ bits = 0; if (cmd->start_src == TRIG_NOW) { - bits |= SW_TRIGGER; + bits |= PCIDAS_TRIG_SEL_SW; } else { /* TRIG_EXT */ - bits |= EXT_TRIGGER | TGEN | XTRCL; + bits |= PCIDAS_TRIG_SEL_EXT | PCIDAS_TRIG_EN | PCIDAS_TRIG_CLR; if (board->is_1602) { if (cmd->start_arg & CR_INVERT) - bits |= TGPOL; + bits |= PCIDAS_TRIG_POL; if (cmd->start_arg & CR_EDGE) - bits |= TGSEL; + bits |= PCIDAS_TRIG_MODE; } } if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) - bits |= BURSTE; - outw(bits, devpriv->control_status + TRIG_CONTSTAT); + bits |= PCIDAS_TRIG_BURSTE; + outw(bits, devpriv->pcibar1 + PCIDAS_TRIG_REG); return 0; } @@ -1051,23 +968,21 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, return 0; } -/* cancel analog input command */ -static int cb_pcidas_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int cb_pcidas_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct cb_pcidas_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); /* disable interrupts */ - devpriv->adc_fifo_bits &= ~INTE & ~EOAIE; - outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); + devpriv->ctrl &= ~(PCIDAS_CTRL_INTE | PCIDAS_CTRL_EOAIE); + outw(devpriv->ctrl, devpriv->pcibar1 + PCIDAS_CTRL_REG); spin_unlock_irqrestore(&dev->spinlock, flags); /* disable start trigger source and burst mode */ - outw(0, devpriv->control_status + TRIG_CONTSTAT); - /* software pacer source */ - outw(0, devpriv->control_status + ADCMUX_CONT); + outw(PCIDAS_TRIG_SEL_NONE, devpriv->pcibar1 + PCIDAS_TRIG_REG); + outw(PCIDAS_AI_PACER_SW, devpriv->pcibar1 + PCIDAS_AI_REG); return 0; } @@ -1083,7 +998,8 @@ static void cb_pcidas_ao_load_fifo(struct comedi_device *dev, 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); + outsw(devpriv->pcibar4 + PCIDAS_AO_FIFO_REG, + devpriv->ao_buffer, nsamples); } static int cb_pcidas_ao_inttrig(struct comedi_device *dev, @@ -1103,15 +1019,15 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, /* enable dac half-full and empty interrupts */ spin_lock_irqsave(&dev->spinlock, flags); - devpriv->adc_fifo_bits |= DAEMIE | DAHFIE; + devpriv->ctrl |= PCIDAS_CTRL_DAEMIE | PCIDAS_CTRL_DAHFIE; /* enable and clear interrupts */ - outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, - devpriv->control_status + INT_ADCFIFO); + outw(devpriv->ctrl | PCIDAS_CTRL_DAEMI | PCIDAS_CTRL_DAHFI, + devpriv->pcibar1 + PCIDAS_CTRL_REG); /* start dac */ - devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY; - outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); + devpriv->ao_ctrl |= PCIDAS_AO_START | PCIDAS_AO_DACEN | PCIDAS_AO_EMPTY; + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); spin_unlock_irqrestore(&dev->spinlock, flags); @@ -1132,21 +1048,21 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, /* set channel limits, gain */ spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + /* enable channel */ - devpriv->ao_control_bits |= - DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i])); + devpriv->ao_ctrl |= PCIDAS_AO_CHAN_EN(chan); /* set range */ - devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]), - CR_RANGE(cmd-> - chanlist[i])); + devpriv->ao_ctrl |= PCIDAS_AO_RANGE(chan, range); } /* disable analog out before settings pacer source and count values */ - outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); spin_unlock_irqrestore(&dev->spinlock, flags); /* clear fifo */ - outw(0, devpriv->ao_registers + DACFIFOCLR); + outw(0, devpriv->pcibar4 + PCIDAS_AO_FIFO_CLR_REG); /* load counters */ if (cmd->scan_begin_src == TRIG_TIMER) { @@ -1158,10 +1074,10 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, spin_lock_irqsave(&dev->spinlock, flags); switch (cmd->scan_begin_src) { case TRIG_TIMER: - devpriv->ao_control_bits |= DAC_PACER_INT; + devpriv->ao_ctrl |= PCIDAS_AO_PACER_INT; break; case TRIG_EXT: - devpriv->ao_control_bits |= DAC_PACER_EXT_RISE; + devpriv->ao_ctrl |= PCIDAS_AO_PACER_EXTP; break; default: spin_unlock_irqrestore(&dev->spinlock, flags); @@ -1175,7 +1091,6 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, return 0; } -/* cancel analog output command */ static int cb_pcidas_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1184,33 +1099,31 @@ static int cb_pcidas_ao_cancel(struct comedi_device *dev, spin_lock_irqsave(&dev->spinlock, flags); /* disable interrupts */ - devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE; - outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); + devpriv->ctrl &= ~(PCIDAS_CTRL_DAHFIE | PCIDAS_CTRL_DAEMIE); + outw(devpriv->ctrl, devpriv->pcibar1 + PCIDAS_CTRL_REG); /* disable output */ - devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK; - outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); + devpriv->ao_ctrl &= ~(PCIDAS_AO_DACEN | PCIDAS_AO_PACER_MASK); + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } -static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) +static unsigned int cb_pcidas_ao_interrupt(struct comedi_device *dev, + unsigned int status) { const struct cb_pcidas_board *board = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; struct comedi_subdevice *s = dev->write_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - unsigned long flags; + unsigned int irq_clr = 0; - if (status & DAEMI) { - /* clear dac empty interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | DAEMI, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); - if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) { + if (status & PCIDAS_CTRL_DAEMI) { + irq_clr |= PCIDAS_CTRL_DAEMI; + + if (inw(devpriv->pcibar4 + PCIDAS_AO_REG) & PCIDAS_AO_EMPTY) { if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) { async->events |= COMEDI_CB_EOA; @@ -1219,83 +1132,55 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) async->events |= COMEDI_CB_ERROR; } } - } else if (status & DAHFI) { - cb_pcidas_ao_load_fifo(dev, s, board->fifo_size / 2); + } else if (status & PCIDAS_CTRL_DAHFI) { + irq_clr |= PCIDAS_CTRL_DAHFI; - /* clear half-full interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | DAHFI, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); + cb_pcidas_ao_load_fifo(dev, s, board->fifo_size / 2); } comedi_handle_events(dev, s); + + return irq_clr; } -static irqreturn_t cb_pcidas_interrupt(int irq, void *d) +static unsigned int cb_pcidas_ai_interrupt(struct comedi_device *dev, + unsigned int status) { - struct comedi_device *dev = (struct comedi_device *)d; const struct cb_pcidas_board *board = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async; - struct comedi_cmd *cmd; - int status, s5933_status; - int half_fifo = board->fifo_size / 2; - unsigned int num_samples, i; - static const int timeout = 10000; - unsigned long flags; - - if (!dev->attached) - return IRQ_NONE; - - async = s->async; - cmd = &async->cmd; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int irq_clr = 0; - s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); + if (status & PCIDAS_CTRL_ADHFI) { + unsigned int num_samples; - if ((INTCSR_INTR_ASSERTED & s5933_status) == 0) - return IRQ_NONE; + irq_clr |= PCIDAS_CTRL_INT_CLR; - /* make sure mailbox 4 is empty */ - inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4); - /* clear interrupt on amcc s5933 */ - outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); - - status = inw(devpriv->control_status + INT_ADCFIFO); - - /* check for analog output interrupt */ - if (status & (DAHFI | DAEMI)) - handle_ao_interrupt(dev, status); - /* check for analog input interrupts */ - /* if fifo half-full */ - if (status & ADHFI) { - /* read data */ - num_samples = comedi_nsamples_left(s, half_fifo); - insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer, - num_samples); + /* FIFO is half-full - read data */ + num_samples = comedi_nsamples_left(s, board->fifo_size / 2); + insw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG, + devpriv->ai_buffer, num_samples); 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; + } else if (status & (PCIDAS_CTRL_ADNEI | PCIDAS_CTRL_EOBI)) { + unsigned int i; - /* clear half-full interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | INT, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); - /* else if fifo not empty */ - } else if (status & (ADNEI | EOBI)) { - for (i = 0; i < timeout; i++) { + irq_clr |= PCIDAS_CTRL_INT_CLR; + + /* FIFO is not empty - read data until empty or timeoout */ + for (i = 0; i < 10000; i++) { unsigned short val; /* break if fifo is empty */ - if ((ADNE & inw(devpriv->control_status + - INT_ADCFIFO)) == 0) + if ((inw(devpriv->pcibar1 + PCIDAS_CTRL_REG) & + PCIDAS_CTRL_ADNE) == 0) break; - val = inw(devpriv->adc_fifo); + val = inw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG); comedi_buf_write_samples(s, &val, 1); if (cmd->stop_src == TRIG_COUNT && @@ -1304,33 +1189,67 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) break; } } - /* clear not-empty interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | INT, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); - } else if (status & EOAI) { + } else if (status & PCIDAS_CTRL_EOAI) { + irq_clr |= PCIDAS_CTRL_EOAI; + dev_err(dev->class_dev, "bug! encountered end of acquisition interrupt?\n"); - /* clear EOA interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | EOAI, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); } + /* check for fifo overflow */ - if (status & LADFUL) { + if (status & PCIDAS_CTRL_LADFUL) { + irq_clr |= PCIDAS_CTRL_LADFUL; + dev_err(dev->class_dev, "fifo overflow\n"); - /* clear overflow interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | LADFUL, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); async->events |= COMEDI_CB_ERROR; } comedi_handle_events(dev, s); + return irq_clr; +} + +static irqreturn_t cb_pcidas_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct cb_pcidas_private *devpriv = dev->private; + unsigned int irq_clr = 0; + unsigned int amcc_status; + unsigned int status; + + if (!dev->attached) + return IRQ_NONE; + + amcc_status = inl(devpriv->amcc + AMCC_OP_REG_INTCSR); + + if ((INTCSR_INTR_ASSERTED & amcc_status) == 0) + return IRQ_NONE; + + /* make sure mailbox 4 is empty */ + inl_p(devpriv->amcc + AMCC_OP_REG_IMB4); + /* clear interrupt on amcc s5933 */ + outl(devpriv->amcc_intcsr | INTCSR_INBOX_INTR_STATUS, + devpriv->amcc + AMCC_OP_REG_INTCSR); + + status = inw(devpriv->pcibar1 + PCIDAS_CTRL_REG); + + /* handle analog output interrupts */ + if (status & PCIDAS_CTRL_AO_INT) + irq_clr |= cb_pcidas_ao_interrupt(dev, status); + + /* handle analog input interrupts */ + if (status & PCIDAS_CTRL_AI_INT) + irq_clr |= cb_pcidas_ai_interrupt(dev, status); + + if (irq_clr) { + unsigned long flags; + + spin_lock_irqsave(&dev->spinlock, flags); + outw(devpriv->ctrl | irq_clr, + devpriv->pcibar1 + PCIDAS_CTRL_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + } + return IRQ_HANDLED; } @@ -1359,16 +1278,16 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, if (ret) return ret; - devpriv->s5933_config = pci_resource_start(pcidev, 0); - devpriv->control_status = pci_resource_start(pcidev, 1); - devpriv->adc_fifo = pci_resource_start(pcidev, 2); + devpriv->amcc = pci_resource_start(pcidev, 0); + devpriv->pcibar1 = pci_resource_start(pcidev, 1); + devpriv->pcibar2 = pci_resource_start(pcidev, 2); dev->iobase = pci_resource_start(pcidev, 3); - if (board->ao_nchan) - devpriv->ao_registers = pci_resource_start(pcidev, 4); + if (board->has_ao) + devpriv->pcibar4 = pci_resource_start(pcidev, 4); /* disable and clear interrupts on amcc s5933 */ outl(INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); + devpriv->amcc + AMCC_OP_REG_INTCSR); ret = request_irq(pcidev->irq, cb_pcidas_interrupt, IRQF_SHARED, dev->board_name, dev); @@ -1379,12 +1298,12 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, } dev->irq = pcidev->irq; - dev->pacer = comedi_8254_init(dev->iobase + ADC8254, + dev->pacer = comedi_8254_init(dev->iobase + PCIDAS_AI_8254_BASE, I8254_OSC_BASE_10MHZ, I8254_IO8, 0); if (!dev->pacer) return -ENOMEM; - devpriv->ao_pacer = comedi_8254_init(dev->iobase + DAC8254, + devpriv->ao_pacer = comedi_8254_init(dev->iobase + PCIDAS_AO_8254_BASE, I8254_OSC_BASE_10MHZ, I8254_IO8, 0); if (!devpriv->ao_pacer) @@ -1394,97 +1313,104 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* analog input subdevice */ - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; - /* WARNING: Number of inputs in differential mode is ignored */ - s->n_chan = board->ai_nchan; - s->len_chanlist = board->ai_nchan; - s->maxdata = (1 << board->ai_bits) - 1; - s->range_table = board->ranges; - s->insn_read = cb_pcidas_ai_rinsn; - s->insn_config = ai_config_insn; - s->do_cmd = cb_pcidas_ai_cmd; - s->do_cmdtest = cb_pcidas_ai_cmdtest; - s->cancel = cb_pcidas_cancel; - - /* analog output subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = board->is_16bit ? 0xffff : 0x0fff; + s->range_table = board->use_alt_range ? &cb_pcidas_alt_ranges + : &cb_pcidas_ranges; + s->insn_read = cb_pcidas_ai_insn_read; + s->insn_config = cb_pcidas_ai_insn_config; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmd = cb_pcidas_ai_cmd; + s->do_cmdtest = cb_pcidas_ai_cmdtest; + s->cancel = cb_pcidas_ai_cancel; + } + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (board->ao_nchan) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->ao_nchan; - /* - * analog out resolution is the same as - * analog input resolution, so use ai_bits - */ - s->maxdata = (1 << board->ai_bits) - 1; - s->range_table = &cb_pcidas_ao_ranges; - /* default to no fifo (*insn_write) */ - s->insn_write = cb_pcidas_ao_nofifo_winsn; + if (board->has_ao) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = 2; + s->maxdata = board->is_16bit ? 0xffff : 0x0fff; + s->range_table = &cb_pcidas_ao_ranges; + s->insn_write = (board->has_ao_fifo) + ? cb_pcidas_ao_fifo_insn_write + : cb_pcidas_ao_nofifo_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) return ret; - if (board->has_ao_fifo) { + if (dev->irq && board->has_ao_fifo) { dev->write_subdev = s; - s->subdev_flags |= SDF_CMD_WRITE; - /* use fifo (*insn_write) instead */ - s->insn_write = cb_pcidas_ao_fifo_winsn; - s->do_cmdtest = cb_pcidas_ao_cmdtest; - s->do_cmd = cb_pcidas_ao_cmd; - s->cancel = cb_pcidas_ao_cancel; + s->subdev_flags |= SDF_CMD_WRITE; + s->do_cmdtest = cb_pcidas_ao_cmdtest; + s->do_cmd = cb_pcidas_ao_cmd; + s->cancel = cb_pcidas_ao_cancel; } } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } /* 8255 */ s = &dev->subdevices[2]; - ret = subdev_8255_init(dev, s, NULL, DIO_8255); + ret = subdev_8255_init(dev, s, NULL, PCIDAS_8255_BASE); if (ret) return ret; - /* serial EEPROM, */ + /* Memory subdevice - serial EEPROM */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE | SDF_INTERNAL; - s->n_chan = 256; - s->maxdata = 0xff; - s->insn_read = eeprom_read_insn; + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_INTERNAL; + s->n_chan = 256; + s->maxdata = 0xff; + s->insn_read = cb_pcidas_eeprom_insn_read; - /* 8800 caldac */ + /* Calibration subdevice - 8800 caldac */ s = &dev->subdevices[4]; - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = NUM_CHANNELS_8800; - s->maxdata = 0xff; - s->insn_write = cb_pcidas_caldac_insn_write; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 8; + s->maxdata = 0xff; + 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; + unsigned int val = s->maxdata / 2; + + /* write 11-bit channel/value to caldac */ + cb_pcidas_calib_write(dev, (i << 8) | val, 11, false); + s->readback[i] = val; } - /* trim potentiometer */ + /* Calibration subdevice - trim potentiometer */ s = &dev->subdevices[5]; - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - if (board->trimpot == AD7376) { - s->n_chan = NUM_CHANNELS_7376; - s->maxdata = 0x7f; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; + if (board->has_ad8402) { + /* + * pci-das1602/16 have an AD8402 trimpot: + * chan 0 : adc gain + * chan 1 : adc postgain offset + */ + s->n_chan = 2; + s->maxdata = 0xff; } else { - s->n_chan = NUM_CHANNELS_8402; - s->maxdata = 0xff; + /* all other boards have an AD7376 trimpot */ + s->n_chan = 1; + s->maxdata = 0x7f; } - s->insn_write = cb_pcidas_trimpot_insn_write; + s->insn_write = cb_pcidas_trimpot_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -1495,36 +1421,35 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, s->readback[i] = s->maxdata / 2; } - /* dac08 caldac */ + /* Calibration subdevice - pci-das1602/16 pregain offset (dac08) */ s = &dev->subdevices[6]; if (board->has_dac08) { - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = NUM_CHANNELS_DAC08; - s->maxdata = 0xff; - s->insn_write = cb_pcidas_dac08_insn_write; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 1; + s->maxdata = 0xff; + 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); + cb_pcidas_dac08_write(dev, s->maxdata / 2); s->readback[i] = s->maxdata / 2; } } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } /* make sure mailbox 4 is empty */ - inl(devpriv->s5933_config + AMCC_OP_REG_IMB4); + inl(devpriv->amcc + AMCC_OP_REG_IMB4); /* Set bits to enable incoming mailbox interrupts on amcc s5933. */ - devpriv->s5933_intcsr_bits = - INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | - INTCSR_INBOX_FULL_INT; + devpriv->amcc_intcsr = INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | + INTCSR_INBOX_FULL_INT; /* clear and enable interrupt on amcc s5933 */ - outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); + outl(devpriv->amcc_intcsr | INTCSR_INBOX_INTR_STATUS, + devpriv->amcc + AMCC_OP_REG_INTCSR); return 0; } @@ -1534,9 +1459,9 @@ static void cb_pcidas_detach(struct comedi_device *dev) struct cb_pcidas_private *devpriv = dev->private; if (devpriv) { - if (devpriv->s5933_config) + if (devpriv->amcc) outl(INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); + devpriv->amcc + AMCC_OP_REG_INTCSR); kfree(devpriv->ao_pacer); } comedi_pci_detach(dev); @@ -1578,5 +1503,5 @@ static struct pci_driver cb_pcidas_pci_driver = { module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for MeasurementComputing PCI-DAS series"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index 80d613c0f..4ab186669 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -1,49 +1,49 @@ /* - comedi/drivers/comedi_test.c + * comedi/drivers/comedi_test.c + * + * Generates fake waveform signals that can be read through + * the command interface. It does _not_ read from any board; + * it just generates deterministic waveforms. + * Useful for various testing purposes. + * + * Copyright (C) 2002 Joachim Wuttke + * Copyright (C) 2002 Frank Mori Hess + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * 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. + */ - Generates fake waveform signals that can be read through - the command interface. It does _not_ read from any board; - it just generates deterministic waveforms. - Useful for various testing purposes. - - Copyright (C) 2002 Joachim Wuttke - Copyright (C) 2002 Frank Mori Hess - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ /* -Driver: comedi_test -Description: generates fake waveforms -Author: Joachim Wuttke , Frank Mori Hess - , ds -Devices: -Status: works -Updated: Sat, 16 Mar 2002 17:34:48 -0800 - -This driver is mainly for testing purposes, but can also be used to -generate sample waveforms on systems that don't have data acquisition -hardware. - -Configuration options: - [0] - Amplitude in microvolts for fake waveforms (default 1 volt) - [1] - Period in microseconds for fake waveforms (default 0.1 sec) - -Generates a sawtooth wave on channel 0, square wave on channel 1, additional -waveforms could be added to other channels (currently they return flatline -zero volts). - -*/ + * Driver: comedi_test + * Description: generates fake waveforms + * Author: Joachim Wuttke , Frank Mori Hess + * , ds + * Devices: + * Status: works + * Updated: Sat, 16 Mar 2002 17:34:48 -0800 + * + * This driver is mainly for testing purposes, but can also be used to + * generate sample waveforms on systems that don't have data acquisition + * hardware. + * + * Configuration options: + * [0] - Amplitude in microvolts for fake waveforms (default 1 volt) + * [1] - Period in microseconds for fake waveforms (default 0.1 sec) + * + * Generates a sawtooth wave on channel 0, square wave on channel 1, additional + * waveforms could be added to other channels (currently they return flatline + * zero volts). + */ #include #include "../comedidev.h" @@ -52,30 +52,31 @@ zero volts). #include #include +#include #define N_CHANS 8 enum waveform_state_bits { - WAVEFORM_AI_RUNNING = 0 + WAVEFORM_AI_RUNNING, + WAVEFORM_AO_RUNNING }; /* Data unique to this driver */ struct waveform_private { - struct timer_list timer; - 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 */ + struct timer_list ai_timer; /* timer for AI commands */ + u64 ai_convert_time; /* time of next AI conversion in usec */ + unsigned int wf_amplitude; /* waveform amplitude in microvolts */ + unsigned int wf_period; /* waveform period in microseconds */ + unsigned int wf_current; /* current time in waveform period */ 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]; + unsigned int ai_scan_period; /* AI scan period in usec */ + unsigned int ai_convert_period; /* AI conversion period in usec */ + struct timer_list ao_timer; /* timer for AO commands */ + u64 ao_last_scan_time; /* time of previous AO scan in usec */ + unsigned int ao_scan_period; /* AO scan period in usec */ + unsigned short ao_loopbacks[N_CHANS]; }; -/* 1000 nanosec in a microsec */ -static const int nano_per_micro = 1000; - /* fake analog input ranges */ static const struct comedi_lrange waveform_ai_ranges = { 2, { @@ -86,7 +87,7 @@ static const struct comedi_lrange waveform_ai_ranges = { static unsigned short fake_sawtooth(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) + unsigned int current_time) { struct waveform_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -97,21 +98,28 @@ static unsigned short fake_sawtooth(struct comedi_device *dev, u64 binary_amplitude; binary_amplitude = s->maxdata; - binary_amplitude *= devpriv->uvolt_amplitude; + binary_amplitude *= devpriv->wf_amplitude; do_div(binary_amplitude, krange->max - krange->min); - current_time %= devpriv->usec_period; value = current_time; value *= binary_amplitude * 2; - do_div(value, devpriv->usec_period); - value -= binary_amplitude; /* get rid of sawtooth's dc offset */ + do_div(value, devpriv->wf_period); + value += offset; + /* get rid of sawtooth's dc offset and clamp value */ + if (value < binary_amplitude) { + value = 0; /* negative saturation */ + } else { + value -= binary_amplitude; + if (value > s->maxdata) + value = s->maxdata; /* positive saturation */ + } - return offset + value; + return value; } static unsigned short fake_squarewave(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) + unsigned int current_time) { struct waveform_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -119,21 +127,29 @@ static unsigned short fake_squarewave(struct comedi_device *dev, u64 value; const struct comedi_krange *krange = &s->range_table->range[range_index]; - current_time %= devpriv->usec_period; value = s->maxdata; - value *= devpriv->uvolt_amplitude; + value *= devpriv->wf_amplitude; do_div(value, krange->max - krange->min); - if (current_time < devpriv->usec_period / 2) - value *= -1; + /* get one of two values for square-wave and clamp */ + if (current_time < devpriv->wf_period / 2) { + if (offset < value) + value = 0; /* negative saturation */ + else + value = offset - value; + } else { + value += offset; + if (value > s->maxdata) + value = s->maxdata; /* positive saturation */ + } - return offset + value; + return value; } static unsigned short fake_flatline(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) + unsigned int current_time) { return dev->read_subdev->maxdata / 2; } @@ -141,7 +157,7 @@ static unsigned short fake_flatline(struct comedi_device *dev, /* generates a different waveform depending on what channel is read */ static unsigned short fake_waveform(struct comedi_device *dev, unsigned int channel, unsigned int range, - unsigned long current_time) + unsigned int current_time) { enum { SAWTOOTH_CHAN, @@ -160,58 +176,62 @@ static unsigned short fake_waveform(struct comedi_device *dev, } /* - This is the background routine used to generate arbitrary data. - It should run in the background; therefore it is scheduled by - a timer mechanism. -*/ -static void waveform_ai_interrupt(unsigned long arg) + * This is the background routine used to generate arbitrary data. + * It should run in the background; therefore it is scheduled by + * a timer mechanism. + */ +static void waveform_ai_timer(unsigned long arg) { struct comedi_device *dev = (struct comedi_device *)arg; struct waveform_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, j; - /* all times in microsec */ - unsigned long elapsed_time; - unsigned int num_scans; - ktime_t now; + u64 now; + unsigned int nsamples; + unsigned int time_increment; /* check command is still active */ if (!test_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits)) return; - now = ktime_get(); - - 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; - - 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; - - sample = fake_waveform(dev, CR_CHAN(cmd->chanlist[j]), - CR_RANGE(cmd->chanlist[j]), - devpriv->usec_current + - i * devpriv->scan_period + - j * devpriv->convert_period); - comedi_buf_write_samples(s, &sample, 1); + now = ktime_to_us(ktime_get()); + nsamples = comedi_nsamples_left(s, UINT_MAX); + + while (nsamples && devpriv->ai_convert_time < now) { + unsigned int chanspec = cmd->chanlist[async->cur_chan]; + unsigned short sample; + + sample = fake_waveform(dev, CR_CHAN(chanspec), + CR_RANGE(chanspec), devpriv->wf_current); + if (comedi_buf_write_samples(s, &sample, 1) == 0) + goto overrun; + time_increment = devpriv->ai_convert_period; + if (async->scan_progress == 0) { + /* done last conversion in scan, so add dead time */ + time_increment += devpriv->ai_scan_period - + devpriv->ai_convert_period * + cmd->scan_end_arg; } + devpriv->wf_current += time_increment; + if (devpriv->wf_current >= devpriv->wf_period) + devpriv->wf_current %= devpriv->wf_period; + devpriv->ai_convert_time += time_increment; + nsamples--; } - devpriv->usec_current += elapsed_time; - devpriv->usec_current %= devpriv->usec_period; - - if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) { async->events |= COMEDI_CB_EOA; - else - mod_timer(&devpriv->timer, jiffies + 1); + } else { + if (devpriv->ai_convert_time > now) + time_increment = devpriv->ai_convert_time - now; + else + time_increment = 1; + mod_timer(&devpriv->ai_timer, + jiffies + usecs_to_jiffies(time_increment)); + } +overrun: comedi_handle_events(dev, s); } @@ -220,12 +240,13 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - unsigned int arg; + unsigned int arg, limit; /* Step 1 : check if triggers are trivially valid */ err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= comedi_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_TIMER); err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW | TRIG_TIMER); err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); @@ -241,6 +262,9 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, /* Step 2b : and mutually compatible */ + if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) + err |= -EINVAL; /* scan period would be 0 */ + if (err) return 2; @@ -248,18 +272,20 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->convert_src == TRIG_NOW) + if (cmd->convert_src == TRIG_NOW) { err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); + } else { /* cmd->convert_src == TRIG_TIMER */ + if (cmd->scan_begin_src == TRIG_FOLLOW) { + err |= comedi_check_trigger_arg_min(&cmd->convert_arg, + NSEC_PER_USEC); + } + } - if (cmd->scan_begin_src == TRIG_TIMER) { + if (cmd->scan_begin_src == TRIG_FOLLOW) { + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + } else { /* cmd->scan_begin_src == TRIG_TIMER */ err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, - nano_per_micro); - if (cmd->convert_src == TRIG_TIMER) { - err |= comedi_check_trigger_arg_min(&cmd-> - scan_begin_arg, - cmd->convert_arg * - cmd->chanlist_len); - } + NSEC_PER_USEC); } err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); @@ -268,7 +294,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, if (cmd->stop_src == TRIG_COUNT) err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); - else /* TRIG_NONE */ + else /* cmd->stop_src == TRIG_NONE */ err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -276,21 +302,34 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->scan_begin_src == TRIG_TIMER) { - arg = cmd->scan_begin_arg; - /* round to nearest microsec */ - arg = nano_per_micro * - ((arg + (nano_per_micro / 2)) / nano_per_micro); - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); - } if (cmd->convert_src == TRIG_TIMER) { + /* round convert_arg to nearest microsecond */ arg = cmd->convert_arg; - /* round to nearest microsec */ - arg = nano_per_micro * - ((arg + (nano_per_micro / 2)) / nano_per_micro); + arg = min(arg, + rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC)); + arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC); + if (cmd->scan_begin_arg == TRIG_TIMER) { + /* limit convert_arg to keep scan_begin_arg in range */ + limit = UINT_MAX / cmd->scan_end_arg; + limit = rounddown(limit, (unsigned int)NSEC_PER_SEC); + arg = min(arg, limit); + } err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); } + if (cmd->scan_begin_src == TRIG_TIMER) { + /* round scan_begin_arg to nearest microsecond */ + arg = cmd->scan_begin_arg; + arg = min(arg, + rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC)); + arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC); + if (cmd->convert_src == TRIG_TIMER) { + /* but ensure scan_begin_arg is large enough */ + arg = max(arg, cmd->convert_arg * cmd->scan_end_arg); + } + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); + } + if (err) return 4; @@ -302,6 +341,8 @@ static int waveform_ai_cmd(struct comedi_device *dev, { struct waveform_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int first_convert_time; + u64 wf_current; if (cmd->flags & CMDF_PRIORITY) { dev_err(dev->class_dev, @@ -309,24 +350,48 @@ static int waveform_ai_cmd(struct comedi_device *dev, return -1; } - devpriv->scan_period = cmd->scan_begin_arg / nano_per_micro; - if (cmd->convert_src == TRIG_NOW) - devpriv->convert_period = 0; - else /* TRIG_TIMER */ - devpriv->convert_period = cmd->convert_arg / nano_per_micro; + devpriv->ai_convert_period = 0; + else /* cmd->convert_src == TRIG_TIMER */ + devpriv->ai_convert_period = cmd->convert_arg / NSEC_PER_USEC; + + if (cmd->scan_begin_src == TRIG_FOLLOW) { + devpriv->ai_scan_period = devpriv->ai_convert_period * + cmd->scan_end_arg; + } else { /* cmd->scan_begin_src == TRIG_TIMER */ + devpriv->ai_scan_period = cmd->scan_begin_arg / NSEC_PER_USEC; + } - devpriv->last = ktime_get(); - devpriv->usec_current = - ((u32)ktime_to_us(devpriv->last)) % devpriv->usec_period; - devpriv->usec_remainder = 0; + /* + * Simulate first conversion to occur at convert period after + * conversion timer starts. If scan_begin_src is TRIG_FOLLOW, assume + * the conversion timer starts immediately. If scan_begin_src is + * TRIG_TIMER, assume the conversion timer starts after the scan + * period. + */ + first_convert_time = devpriv->ai_convert_period; + if (cmd->scan_begin_src == TRIG_TIMER) + first_convert_time += devpriv->ai_scan_period; + devpriv->ai_convert_time = ktime_to_us(ktime_get()) + + first_convert_time; + + /* Determine time within waveform period at time of conversion. */ + wf_current = devpriv->ai_convert_time; + devpriv->wf_current = do_div(wf_current, devpriv->wf_period); + + /* + * Schedule timer to expire just after first conversion time. + * Seem to need an extra jiffy here, otherwise timer expires slightly + * early! + */ + devpriv->ai_timer.expires = + jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1; - 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); + add_timer(&devpriv->ai_timer); return 0; } @@ -339,7 +404,7 @@ static int waveform_ai_cancel(struct comedi_device *dev, 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); + del_timer(&devpriv->ai_timer); return 0; } @@ -356,6 +421,201 @@ static int waveform_ai_insn_read(struct comedi_device *dev, return insn->n; } +/* + * This is the background routine to handle AO commands, scheduled by + * a timer mechanism. + */ +static void waveform_ao_timer(unsigned long arg) +{ + struct comedi_device *dev = (struct comedi_device *)arg; + struct waveform_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->write_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + u64 now; + u64 scans_since; + unsigned int scans_avail = 0; + + /* check command is still active */ + if (!test_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits)) + return; + + /* determine number of scan periods since last time */ + now = ktime_to_us(ktime_get()); + scans_since = now - devpriv->ao_last_scan_time; + do_div(scans_since, devpriv->ao_scan_period); + if (scans_since) { + unsigned int i; + + /* determine scans in buffer, limit to scans to do this time */ + scans_avail = comedi_nscans_left(s, 0); + if (scans_avail > scans_since) + scans_avail = scans_since; + if (scans_avail) { + /* skip all but the last scan to save processing time */ + if (scans_avail > 1) { + unsigned int skip_bytes, nbytes; + + skip_bytes = + comedi_samples_to_bytes(s, cmd->scan_end_arg * + (scans_avail - 1)); + nbytes = comedi_buf_read_alloc(s, skip_bytes); + comedi_buf_read_free(s, nbytes); + comedi_inc_scan_progress(s, nbytes); + if (nbytes < skip_bytes) { + /* unexpected underrun! (cancelled?) */ + async->events |= COMEDI_CB_OVERFLOW; + goto underrun; + } + } + /* output the last scan */ + for (i = 0; i < cmd->scan_end_arg; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (comedi_buf_read_samples(s, + &devpriv-> + ao_loopbacks[chan], + 1) == 0) { + /* unexpected underrun! (cancelled?) */ + async->events |= COMEDI_CB_OVERFLOW; + goto underrun; + } + } + /* advance time of last scan */ + devpriv->ao_last_scan_time += + (u64)scans_avail * devpriv->ao_scan_period; + } + } + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) { + async->events |= COMEDI_CB_EOA; + } else if (scans_avail < scans_since) { + async->events |= COMEDI_CB_OVERFLOW; + } else { + unsigned int time_inc = devpriv->ao_last_scan_time + + devpriv->ao_scan_period - now; + + mod_timer(&devpriv->ao_timer, + jiffies + usecs_to_jiffies(time_inc)); + } + +underrun: + comedi_handle_events(dev, s); +} + +static int waveform_ao_inttrig_start(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) +{ + struct waveform_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + + if (trig_num != cmd->start_arg) + return -EINVAL; + + async->inttrig = NULL; + + devpriv->ao_last_scan_time = ktime_to_us(ktime_get()); + devpriv->ao_timer.expires = + jiffies + usecs_to_jiffies(devpriv->ao_scan_period); + + /* mark command as active */ + smp_mb__before_atomic(); + set_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits); + smp_mb__after_atomic(); + add_timer(&devpriv->ao_timer); + + return 1; +} + +static int waveform_ao_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + unsigned int arg; + + /* Step 1 : check if triggers are trivially valid */ + + err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= comedi_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 |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, + NSEC_PER_USEC); + err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, + cmd->chanlist_len); + if (cmd->stop_src == TRIG_COUNT) + err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* cmd->stop_src == TRIG_NONE */ + err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* round scan_begin_arg to nearest microsecond */ + arg = cmd->scan_begin_arg; + arg = min(arg, rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC)); + arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC); + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); + + if (err) + return 4; + + return 0; +} + +static int waveform_ao_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct waveform_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + if (cmd->flags & CMDF_PRIORITY) { + dev_err(dev->class_dev, + "commands at RT priority not supported in this driver\n"); + return -1; + } + + devpriv->ao_scan_period = cmd->scan_begin_arg / NSEC_PER_USEC; + s->async->inttrig = waveform_ao_inttrig_start; + return 0; +} + +static int waveform_ao_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct waveform_private *devpriv = dev->private; + + s->async->inttrig = NULL; + /* mark command as no longer active */ + clear_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits); + smp_mb__after_atomic(); + /* cannot call del_timer_sync() as may be called from timer routine */ + del_timer(&devpriv->ao_timer); + return 0; +} + static int waveform_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -389,8 +649,8 @@ static int waveform_attach(struct comedi_device *dev, if (period <= 0) period = 100000; /* 0.1 sec */ - devpriv->uvolt_amplitude = amplitude; - devpriv->usec_period = period; + devpriv->wf_amplitude = amplitude; + devpriv->wf_period = period; ret = comedi_alloc_subdevices(dev, 2); if (ret) @@ -414,23 +674,28 @@ 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_WRITABLE | SDF_GROUND; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; s->n_chan = N_CHANS; s->maxdata = 0xffff; s->range_table = &waveform_ai_ranges; + s->len_chanlist = s->n_chan; s->insn_write = waveform_ao_insn_write; + s->insn_read = waveform_ai_insn_read; /* do same as AI insn_read */ + s->do_cmd = waveform_ao_cmd; + s->do_cmdtest = waveform_ao_cmdtest; + s->cancel = waveform_ao_cancel; /* Our default loopback value is just a 0V flatline */ for (i = 0; i < s->n_chan; i++) devpriv->ao_loopbacks[i] = s->maxdata / 2; - setup_timer(&devpriv->timer, waveform_ai_interrupt, - (unsigned long)dev); + setup_timer(&devpriv->ai_timer, waveform_ai_timer, (unsigned long)dev); + setup_timer(&devpriv->ao_timer, waveform_ao_timer, (unsigned long)dev); dev_info(dev->class_dev, - "%s: %i microvolt, %li microsecond waveform attached\n", + "%s: %u microvolt, %u microsecond waveform attached\n", dev->board_name, - devpriv->uvolt_amplitude, devpriv->usec_period); + devpriv->wf_amplitude, devpriv->wf_period); return 0; } @@ -439,8 +704,10 @@ static void waveform_detach(struct comedi_device *dev) { struct waveform_private *devpriv = dev->private; - if (devpriv) - del_timer_sync(&devpriv->timer); + if (devpriv) { + del_timer_sync(&devpriv->ai_timer); + del_timer_sync(&devpriv->ao_timer); + } } static struct comedi_driver waveform_driver = { diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 3536f9254..87d86130d 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -713,12 +713,8 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, return result; s = &dev->subdevices[2]; - result = subdev_8255_init(dev, s, daqboard2000_8255_cb, - dioP2ExpansionIO8Bit); - if (result) - return result; - - return 0; + return subdev_8255_init(dev, s, daqboard2000_8255_cb, + dioP2ExpansionIO8Bit); } static void daqboard2000_detach(struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 8c4f284d1..ab7a332fb 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -1,52 +1,53 @@ /* - comedi/drivers/dt3000.c - Data Translation DT3000 series driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 David A. Schleef - - 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: dt3000 -Description: Data Translation DT3000 series -Author: ds -Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003, - DT3003-PGL, DT3004, DT3005, DT3004-200 -Updated: Mon, 14 Apr 2008 15:41:24 +0100 -Status: works - -Configuration Options: not applicable, uses PCI auto config - -There is code to support AI commands, but it may not work. + * dt3000.c + * Data Translation DT3000 series driver + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 David A. Schleef + * + * 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. + */ -AO commands are not supported. -*/ +/* + * Driver: dt3000 + * Description: Data Translation DT3000 series + * Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003, + * DT3003-PGL, DT3004, DT3005, DT3004-200 + * Author: ds + * Updated: Mon, 14 Apr 2008 15:41:24 +0100 + * Status: works + * + * Configuration Options: not applicable, uses PCI auto config + * + * There is code to support AI commands, but it may not work. + * + * AO commands are not supported. + */ /* - The DT3000 series is Data Translation's attempt to make a PCI - data acquisition board. The design of this series is very nice, - since each board has an on-board DSP (Texas Instruments TMS320C52). - However, a few details are a little annoying. The boards lack - bus-mastering DMA, which eliminates them from serious work. - They also are not capable of autocalibration, which is a common - feature in modern hardware. The default firmware is pretty bad, - making it nearly impossible to write an RT compatible driver. - It would make an interesting project to write a decent firmware - for these boards. - - Data Translation originally wanted an NDA for the documentation - for the 3k series. However, if you ask nicely, they might send - you the docs without one, also. -*/ + * The DT3000 series is Data Translation's attempt to make a PCI + * data acquisition board. The design of this series is very nice, + * since each board has an on-board DSP (Texas Instruments TMS320C52). + * However, a few details are a little annoying. The boards lack + * bus-mastering DMA, which eliminates them from serious work. + * They also are not capable of autocalibration, which is a common + * feature in modern hardware. The default firmware is pretty bad, + * making it nearly impossible to write an RT compatible driver. + * It would make an interesting project to write a decent firmware + * for these boards. + * + * Data Translation originally wanted an NDA for the documentation + * for the 3k series. However, if you ask nicely, they might send + * you the docs without one, also. + */ #include #include @@ -54,6 +55,88 @@ AO commands are not supported. #include "../comedi_pci.h" +/* + * PCI BAR0 - dual-ported RAM location definitions (dev->mmio) + */ +#define DPR_DAC_BUFFER (4 * 0x000) +#define DPR_ADC_BUFFER (4 * 0x800) +#define DPR_COMMAND (4 * 0xfd3) +#define DPR_SUBSYS (4 * 0xfd3) +#define DPR_SUBSYS_AI 0 +#define DPR_SUBSYS_AO 1 +#define DPR_SUBSYS_DIN 2 +#define DPR_SUBSYS_DOUT 3 +#define DPR_SUBSYS_MEM 4 +#define DPR_SUBSYS_CT 5 +#define DPR_ENCODE (4 * 0xfd4) +#define DPR_PARAMS(x) (4 * (0xfd5 + (x))) +#define DPR_TICK_REG_LO (4 * 0xff5) +#define DPR_TICK_REG_HI (4 * 0xff6) +#define DPR_DA_BUF_FRONT (4 * 0xff7) +#define DPR_DA_BUF_REAR (4 * 0xff8) +#define DPR_AD_BUF_FRONT (4 * 0xff9) +#define DPR_AD_BUF_REAR (4 * 0xffa) +#define DPR_INT_MASK (4 * 0xffb) +#define DPR_INTR_FLAG (4 * 0xffc) +#define DPR_INTR_CMDONE BIT(7) +#define DPR_INTR_CTDONE BIT(6) +#define DPR_INTR_DAHWERR BIT(5) +#define DPR_INTR_DASWERR BIT(4) +#define DPR_INTR_DAEMPTY BIT(3) +#define DPR_INTR_ADHWERR BIT(2) +#define DPR_INTR_ADSWERR BIT(1) +#define DPR_INTR_ADFULL BIT(0) +#define DPR_RESPONSE_MBX (4 * 0xffe) +#define DPR_CMD_MBX (4 * 0xfff) +#define DPR_CMD_COMPLETION(x) ((x) << 8) +#define DPR_CMD_NOTPROCESSED DPR_CMD_COMPLETION(0x00) +#define DPR_CMD_NOERROR DPR_CMD_COMPLETION(0x55) +#define DPR_CMD_ERROR DPR_CMD_COMPLETION(0xaa) +#define DPR_CMD_NOTSUPPORTED DPR_CMD_COMPLETION(0xff) +#define DPR_CMD_COMPLETION_MASK DPR_CMD_COMPLETION(0xff) +#define DPR_CMD(x) ((x) << 0) +#define DPR_CMD_GETBRDINFO DPR_CMD(0) +#define DPR_CMD_CONFIG DPR_CMD(1) +#define DPR_CMD_GETCONFIG DPR_CMD(2) +#define DPR_CMD_START DPR_CMD(3) +#define DPR_CMD_STOP DPR_CMD(4) +#define DPR_CMD_READSINGLE DPR_CMD(5) +#define DPR_CMD_WRITESINGLE DPR_CMD(6) +#define DPR_CMD_CALCCLOCK DPR_CMD(7) +#define DPR_CMD_READEVENTS DPR_CMD(8) +#define DPR_CMD_WRITECTCTRL DPR_CMD(16) +#define DPR_CMD_READCTCTRL DPR_CMD(17) +#define DPR_CMD_WRITECT DPR_CMD(18) +#define DPR_CMD_READCT DPR_CMD(19) +#define DPR_CMD_WRITEDATA DPR_CMD(32) +#define DPR_CMD_READDATA DPR_CMD(33) +#define DPR_CMD_WRITEIO DPR_CMD(34) +#define DPR_CMD_READIO DPR_CMD(35) +#define DPR_CMD_WRITECODE DPR_CMD(36) +#define DPR_CMD_READCODE DPR_CMD(37) +#define DPR_CMD_EXECUTE DPR_CMD(38) +#define DPR_CMD_HALT DPR_CMD(48) +#define DPR_CMD_MASK DPR_CMD(0xff) + +#define DPR_PARAM5_AD_TRIG(x) (((x) & 0x7) << 2) +#define DPR_PARAM5_AD_TRIG_INT DPR_PARAM5_AD_TRIG(0) +#define DPR_PARAM5_AD_TRIG_EXT DPR_PARAM5_AD_TRIG(1) +#define DPR_PARAM5_AD_TRIG_INT_RETRIG DPR_PARAM5_AD_TRIG(2) +#define DPR_PARAM5_AD_TRIG_EXT_RETRIG DPR_PARAM5_AD_TRIG(3) +#define DPR_PARAM5_AD_TRIG_INT_RETRIG2 DPR_PARAM5_AD_TRIG(4) + +#define DPR_PARAM6_AD_DIFF BIT(0) + +#define DPR_AI_FIFO_DEPTH 2003 +#define DPR_AO_FIFO_DEPTH 2048 + +#define DPR_EXTERNAL_CLOCK 1 +#define DPR_RISING_EDGE 2 + +#define DPR_TMODE_MASK 0x1c + +#define DPR_CMD_TIMEOUT 100 + static const struct comedi_lrange range_dt3000_ai = { 4, { BIP_RANGE(10), @@ -85,184 +168,87 @@ enum dt3k_boardid { struct dt3k_boardtype { const char *name; int adchan; - int adbits; int ai_speed; const struct comedi_lrange *adrange; - int dachan; - int dabits; + unsigned int ai_is_16bit:1; + unsigned int has_ao:1; }; static const struct dt3k_boardtype dt3k_boardtypes[] = { [BOARD_DT3001] = { .name = "dt3001", .adchan = 16, - .adbits = 12, .adrange = &range_dt3000_ai, .ai_speed = 3000, - .dachan = 2, - .dabits = 12, + .has_ao = 1, }, [BOARD_DT3001_PGL] = { .name = "dt3001-pgl", .adchan = 16, - .adbits = 12, .adrange = &range_dt3000_ai_pgl, .ai_speed = 3000, - .dachan = 2, - .dabits = 12, + .has_ao = 1, }, [BOARD_DT3002] = { .name = "dt3002", .adchan = 32, - .adbits = 12, .adrange = &range_dt3000_ai, .ai_speed = 3000, }, [BOARD_DT3003] = { .name = "dt3003", .adchan = 64, - .adbits = 12, .adrange = &range_dt3000_ai, .ai_speed = 3000, - .dachan = 2, - .dabits = 12, + .has_ao = 1, }, [BOARD_DT3003_PGL] = { .name = "dt3003-pgl", .adchan = 64, - .adbits = 12, .adrange = &range_dt3000_ai_pgl, .ai_speed = 3000, - .dachan = 2, - .dabits = 12, + .has_ao = 1, }, [BOARD_DT3004] = { .name = "dt3004", .adchan = 16, - .adbits = 16, .adrange = &range_dt3000_ai, .ai_speed = 10000, - .dachan = 2, - .dabits = 12, + .ai_is_16bit = 1, + .has_ao = 1, }, [BOARD_DT3005] = { .name = "dt3005", /* a.k.a. 3004-200 */ .adchan = 16, - .adbits = 16, .adrange = &range_dt3000_ai, .ai_speed = 5000, - .dachan = 2, - .dabits = 12, + .ai_is_16bit = 1, + .has_ao = 1, }, }; -/* dual-ported RAM location definitions */ - -#define DPR_DAC_buffer (4*0x000) -#define DPR_ADC_buffer (4*0x800) -#define DPR_Command (4*0xfd3) -#define DPR_SubSys (4*0xfd3) -#define DPR_Encode (4*0xfd4) -#define DPR_Params(a) (4*(0xfd5+(a))) -#define DPR_Tick_Reg_Lo (4*0xff5) -#define DPR_Tick_Reg_Hi (4*0xff6) -#define DPR_DA_Buf_Front (4*0xff7) -#define DPR_DA_Buf_Rear (4*0xff8) -#define DPR_AD_Buf_Front (4*0xff9) -#define DPR_AD_Buf_Rear (4*0xffa) -#define DPR_Int_Mask (4*0xffb) -#define DPR_Intr_Flag (4*0xffc) -#define DPR_Response_Mbx (4*0xffe) -#define DPR_Command_Mbx (4*0xfff) - -#define AI_FIFO_DEPTH 2003 -#define AO_FIFO_DEPTH 2048 - -/* command list */ - -#define CMD_GETBRDINFO 0 -#define CMD_CONFIG 1 -#define CMD_GETCONFIG 2 -#define CMD_START 3 -#define CMD_STOP 4 -#define CMD_READSINGLE 5 -#define CMD_WRITESINGLE 6 -#define CMD_CALCCLOCK 7 -#define CMD_READEVENTS 8 -#define CMD_WRITECTCTRL 16 -#define CMD_READCTCTRL 17 -#define CMD_WRITECT 18 -#define CMD_READCT 19 -#define CMD_WRITEDATA 32 -#define CMD_READDATA 33 -#define CMD_WRITEIO 34 -#define CMD_READIO 35 -#define CMD_WRITECODE 36 -#define CMD_READCODE 37 -#define CMD_EXECUTE 38 -#define CMD_HALT 48 - -#define SUBS_AI 0 -#define SUBS_AO 1 -#define SUBS_DIN 2 -#define SUBS_DOUT 3 -#define SUBS_MEM 4 -#define SUBS_CT 5 - -/* interrupt flags */ -#define DT3000_CMDONE 0x80 -#define DT3000_CTDONE 0x40 -#define DT3000_DAHWERR 0x20 -#define DT3000_DASWERR 0x10 -#define DT3000_DAEMPTY 0x08 -#define DT3000_ADHWERR 0x04 -#define DT3000_ADSWERR 0x02 -#define DT3000_ADFULL 0x01 - -#define DT3000_COMPLETION_MASK 0xff00 -#define DT3000_COMMAND_MASK 0x00ff -#define DT3000_NOTPROCESSED 0x0000 -#define DT3000_NOERROR 0x5500 -#define DT3000_ERROR 0xaa00 -#define DT3000_NOTSUPPORTED 0xff00 - -#define DT3000_EXTERNAL_CLOCK 1 -#define DT3000_RISING_EDGE 2 - -#define TMODE_MASK 0x1c - -#define DT3000_AD_TRIG_INTERNAL (0<<2) -#define DT3000_AD_TRIG_EXTERNAL (1<<2) -#define DT3000_AD_RETRIG_INTERNAL (2<<2) -#define DT3000_AD_RETRIG_EXTERNAL (3<<2) -#define DT3000_AD_EXTRETRIG (4<<2) - -#define DT3000_CHANNEL_MODE_SE 0 -#define DT3000_CHANNEL_MODE_DI 1 - struct dt3k_private { unsigned int lock; unsigned int ai_front; unsigned int ai_rear; }; -#define TIMEOUT 100 - static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) { int i; unsigned int status = 0; - writew(cmd, dev->mmio + DPR_Command_Mbx); + writew(cmd, dev->mmio + DPR_CMD_MBX); - for (i = 0; i < TIMEOUT; i++) { - status = readw(dev->mmio + DPR_Command_Mbx); - if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED) + for (i = 0; i < DPR_CMD_TIMEOUT; i++) { + status = readw(dev->mmio + DPR_CMD_MBX); + status &= DPR_CMD_COMPLETION_MASK; + if (status != DPR_CMD_NOTPROCESSED) break; udelay(1); } - if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR) + if (status != DPR_CMD_NOERROR) dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n", __func__, status); } @@ -271,26 +257,26 @@ static unsigned int dt3k_readsingle(struct comedi_device *dev, unsigned int subsys, unsigned int chan, unsigned int gain) { - writew(subsys, dev->mmio + DPR_SubSys); + writew(subsys, dev->mmio + DPR_SUBSYS); - writew(chan, dev->mmio + DPR_Params(0)); - writew(gain, dev->mmio + DPR_Params(1)); + writew(chan, dev->mmio + DPR_PARAMS(0)); + writew(gain, dev->mmio + DPR_PARAMS(1)); - dt3k_send_cmd(dev, CMD_READSINGLE); + dt3k_send_cmd(dev, DPR_CMD_READSINGLE); - return readw(dev->mmio + DPR_Params(2)); + return readw(dev->mmio + DPR_PARAMS(2)); } static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, unsigned int chan, unsigned int data) { - writew(subsys, dev->mmio + DPR_SubSys); + writew(subsys, dev->mmio + DPR_SUBSYS); - writew(chan, dev->mmio + DPR_Params(0)); - writew(0, dev->mmio + DPR_Params(1)); - writew(data, dev->mmio + DPR_Params(2)); + writew(chan, dev->mmio + DPR_PARAMS(0)); + writew(0, dev->mmio + DPR_PARAMS(1)); + writew(data, dev->mmio + DPR_PARAMS(2)); - dt3k_send_cmd(dev, CMD_WRITESINGLE); + dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE); } static void dt3k_ai_empty_fifo(struct comedi_device *dev, @@ -303,32 +289,32 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, int i; unsigned short data; - front = readw(dev->mmio + DPR_AD_Buf_Front); + front = readw(dev->mmio + DPR_AD_BUF_FRONT); count = front - devpriv->ai_front; if (count < 0) - count += AI_FIFO_DEPTH; + count += DPR_AI_FIFO_DEPTH; rear = devpriv->ai_rear; for (i = 0; i < count; i++) { - data = readw(dev->mmio + DPR_ADC_buffer + rear); + data = readw(dev->mmio + DPR_ADC_BUFFER + rear); comedi_buf_write_samples(s, &data, 1); rear++; - if (rear >= AI_FIFO_DEPTH) + if (rear >= DPR_AI_FIFO_DEPTH) rear = 0; } devpriv->ai_rear = rear; - writew(rear, dev->mmio + DPR_AD_Buf_Rear); + writew(rear, dev->mmio + DPR_AD_BUF_REAR); } static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - writew(SUBS_AI, dev->mmio + DPR_SubSys); - dt3k_send_cmd(dev, CMD_STOP); + writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); + dt3k_send_cmd(dev, DPR_CMD_STOP); - writew(0, dev->mmio + DPR_Int_Mask); + writew(0, dev->mmio + DPR_INT_MASK); return 0; } @@ -346,12 +332,12 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) if (!dev->attached) return IRQ_NONE; - status = readw(dev->mmio + DPR_Intr_Flag); + status = readw(dev->mmio + DPR_INTR_FLAG); - if (status & DT3000_ADFULL) + if (status & DPR_INTR_ADFULL) dt3k_ai_empty_fifo(dev, s); - if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) + if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR)) s->async->events |= COMEDI_CB_ERROR; debug_n_ints++; @@ -486,46 +472,49 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) chan = CR_CHAN(cmd->chanlist[i]); range = CR_RANGE(cmd->chanlist[i]); - writew((range << 6) | chan, dev->mmio + DPR_ADC_buffer + i); + writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i); } aref = CR_AREF(cmd->chanlist[0]); - writew(cmd->scan_end_arg, dev->mmio + DPR_Params(0)); + writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0)); if (cmd->convert_src == TRIG_TIMER) { divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags); - writew((divider >> 16), dev->mmio + DPR_Params(1)); - writew((divider & 0xffff), dev->mmio + DPR_Params(2)); + writew((divider >> 16), dev->mmio + DPR_PARAMS(1)); + writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2)); } if (cmd->scan_begin_src == TRIG_TIMER) { tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg, cmd->flags); - writew((tscandiv >> 16), dev->mmio + DPR_Params(3)); - writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4)); + writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3)); + writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4)); } - writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5)); - writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6)); + writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5)); + writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0, + dev->mmio + DPR_PARAMS(6)); - writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7)); + writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7)); - writew(SUBS_AI, dev->mmio + DPR_SubSys); - dt3k_send_cmd(dev, CMD_CONFIG); + writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); + dt3k_send_cmd(dev, DPR_CMD_CONFIG); - writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR, - dev->mmio + DPR_Int_Mask); + writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR, + dev->mmio + DPR_INT_MASK); debug_n_ints = 0; - writew(SUBS_AI, dev->mmio + DPR_SubSys); - dt3k_send_cmd(dev, CMD_START); + writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); + dt3k_send_cmd(dev, DPR_CMD_START); return 0; } -static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dt3k_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { int i; unsigned int chan, gain, aref; @@ -536,7 +525,7 @@ static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, aref = CR_AREF(insn->chanspec); for (i = 0; i < insn->n; i++) - data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain); + data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain); return i; } @@ -552,7 +541,7 @@ static int dt3k_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - dt3k_writesingle(dev, SUBS_AO, chan, val); + dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val); } s->readback[chan] = val; @@ -562,16 +551,13 @@ static int dt3k_ao_insn_write(struct comedi_device *dev, static void dt3k_dio_config(struct comedi_device *dev, int bits) { /* XXX */ - writew(SUBS_DOUT, dev->mmio + DPR_SubSys); + writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS); - writew(bits, dev->mmio + DPR_Params(0)); -#if 0 - /* don't know */ - writew(0, dev->mmio + DPR_Params(1)); - writew(0, dev->mmio + DPR_Params(2)); -#endif + writew(bits, dev->mmio + DPR_PARAMS(0)); - dt3k_send_cmd(dev, CMD_CONFIG); + /* XXX write 0 to DPR_PARAMS(1) and DPR_PARAMS(2) ? */ + + dt3k_send_cmd(dev, DPR_CMD_CONFIG); } static int dt3k_dio_insn_config(struct comedi_device *dev, @@ -603,9 +589,9 @@ static int dt3k_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - dt3k_writesingle(dev, SUBS_DOUT, 0, s->state); + dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state); - data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0); + data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0); return insn->n; } @@ -619,13 +605,13 @@ static int dt3k_mem_insn_read(struct comedi_device *dev, int i; for (i = 0; i < insn->n; i++) { - writew(SUBS_MEM, dev->mmio + DPR_SubSys); - writew(addr, dev->mmio + DPR_Params(0)); - writew(1, dev->mmio + DPR_Params(1)); + writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS); + writew(addr, dev->mmio + DPR_PARAMS(0)); + writew(1, dev->mmio + DPR_PARAMS(1)); - dt3k_send_cmd(dev, CMD_READCODE); + dt3k_send_cmd(dev, DPR_CMD_READCODE); - data[i] = readw(dev->mmio + DPR_Params(2)); + data[i] = readw(dev->mmio + DPR_PARAMS(2)); } return i; @@ -670,14 +656,14 @@ static int dt3000_auto_attach(struct comedi_device *dev, if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; s->n_chan = board->adchan; - s->insn_read = dt3k_ai_insn; - s->maxdata = (1 << board->adbits) - 1; + s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff; s->range_table = &range_dt3000_ai; /* XXX */ + s->insn_read = dt3k_ai_insn_read; if (dev->irq) { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; @@ -687,46 +673,42 @@ static int dt3000_auto_attach(struct comedi_device *dev, s->cancel = dt3k_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* ao subsystem */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->maxdata = (1 << board->dabits) - 1; - s->len_chanlist = 1; - s->range_table = &range_bipolar10; - s->insn_write = dt3k_ao_insn_write; - - ret = comedi_alloc_subdev_readback(s); - if (ret) - return ret; + if (board->has_ao) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_bipolar10; + s->insn_write = dt3k_ao_insn_write; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + } else { + s->type = COMEDI_SUBD_UNUSED; + } + /* Digital I/O subdevice */ s = &dev->subdevices[2]; - /* dio subsystem */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 8; - s->insn_config = dt3k_dio_insn_config; - s->insn_bits = dt3k_dio_insn_bits; s->maxdata = 1; - s->len_chanlist = 8; s->range_table = &range_digital; + s->insn_config = dt3k_dio_insn_config; + s->insn_bits = dt3k_dio_insn_bits; + /* Memory subdevice */ s = &dev->subdevices[3]; - /* mem subsystem */ s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE; s->n_chan = 0x1000; - s->insn_read = dt3k_mem_insn_read; s->maxdata = 0xff; - s->len_chanlist = 1; s->range_table = &range_unknown; - -#if 0 - s = &dev->subdevices[4]; - /* proc subsystem */ - s->type = COMEDI_SUBD_PROC; -#endif + s->insn_read = dt3k_mem_insn_read; return 0; } @@ -765,5 +747,5 @@ static struct pci_driver dt3000_pci_driver = { module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Data Translation DT3000 series boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index e11c216a4..3295bb4ac 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -18,17 +18,17 @@ */ /* -Driver: dt9812 -Description: Data Translation DT9812 USB module -Author: anders.blomdell@control.lth.se (Anders Blomdell) -Status: in development -Devices: [Data Translation] DT9812 (dt9812) -Updated: Sun Nov 20 20:18:34 EST 2005 - -This driver works, but bulk transfers not implemented. Might be a starting point -for someone else. I found out too late that USB has too high latencies (>1 ms) -for my needs. -*/ + * Driver: dt9812 + * Description: Data Translation DT9812 USB module + * Devices: [Data Translation] DT9812 (dt9812) + * Author: anders.blomdell@control.lth.se (Anders Blomdell) + * Status: in development + * Updated: Sun Nov 20 20:18:34 EST 2005 + * + * This driver works, but bulk transfers not implemented. Might be a + * starting point for someone else. I found out too late that USB has + * too high latencies (>1 ms) for my needs. + */ /* * Nota Bene: @@ -80,7 +80,7 @@ for my needs. #define F020_MASK_ADC0CN_AD0INT 0x20 #define F020_MASK_ADC0CN_AD0BUSY 0x10 -#define F020_MASK_DACxCN_DACxEN 0x80 +#define F020_MASK_DACXCN_DACXEN 0x80 enum { /* A/D D/A DI DO CT */ @@ -233,7 +233,7 @@ struct dt9812_usb_cmd { }; struct dt9812_private { - struct semaphore sem; + struct mutex mut; struct { __u8 addr; size_t size; @@ -335,7 +335,7 @@ static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) u8 value[2]; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); ret = dt9812_read_multiple_registers(dev, 2, reg, value); if (ret == 0) { /* @@ -345,7 +345,7 @@ static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) */ *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -357,9 +357,9 @@ static int dt9812_digital_out(struct comedi_device *dev, u8 bits) u8 value[1] = { bits }; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); ret = dt9812_write_multiple_registers(dev, 1, reg, value); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -444,7 +444,7 @@ static int dt9812_analog_in(struct comedi_device *dev, u8 val[3]; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* 1 select the gain */ dt9812_configure_gain(dev, &rmw[0], gain); @@ -493,7 +493,7 @@ static int dt9812_analog_in(struct comedi_device *dev, } exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -504,22 +504,21 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) struct dt9812_rmw_byte rmw[3]; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); switch (channel) { case 0: /* 1. Set DAC mode */ rmw[0].address = F020_SFR_DAC0CN; rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + rmw[0].or_value = F020_MASK_DACXCN_DACXEN; - /* 2 load low byte of DAC value first */ + /* 2. load lsb of DAC value first */ rmw[1].address = F020_SFR_DAC0L; rmw[1].and_mask = 0xff; rmw[1].or_value = value & 0xff; - /* 3 load high byte of DAC value next to latch the - 12-bit value */ + /* 3. load msb of DAC value next to latch the 12-bit value */ rmw[2].address = F020_SFR_DAC0H; rmw[2].and_mask = 0xff; rmw[2].or_value = (value >> 8) & 0xf; @@ -529,15 +528,14 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) /* 1. Set DAC mode */ rmw[0].address = F020_SFR_DAC1CN; rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + rmw[0].or_value = F020_MASK_DACXCN_DACXEN; - /* 2 load low byte of DAC value first */ + /* 2. load lsb of DAC value first */ rmw[1].address = F020_SFR_DAC1L; rmw[1].and_mask = 0xff; rmw[1].or_value = value & 0xff; - /* 3 load high byte of DAC value next to latch the - 12-bit value */ + /* 3. load msb of DAC value next to latch the 12-bit value */ rmw[2].address = F020_SFR_DAC1H; rmw[2].and_mask = 0xff; rmw[2].or_value = (value >> 8) & 0xf; @@ -545,7 +543,7 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) } ret = dt9812_rmw_multiple_registers(dev, 3, rmw); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -608,9 +606,9 @@ static int dt9812_ao_insn_read(struct comedi_device *dev, struct dt9812_private *devpriv = dev->private; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); ret = comedi_readback_insn_read(dev, s, insn, data); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -774,7 +772,7 @@ static int dt9812_auto_attach(struct comedi_device *dev, if (!devpriv) return -ENOMEM; - sema_init(&devpriv->sem, 1); + mutex_init(&devpriv->mut); usb_set_intfdata(intf, devpriv); ret = dt9812_find_endpoints(dev); @@ -846,11 +844,11 @@ static void dt9812_detach(struct comedi_device *dev) if (!devpriv) return; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); usb_set_intfdata(intf, NULL); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); } static struct comedi_driver dt9812_driver = { diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index 55cae6145..0f278ffda 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -71,7 +71,7 @@ static int fl512_ai_insn_read(struct comedi_device *dev, outb(0, dev->iobase + FL512_AI_START_CONV_REG); /* XXX should test "done" flag instead of delay */ - udelay(30); + usleep_range(30, 100); val = inb(dev->iobase + FL512_AI_LSB_REG); val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8); diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index e92961822..46ca5d938 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -125,7 +125,7 @@ struct hpdi_private { void __iomem *plx9080_mmio; - uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ + u32 *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ /* physical addresses of dma buffers */ dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; /* @@ -137,7 +137,7 @@ struct hpdi_private { dma_addr_t dma_desc_phys_addr; unsigned int num_dma_descriptors; /* pointer to start of buffers indexed by descriptor */ - uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; + u32 *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* index of the dma descriptor that is currently being used */ unsigned int dma_desc_index; unsigned int tx_fifo_size; @@ -169,7 +169,7 @@ static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) for (desc = 0; (next < start || next >= start + devpriv->block_size) && desc < devpriv->num_dma_descriptors; desc++) { /* transfer data from dma buffer to comedi buffer */ - size = devpriv->block_size / sizeof(uint32_t); + size = devpriv->block_size / sizeof(u32); if (cmd->stop_src == TRIG_COUNT) { if (size > devpriv->dio_count) size = devpriv->dio_count; @@ -192,10 +192,10 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) struct hpdi_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; - uint32_t hpdi_intr_status, hpdi_board_status; - uint32_t plx_status; - uint32_t plx_bits; - uint8_t dma0_status, dma1_status; + u32 hpdi_intr_status, hpdi_board_status; + u32 plx_status; + u32 plx_bits; + u8 dma0_status, dma1_status; unsigned long flags; if (!dev->attached) @@ -290,7 +290,7 @@ static int gsc_hpdi_cmd(struct comedi_device *dev, struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned long flags; - uint32_t bits; + u32 bits; if (s->io_bits) return -EINVAL; @@ -424,15 +424,15 @@ static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, { struct hpdi_private *devpriv = dev->private; dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; - uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI; + u32 next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | + PLX_XFER_LOCAL_TO_PCI; unsigned int offset = 0; unsigned int idx = 0; unsigned int i; if (len > DMA_BUFFER_SIZE) len = DMA_BUFFER_SIZE; - len -= len % sizeof(uint32_t); + len -= len % sizeof(u32); if (len == 0) return -EINVAL; @@ -445,7 +445,7 @@ static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + - (offset / sizeof(uint32_t)); + (offset / sizeof(u32)); offset += len; if (len + offset > DMA_BUFFER_SIZE) { @@ -516,7 +516,7 @@ static void gsc_hpdi_free_dma(struct comedi_device *dev) static int gsc_hpdi_init(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; - uint32_t plx_intcsr_bits; + u32 plx_intcsr_bits; /* wait 10usec after reset before accessing fifos */ writel(BOARD_RESET_BIT, dev->mmio + BOARD_CONTROL_REG); @@ -546,7 +546,7 @@ static int gsc_hpdi_init(struct comedi_device *dev) static void gsc_hpdi_init_plx9080(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; - uint32_t bits; + u32 bits; void __iomem *plx_iobase = devpriv->plx9080_mmio; #ifdef __BIG_ENDIAN diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 1e104ebf8..28cf53e48 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -1,94 +1,89 @@ /* - comedi/drivers/icp_multi.c - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-2002 David A. Schleef - - 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. -*/ + * icp_multi.c + * Comedi driver for Inova ICP_MULTI board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2002 David A. Schleef + * + * 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: icp_multi -Description: Inova ICP_MULTI -Author: Anne Smorthit -Devices: [Inova] ICP_MULTI (icp_multi) -Status: works - -The driver works for analog input and output and digital input and output. -It does not work with interrupts or with the counters. Currently no support -for DMA. - -It has 16 single-ended or 8 differential Analogue Input channels with 12-bit -resolution. Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA. Input -ranges can be individually programmed for each channel. Voltage or current -measurement is selected by jumper. - -There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V - -16 x Digital Inputs, 24V - -8 x Digital Outputs, 24V, 1A - -4 x 16-bit counters - -Configuration options: not applicable, uses PCI auto config -*/ + * Driver: icp_multi + * Description: Inova ICP_MULTI + * Devices: [Inova] ICP_MULTI (icp_multi) + * Author: Anne Smorthit + * Status: works + * + * Configuration options: not applicable, uses PCI auto config + * + * The driver works for analog input and output and digital input and + * output. It does not work with interrupts or with the counters. Currently + * no support for DMA. + * + * It has 16 single-ended or 8 differential Analogue Input channels with + * 12-bit resolution. Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA. + * Input ranges can be individually programmed for each channel. Voltage or + * current measurement is selected by jumper. + * + * There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V + * + * 16 x Digital Inputs, 24V + * + * 8 x Digital Outputs, 24V, 1A + * + * 4 x 16-bit counters - not implemented + */ #include #include -#include #include "../comedi_pci.h" -#define ICP_MULTI_ADC_CSR 0 /* R/W: ADC command/status register */ +#define ICP_MULTI_ADC_CSR 0x00 /* R/W: ADC command/status register */ +#define ICP_MULTI_ADC_CSR_ST BIT(0) /* Start ADC */ +#define ICP_MULTI_ADC_CSR_BSY BIT(0) /* ADC busy */ +#define ICP_MULTI_ADC_CSR_BI BIT(4) /* Bipolar input range */ +#define ICP_MULTI_ADC_CSR_RA BIT(5) /* Input range 0 = 5V, 1 = 10V */ +#define ICP_MULTI_ADC_CSR_DI BIT(6) /* Input mode 1 = differential */ +#define ICP_MULTI_ADC_CSR_DI_CHAN(x) (((x) & 0x7) << 9) +#define ICP_MULTI_ADC_CSR_SE_CHAN(x) (((x) & 0xf) << 8) #define ICP_MULTI_AI 2 /* R: Analogue input data */ -#define ICP_MULTI_DAC_CSR 4 /* R/W: DAC command/status register */ +#define ICP_MULTI_DAC_CSR 0x04 /* R/W: DAC command/status register */ +#define ICP_MULTI_DAC_CSR_ST BIT(0) /* Start DAC */ +#define ICP_MULTI_DAC_CSR_BSY BIT(0) /* DAC busy */ +#define ICP_MULTI_DAC_CSR_BI BIT(4) /* Bipolar output range */ +#define ICP_MULTI_DAC_CSR_RA BIT(5) /* Output range 0 = 5V, 1 = 10V */ +#define ICP_MULTI_DAC_CSR_CHAN(x) (((x) & 0x3) << 8) #define ICP_MULTI_AO 6 /* R/W: Analogue output data */ #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 */ +#define ICP_MULTI_INT_EN 0x0c /* R/W: Interrupt enable register */ +#define ICP_MULTI_INT_STAT 0x0e /* R/W: Interrupt status register */ +#define ICP_MULTI_INT_ADC_RDY BIT(0) /* A/D conversion ready interrupt */ +#define ICP_MULTI_INT_DAC_RDY BIT(1) /* D/A conversion ready interrupt */ +#define ICP_MULTI_INT_DOUT_ERR BIT(2) /* Digital output error interrupt */ +#define ICP_MULTI_INT_DIN_STAT BIT(3) /* Digital input status change int. */ +#define ICP_MULTI_INT_CIE0 BIT(4) /* Counter 0 overrun interrupt */ +#define ICP_MULTI_INT_CIE1 BIT(5) /* Counter 1 overrun interrupt */ +#define ICP_MULTI_INT_CIE2 BIT(6) /* Counter 2 overrun interrupt */ +#define ICP_MULTI_INT_CIE3 BIT(7) /* Counter 3 overrun interrupt */ +#define ICP_MULTI_INT_MASK 0xff /* All interrupts */ #define ICP_MULTI_CNTR0 0x10 /* R/W: Counter 0 */ #define ICP_MULTI_CNTR1 0x12 /* R/W: counter 1 */ #define ICP_MULTI_CNTR2 0x14 /* R/W: Counter 2 */ #define ICP_MULTI_CNTR3 0x16 /* R/W: Counter 3 */ -/* Define bits from ADC command/status register */ -#define ADC_ST 0x0001 /* Start ADC */ -#define ADC_BSY 0x0001 /* ADC busy */ -#define ADC_BI 0x0010 /* Bipolar input range 1 = bipolar */ -#define ADC_RA 0x0020 /* Input range 0 = 5V, 1 = 10V */ -#define ADC_DI 0x0040 /* Differential input mode 1 = differential */ - -/* Define bits from DAC command/status register */ -#define DAC_ST 0x0001 /* Start DAC */ -#define DAC_BSY 0x0001 /* DAC busy */ -#define DAC_BI 0x0010 /* Bipolar input range 1 = bipolar */ -#define DAC_RA 0x0020 /* Input range 0 = 5V, 1 = 10V */ - -/* Define bits from interrupt enable/status registers */ -#define ADC_READY 0x0001 /* A/d conversion ready interrupt */ -#define DAC_READY 0x0002 /* D/a conversion ready interrupt */ -#define DOUT_ERROR 0x0004 /* Digital output error interrupt */ -#define DIN_STATUS 0x0008 /* Digital input status change interrupt */ -#define CIE0 0x0010 /* Counter 0 overrun interrupt */ -#define CIE1 0x0020 /* Counter 1 overrun interrupt */ -#define CIE2 0x0040 /* Counter 2 overrun interrupt */ -#define CIE3 0x0080 /* Counter 3 overrun interrupt */ - -/* Useful definitions */ -#define Status_IRQ 0x00ff /* All interrupts */ - -/* Define analogue range */ -static const struct comedi_lrange range_analog = { +/* analog input and output have the same range options */ +static const struct comedi_lrange icp_multi_ranges = { 4, { UNI_RANGE(5), UNI_RANGE(10), @@ -99,71 +94,6 @@ static const struct comedi_lrange range_analog = { static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; -/* -============================================================================== - Data & Structure declarations -============================================================================== -*/ - -struct icp_multi_private { - unsigned int AdcCmdStatus; /* ADC Command/Status register */ - unsigned int DacCmdStatus; /* DAC Command/Status register */ - unsigned int IntEnable; /* Interrupt Enable register */ - unsigned int IntStatus; /* Interrupt Status register */ - unsigned int act_chanlist[32]; /* list of scanned channel */ - unsigned char act_chanlist_len; /* len of scanlist */ - unsigned char act_chanlist_pos; /* actual position in MUX list */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int do_data; /* Remember digital output data */ -}; - -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - struct icp_multi_private *devpriv = dev->private; - unsigned int i, range, chanprog; - unsigned int diff; - - devpriv->act_chanlist_len = n_chan; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < n_chan; i++) { - /* Get channel */ - chanprog = CR_CHAN(chanlist[i]); - - /* Determine if it is a differential channel (Bit 15 = 1) */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - diff = 1; - chanprog &= 0x0007; - } else { - diff = 0; - chanprog &= 0x000f; - } - - /* Clear channel, range and input mode bits - * in A/D command/status register */ - devpriv->AdcCmdStatus &= 0xf00f; - - /* Set channel number and differential mode status bit */ - if (diff) { - /* Set channel number, bits 9-11 & mode, bit 6 */ - devpriv->AdcCmdStatus |= (chanprog << 9); - devpriv->AdcCmdStatus |= ADC_DI; - } else - /* Set channel number, bits 8-11 */ - devpriv->AdcCmdStatus |= (chanprog << 8); - - /* Get range for current channel */ - range = range_codes_analog[CR_RANGE(chanlist[i])]; - /* Set range. bits 4-5 */ - devpriv->AdcCmdStatus |= range; - - /* Output channel, range, mode to ICP Multi */ - writew(devpriv->AdcCmdStatus, dev->mmio + ICP_MULTI_ADC_CSR); - } -} - static int icp_multi_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -172,36 +102,37 @@ static int icp_multi_ai_eoc(struct comedi_device *dev, unsigned int status; status = readw(dev->mmio + ICP_MULTI_ADC_CSR); - if ((status & ADC_BSY) == 0) + if ((status & ICP_MULTI_ADC_CSR_BSY) == 0) return 0; return -EBUSY; } -static int icp_multi_insn_read_ai(struct comedi_device *dev, +static int icp_multi_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct icp_multi_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned int adc_csr; int ret = 0; int n; - /* Disable A/D conversion ready interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - - /* Set up appropriate channel, mode and range data, for specified ch */ - setup_channel_list(dev, s, &insn->chanspec, 1); + /* Set mode and range data for specified channel */ + if (aref == AREF_DIFF) { + adc_csr = ICP_MULTI_ADC_CSR_DI_CHAN(chan) | + ICP_MULTI_ADC_CSR_DI; + } else { + adc_csr = ICP_MULTI_ADC_CSR_SE_CHAN(chan); + } + adc_csr |= range_codes_analog[range]; + writew(adc_csr, dev->mmio + ICP_MULTI_ADC_CSR); for (n = 0; n < insn->n; n++) { /* Set start ADC bit */ - devpriv->AdcCmdStatus |= ADC_ST; - writew(devpriv->AdcCmdStatus, dev->mmio + ICP_MULTI_ADC_CSR); - devpriv->AdcCmdStatus &= ~ADC_ST; + writew(adc_csr | ICP_MULTI_ADC_CSR_ST, + dev->mmio + ICP_MULTI_ADC_CSR); udelay(1); @@ -213,26 +144,18 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, data[n] = (readw(dev->mmio + ICP_MULTI_AI) >> 4) & 0x0fff; } - /* Disable interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - return ret ? ret : n; } -static int icp_multi_ao_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned long context) +static int icp_multi_ao_ready(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; status = readw(dev->mmio + ICP_MULTI_DAC_CSR); - if ((status & DAC_BSY) == 0) + if ((status & ICP_MULTI_DAC_CSR_BSY) == 0) return 0; return -EBUSY; } @@ -242,57 +165,30 @@ static int icp_multi_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct icp_multi_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); + unsigned int dac_csr; int i; - /* Disable D/A conversion ready interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - - /* Set up range and channel data */ - /* Bit 4 = 1 : Bipolar */ - /* Bit 5 = 0 : 5V */ - /* Bit 5 = 1 : 10V */ - /* Bits 8-9 : Channel number */ - devpriv->DacCmdStatus &= 0xfccf; - devpriv->DacCmdStatus |= range_codes_analog[range]; - devpriv->DacCmdStatus |= (chan << 8); - - writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR); + /* Select channel and range */ + dac_csr = ICP_MULTI_DAC_CSR_CHAN(chan); + dac_csr |= range_codes_analog[range]; + writew(dac_csr, dev->mmio + ICP_MULTI_DAC_CSR); for (i = 0; i < insn->n; i++) { unsigned int val = data[i]; int ret; - /* Wait for analogue output data register to be - * ready for new data, or get fed up waiting */ - ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0); - if (ret) { - /* Disable interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, - dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, - dev->mmio + ICP_MULTI_INT_STAT); - + /* Wait for analog output to be ready for new data */ + ret = comedi_timeout(dev, s, insn, icp_multi_ao_ready, 0); + if (ret) return ret; - } writew(val, dev->mmio + ICP_MULTI_AO); - /* Set DAC_ST bit to write the data to selected channel */ - devpriv->DacCmdStatus |= DAC_ST; - writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR); - devpriv->DacCmdStatus &= ~DAC_ST; + /* Set start conversion bit to write data to channel */ + writew(dac_csr | ICP_MULTI_DAC_CSR_ST, + dev->mmio + ICP_MULTI_DAC_CSR); s->readback[chan] = val; } @@ -300,7 +196,7 @@ static int icp_multi_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int icp_multi_insn_bits_di(struct comedi_device *dev, +static int icp_multi_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -310,7 +206,7 @@ static int icp_multi_insn_bits_di(struct comedi_device *dev, return insn->n; } -static int icp_multi_insn_bits_do(struct comedi_device *dev, +static int icp_multi_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -323,116 +219,27 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev, return insn->n; } -static int icp_multi_insn_read_ctr(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return 0; -} - -static int icp_multi_insn_write_ctr(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - return 0; -} - -static irqreturn_t interrupt_service_icp_multi(int irq, void *d) -{ - struct comedi_device *dev = d; - int int_no; - - /* Is this interrupt from our board? */ - int_no = readw(dev->mmio + ICP_MULTI_INT_STAT) & Status_IRQ; - if (!int_no) - /* No, exit */ - return IRQ_NONE; - - /* Determine which interrupt is active & handle it */ - switch (int_no) { - case ADC_READY: - break; - case DAC_READY: - break; - case DOUT_ERROR: - break; - case DIN_STATUS: - break; - case CIE0: - break; - case CIE1: - break; - case CIE2: - break; - case CIE3: - break; - default: - break; - } - - return IRQ_HANDLED; -} - -#if 0 -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - unsigned int i; - - /* Check that we at least have one channel to check */ - if (n_chan < 1) { - dev_err(dev->class_dev, "range/channel list is empty!\n"); - return 0; - } - /* Check all channels */ - for (i = 0; i < n_chan; i++) { - /* Check that channel number is < maximum */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - if (CR_CHAN(chanlist[i]) > (s->nchan / 2)) { - dev_err(dev->class_dev, - "Incorrect differential ai ch-nr\n"); - return 0; - } - } else { - if (CR_CHAN(chanlist[i]) > s->n_chan) { - dev_err(dev->class_dev, - "Incorrect ai channel number\n"); - return 0; - } - } - } - return 1; -} -#endif - static int icp_multi_reset(struct comedi_device *dev) { - struct icp_multi_private *devpriv = dev->private; - unsigned int i; + int i; - /* Clear INT enables and requests */ + /* Disable all interrupts and clear any requests */ writew(0, dev->mmio + ICP_MULTI_INT_EN); - writew(0x00ff, dev->mmio + ICP_MULTI_INT_STAT); + writew(ICP_MULTI_INT_MASK, dev->mmio + ICP_MULTI_INT_STAT); - /* Set DACs to 0..5V range and 0V output */ + /* Reset the analog output channels to 0V */ for (i = 0; i < 4; i++) { - devpriv->DacCmdStatus &= 0xfcce; + unsigned int dac_csr = ICP_MULTI_DAC_CSR_CHAN(i); - /* Set channel number */ - devpriv->DacCmdStatus |= (i << 8); + /* Select channel and 0..5V range */ + writew(dac_csr, dev->mmio + ICP_MULTI_DAC_CSR); - /* Output 0V */ + /* Output 0V */ writew(0, dev->mmio + ICP_MULTI_AO); - /* Set start conversion bit */ - devpriv->DacCmdStatus |= DAC_ST; - - /* Output to command / status register */ - writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR); - - /* Delay to allow DAC time to recover */ + /* Set start conversion bit to write data to channel */ + writew(dac_csr | ICP_MULTI_DAC_CSR_ST, + dev->mmio + ICP_MULTI_DAC_CSR); udelay(1); } @@ -446,14 +253,9 @@ static int icp_multi_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct icp_multi_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; @@ -462,85 +264,60 @@ static int icp_multi_auto_attach(struct comedi_device *dev, if (!dev->mmio) return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 5); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; icp_multi_reset(dev); - if (pcidev->irq) { - ret = request_irq(pcidev->irq, interrupt_service_icp_multi, - IRQF_SHARED, dev->board_name, dev); - if (ret == 0) - dev->irq = pcidev->irq; - } - + /* 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; - s->n_chan = 16; - s->maxdata = 0x0fff; - s->len_chanlist = 16; - s->range_table = &range_analog; - s->insn_read = icp_multi_insn_read_ai; - + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = &icp_multi_ranges; + s->insn_read = icp_multi_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 0x0fff; - s->len_chanlist = 4; - s->range_table = &range_analog; - s->insn_write = icp_multi_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->range_table = &icp_multi_ranges; + s->insn_write = icp_multi_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) return ret; + /* Digital Input subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->insn_bits = icp_multi_insn_bits_di; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = icp_multi_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->len_chanlist = 8; - s->range_table = &range_digital; - s->insn_bits = icp_multi_insn_bits_do; - - s = &dev->subdevices[4]; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - s->state = 0; - s->insn_read = icp_multi_insn_read_ctr; - s->insn_write = icp_multi_insn_write_ctr; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = icp_multi_do_insn_bits; return 0; } -static void icp_multi_detach(struct comedi_device *dev) -{ - if (dev->mmio) - icp_multi_reset(dev); - comedi_pci_detach(dev); -} - static struct comedi_driver icp_multi_driver = { .driver_name = "icp_multi", .module = THIS_MODULE, .auto_attach = icp_multi_auto_attach, - .detach = icp_multi_detach, + .detach = comedi_pci_detach, }; static int icp_multi_pci_probe(struct pci_dev *dev, @@ -564,5 +341,5 @@ static struct pci_driver icp_multi_pci_driver = { module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Inova ICP_MULTI board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 14ef1f67d..77e1d891f 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -37,37 +37,37 @@ #define II20K_SIZE 0x400 #define II20K_MOD_OFFSET 0x100 #define II20K_ID_REG 0x00 -#define II20K_ID_MOD1_EMPTY (1 << 7) -#define II20K_ID_MOD2_EMPTY (1 << 6) -#define II20K_ID_MOD3_EMPTY (1 << 5) +#define II20K_ID_MOD1_EMPTY BIT(7) +#define II20K_ID_MOD2_EMPTY BIT(6) +#define II20K_ID_MOD3_EMPTY BIT(5) #define II20K_ID_MASK 0x1f #define II20K_ID_PCI20001C_1A 0x1b /* no on-board DIO */ #define II20K_ID_PCI20001C_2A 0x1d /* on-board DIO */ #define II20K_MOD_STATUS_REG 0x40 -#define II20K_MOD_STATUS_IRQ_MOD1 (1 << 7) -#define II20K_MOD_STATUS_IRQ_MOD2 (1 << 6) -#define II20K_MOD_STATUS_IRQ_MOD3 (1 << 5) +#define II20K_MOD_STATUS_IRQ_MOD1 BIT(7) +#define II20K_MOD_STATUS_IRQ_MOD2 BIT(6) +#define II20K_MOD_STATUS_IRQ_MOD3 BIT(5) #define II20K_DIO0_REG 0x80 #define II20K_DIO1_REG 0x81 #define II20K_DIR_ENA_REG 0x82 -#define II20K_DIR_DIO3_OUT (1 << 7) -#define II20K_DIR_DIO2_OUT (1 << 6) -#define II20K_BUF_DISAB_DIO3 (1 << 5) -#define II20K_BUF_DISAB_DIO2 (1 << 4) -#define II20K_DIR_DIO1_OUT (1 << 3) -#define II20K_DIR_DIO0_OUT (1 << 2) -#define II20K_BUF_DISAB_DIO1 (1 << 1) -#define II20K_BUF_DISAB_DIO0 (1 << 0) +#define II20K_DIR_DIO3_OUT BIT(7) +#define II20K_DIR_DIO2_OUT BIT(6) +#define II20K_BUF_DISAB_DIO3 BIT(5) +#define II20K_BUF_DISAB_DIO2 BIT(4) +#define II20K_DIR_DIO1_OUT BIT(3) +#define II20K_DIR_DIO0_OUT BIT(2) +#define II20K_BUF_DISAB_DIO1 BIT(1) +#define II20K_BUF_DISAB_DIO0 BIT(0) #define II20K_CTRL01_REG 0x83 -#define II20K_CTRL01_SET (1 << 7) -#define II20K_CTRL01_DIO0_IN (1 << 4) -#define II20K_CTRL01_DIO1_IN (1 << 1) +#define II20K_CTRL01_SET BIT(7) +#define II20K_CTRL01_DIO0_IN BIT(4) +#define II20K_CTRL01_DIO1_IN BIT(1) #define II20K_DIO2_REG 0xc0 #define II20K_DIO3_REG 0xc1 #define II20K_CTRL23_REG 0xc3 -#define II20K_CTRL23_SET (1 << 7) -#define II20K_CTRL23_DIO2_IN (1 << 4) -#define II20K_CTRL23_DIO3_IN (1 << 1) +#define II20K_CTRL23_SET BIT(7) +#define II20K_CTRL23_DIO2_IN BIT(4) +#define II20K_CTRL23_DIO3_IN BIT(1) #define II20K_ID_PCI20006M_1 0xe2 /* 1 AO channels */ #define II20K_ID_PCI20006M_2 0xe3 /* 2 AO channels */ @@ -78,27 +78,27 @@ #define II20K_ID_PCI20341M_1 0x77 /* 4 AI channels */ #define II20K_AI_STATUS_CMD_REG 0x01 -#define II20K_AI_STATUS_CMD_BUSY (1 << 7) -#define II20K_AI_STATUS_CMD_HW_ENA (1 << 1) -#define II20K_AI_STATUS_CMD_EXT_START (1 << 0) +#define II20K_AI_STATUS_CMD_BUSY BIT(7) +#define II20K_AI_STATUS_CMD_HW_ENA BIT(1) +#define II20K_AI_STATUS_CMD_EXT_START BIT(0) #define II20K_AI_LSB_REG 0x02 #define II20K_AI_MSB_REG 0x03 #define II20K_AI_PACER_RESET_REG 0x04 #define II20K_AI_16BIT_DATA_REG 0x06 #define II20K_AI_CONF_REG 0x10 -#define II20K_AI_CONF_ENA (1 << 2) +#define II20K_AI_CONF_ENA BIT(2) #define II20K_AI_OPT_REG 0x11 -#define II20K_AI_OPT_TRIG_ENA (1 << 5) -#define II20K_AI_OPT_TRIG_INV (1 << 4) +#define II20K_AI_OPT_TRIG_ENA BIT(5) +#define II20K_AI_OPT_TRIG_INV BIT(4) #define II20K_AI_OPT_TIMEBASE(x) (((x) & 0x3) << 1) -#define II20K_AI_OPT_BURST_MODE (1 << 0) +#define II20K_AI_OPT_BURST_MODE BIT(0) #define II20K_AI_STATUS_REG 0x12 -#define II20K_AI_STATUS_INT (1 << 7) -#define II20K_AI_STATUS_TRIG (1 << 6) -#define II20K_AI_STATUS_TRIG_ENA (1 << 5) -#define II20K_AI_STATUS_PACER_ERR (1 << 2) -#define II20K_AI_STATUS_DATA_ERR (1 << 1) -#define II20K_AI_STATUS_SET_TIME_ERR (1 << 0) +#define II20K_AI_STATUS_INT BIT(7) +#define II20K_AI_STATUS_TRIG BIT(6) +#define II20K_AI_STATUS_TRIG_ENA BIT(5) +#define II20K_AI_STATUS_PACER_ERR BIT(2) +#define II20K_AI_STATUS_DATA_ERR BIT(1) +#define II20K_AI_STATUS_SET_TIME_ERR BIT(0) #define II20K_AI_LAST_CHAN_ADDR_REG 0x13 #define II20K_AI_CUR_ADDR_REG 0x14 #define II20K_AI_SET_TIME_REG 0x15 @@ -109,9 +109,9 @@ #define II20K_AI_START_TRIG_REG 0x1a #define II20K_AI_COUNT_RESET_REG 0x1b #define II20K_AI_CHANLIST_REG 0x80 -#define II20K_AI_CHANLIST_ONBOARD_ONLY (1 << 5) +#define II20K_AI_CHANLIST_ONBOARD_ONLY BIT(5) #define II20K_AI_CHANLIST_GAIN(x) (((x) & 0x3) << 3) -#define II20K_AI_CHANLIST_MUX_ENA (1 << 2) +#define II20K_AI_CHANLIST_MUX_ENA BIT(2) #define II20K_AI_CHANLIST_CHAN(x) (((x) & 0x3) << 0) #define II20K_AI_CHANLIST_LEN 0x80 @@ -153,9 +153,8 @@ static int ii20k_ao_insn_write(struct comedi_device *dev, s->readback[chan] = val; - /* munge data */ - val += ((s->maxdata + 1) >> 1); - val &= s->maxdata; + /* munge the offset binary data to 2's complement */ + val = comedi_offset_munge(s, val); writeb(val & 0xff, iobase + II20K_AO_LSB_REG(chan)); writeb((val >> 8) & 0xff, iobase + II20K_AO_MSB_REG(chan)); @@ -243,11 +242,8 @@ static int ii20k_ai_insn_read(struct comedi_device *dev, val = readb(iobase + II20K_AI_LSB_REG); val |= (readb(iobase + II20K_AI_MSB_REG) << 8); - /* munge two's complement data */ - val += ((s->maxdata + 1) >> 1); - val &= s->maxdata; - - data[i] = val; + /* munge the 2's complement data to offset binary */ + data[i] = comedi_offset_munge(s, val); } return insn->n; @@ -523,5 +519,5 @@ static struct comedi_driver ii20k_driver = { module_comedi_driver(ii20k_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Intelligent Instruments PCI-20001C"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 40dd2b219..f1793bd50 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -30,11 +30,7 @@ * driver; supported PCI devices are configured as comedi devices * automatically. * - * The DSP on the board requires initialization code, which can be - * loaded by placing it in /lib/firmware/comedi. The initialization - * code should be somewhere on the media you got with your card. One - * version is available from http://www.comedi.org in the - * comedi_nonfree_firmware tarball. The file is called "/*(DEBLOBBED)*/ +/*(DEBLOBBED)*/ #include #include diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index dc642edf4..93198abf0 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -41,9 +41,10 @@ #define KE_MSB_REG(x) (0x0c + ((x) * 0x20)) #define KE_SIGN_REG(x) (0x10 + ((x) * 0x20)) #define KE_OSC_SEL_REG 0xf8 -#define KE_OSC_SEL_EXT (1 << 0) -#define KE_OSC_SEL_4MHZ (2 << 0) -#define KE_OSC_SEL_20MHZ (3 << 0) +#define KE_OSC_SEL_CLK(x) (((x) & 0x3) << 0) +#define KE_OSC_SEL_EXT KE_OSC_SEL_CLK(1) +#define KE_OSC_SEL_4MHZ KE_OSC_SEL_CLK(2) +#define KE_OSC_SEL_20MHZ KE_OSC_SEL_CLK(3) #define KE_DO_REG 0xfc static int ke_counter_insn_write(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 80925450f..5d877a2e6 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -41,84 +41,63 @@ #define XILINX_DOWNLOAD_RESET 0x42 /* Xilinx registers */ -#define ME_CONTROL_1 0x0000 /* - | W */ -#define INTERRUPT_ENABLE (1<<15) -#define COUNTER_B_IRQ (1<<12) -#define COUNTER_A_IRQ (1<<11) -#define CHANLIST_READY_IRQ (1<<10) -#define EXT_IRQ (1<<9) -#define ADFIFO_HALFFULL_IRQ (1<<8) -#define SCAN_COUNT_ENABLE (1<<5) -#define SIMULTANEOUS_ENABLE (1<<4) -#define TRIGGER_FALLING_EDGE (1<<3) -#define CONTINUOUS_MODE (1<<2) -#define DISABLE_ADC (0<<0) -#define SOFTWARE_TRIGGERED_ADC (1<<0) -#define SCAN_TRIGGERED_ADC (2<<0) -#define EXT_TRIGGERED_ADC (3<<0) -#define ME_ADC_START 0x0000 /* R | - */ -#define ME_CONTROL_2 0x0002 /* - | W */ -#define ENABLE_ADFIFO (1<<10) -#define ENABLE_CHANLIST (1<<9) -#define ENABLE_PORT_B (1<<7) -#define ENABLE_PORT_A (1<<6) -#define ENABLE_COUNTER_B (1<<4) -#define ENABLE_COUNTER_A (1<<3) -#define ENABLE_DAC (1<<1) -#define BUFFERED_DAC (1<<0) -#define ME_DAC_UPDATE 0x0002 /* R | - */ -#define ME_STATUS 0x0004 /* R | - */ -#define COUNTER_B_IRQ_PENDING (1<<12) -#define COUNTER_A_IRQ_PENDING (1<<11) -#define CHANLIST_READY_IRQ_PENDING (1<<10) -#define EXT_IRQ_PENDING (1<<9) -#define ADFIFO_HALFFULL_IRQ_PENDING (1<<8) -#define ADFIFO_FULL (1<<4) -#define ADFIFO_HALFFULL (1<<3) -#define ADFIFO_EMPTY (1<<2) -#define CHANLIST_FULL (1<<1) -#define FST_ACTIVE (1<<0) -#define ME_RESET_INTERRUPT 0x0004 /* - | W */ -#define ME_DIO_PORT_A 0x0006 /* R | W */ -#define ME_DIO_PORT_B 0x0008 /* R | W */ -#define ME_TIMER_DATA_0 0x000A /* - | W */ -#define ME_TIMER_DATA_1 0x000C /* - | W */ -#define ME_TIMER_DATA_2 0x000E /* - | W */ -#define ME_CHANNEL_LIST 0x0010 /* - | W */ -#define ADC_UNIPOLAR (1<<6) -#define ADC_GAIN_0 (0<<4) -#define ADC_GAIN_1 (1<<4) -#define ADC_GAIN_2 (2<<4) -#define ADC_GAIN_3 (3<<4) -#define ME_READ_AD_FIFO 0x0010 /* R | - */ -#define ME_DAC_CONTROL 0x0012 /* - | W */ -#define DAC_UNIPOLAR_D (0<<4) -#define DAC_BIPOLAR_D (1<<4) -#define DAC_UNIPOLAR_C (0<<5) -#define DAC_BIPOLAR_C (1<<5) -#define DAC_UNIPOLAR_B (0<<6) -#define DAC_BIPOLAR_B (1<<6) -#define DAC_UNIPOLAR_A (0<<7) -#define DAC_BIPOLAR_A (1<<7) -#define DAC_GAIN_0_D (0<<8) -#define DAC_GAIN_1_D (1<<8) -#define DAC_GAIN_0_C (0<<9) -#define DAC_GAIN_1_C (1<<9) -#define DAC_GAIN_0_B (0<<10) -#define DAC_GAIN_1_B (1<<10) -#define DAC_GAIN_0_A (0<<11) -#define DAC_GAIN_1_A (1<<11) -#define ME_DAC_CONTROL_UPDATE 0x0012 /* R | - */ -#define ME_DAC_DATA_A 0x0014 /* - | W */ -#define ME_DAC_DATA_B 0x0016 /* - | W */ -#define ME_DAC_DATA_C 0x0018 /* - | W */ -#define ME_DAC_DATA_D 0x001A /* - | W */ -#define ME_COUNTER_ENDDATA_A 0x001C /* - | W */ -#define ME_COUNTER_ENDDATA_B 0x001E /* - | W */ -#define ME_COUNTER_STARTDATA_A 0x0020 /* - | W */ -#define ME_COUNTER_VALUE_A 0x0020 /* R | - */ -#define ME_COUNTER_STARTDATA_B 0x0022 /* - | W */ -#define ME_COUNTER_VALUE_B 0x0022 /* R | - */ +/* + * PCI BAR2 Memory map (dev->mmio) + */ +#define ME_CTRL1_REG 0x00 /* R (ai start) | W */ +#define ME_CTRL1_INT_ENA BIT(15) +#define ME_CTRL1_COUNTER_B_IRQ BIT(12) +#define ME_CTRL1_COUNTER_A_IRQ BIT(11) +#define ME_CTRL1_CHANLIST_READY_IRQ BIT(10) +#define ME_CTRL1_EXT_IRQ BIT(9) +#define ME_CTRL1_ADFIFO_HALFFULL_IRQ BIT(8) +#define ME_CTRL1_SCAN_COUNT_ENA BIT(5) +#define ME_CTRL1_SIMULTANEOUS_ENA BIT(4) +#define ME_CTRL1_TRIGGER_FALLING_EDGE BIT(3) +#define ME_CTRL1_CONTINUOUS_MODE BIT(2) +#define ME_CTRL1_ADC_MODE(x) (((x) & 0x3) << 0) +#define ME_CTRL1_ADC_MODE_DISABLE ME_CTRL1_ADC_MODE(0) +#define ME_CTRL1_ADC_MODE_SOFT_TRIG ME_CTRL1_ADC_MODE(1) +#define ME_CTRL1_ADC_MODE_SCAN_TRIG ME_CTRL1_ADC_MODE(2) +#define ME_CTRL1_ADC_MODE_EXT_TRIG ME_CTRL1_ADC_MODE(3) +#define ME_CTRL1_ADC_MODE_MASK ME_CTRL1_ADC_MODE(3) +#define ME_CTRL2_REG 0x02 /* R (dac update) | W */ +#define ME_CTRL2_ADFIFO_ENA BIT(10) +#define ME_CTRL2_CHANLIST_ENA BIT(9) +#define ME_CTRL2_PORT_B_ENA BIT(7) +#define ME_CTRL2_PORT_A_ENA BIT(6) +#define ME_CTRL2_COUNTER_B_ENA BIT(4) +#define ME_CTRL2_COUNTER_A_ENA BIT(3) +#define ME_CTRL2_DAC_ENA BIT(1) +#define ME_CTRL2_BUFFERED_DAC BIT(0) +#define ME_STATUS_REG 0x04 /* R | W (clears interrupts) */ +#define ME_STATUS_COUNTER_B_IRQ BIT(12) +#define ME_STATUS_COUNTER_A_IRQ BIT(11) +#define ME_STATUS_CHANLIST_READY_IRQ BIT(10) +#define ME_STATUS_EXT_IRQ BIT(9) +#define ME_STATUS_ADFIFO_HALFFULL_IRQ BIT(8) +#define ME_STATUS_ADFIFO_FULL BIT(4) +#define ME_STATUS_ADFIFO_HALFFULL BIT(3) +#define ME_STATUS_ADFIFO_EMPTY BIT(2) +#define ME_STATUS_CHANLIST_FULL BIT(1) +#define ME_STATUS_FST_ACTIVE BIT(0) +#define ME_DIO_PORT_A_REG 0x06 /* R | W */ +#define ME_DIO_PORT_B_REG 0x08 /* R | W */ +#define ME_TIMER_DATA_REG(x) (0x0a + ((x) * 2)) /* - | W */ +#define ME_AI_FIFO_REG 0x10 /* R (fifo) | W (chanlist) */ +#define ME_AI_FIFO_CHANLIST_DIFF BIT(7) +#define ME_AI_FIFO_CHANLIST_UNIPOLAR BIT(6) +#define ME_AI_FIFO_CHANLIST_GAIN(x) (((x) & 0x3) << 4) +#define ME_AI_FIFO_CHANLIST_CHAN(x) (((x) & 0xf) << 0) +#define ME_DAC_CTRL_REG 0x12 /* R (updates) | W */ +#define ME_DAC_CTRL_BIPOLAR(x) BIT(7 - ((x) & 0x3)) +#define ME_DAC_CTRL_GAIN(x) BIT(11 - ((x) & 0x3)) +#define ME_DAC_CTRL_MASK(x) (ME_DAC_CTRL_BIPOLAR(x) | \ + ME_DAC_CTRL_GAIN(x)) +#define ME_AO_DATA_REG(x) (0x14 + ((x) * 2)) /* - | W */ +#define ME_COUNTER_ENDDATA_REG(x) (0x1c + ((x) * 2)) /* - | W */ +#define ME_COUNTER_STARTDATA_REG(x) (0x20 + ((x) * 2)) /* - | W */ +#define ME_COUNTER_VALUE_REG(x) (0x20 + ((x) * 2)) /* R | - */ static const struct comedi_lrange me_ai_range = { 8, { @@ -166,9 +145,9 @@ static const struct me_board me_boards[] = { struct me_private_data { void __iomem *plx_regbase; /* PLX configuration base address */ - unsigned short control_1; /* Mirror of CONTROL_1 register */ - unsigned short control_2; /* Mirror of CONTROL_2 register */ - unsigned short dac_control; /* Mirror of the DAC_CONTROL register */ + unsigned short ctrl1; /* Mirror of CONTROL_1 register */ + unsigned short ctrl2; /* Mirror of CONTROL_2 register */ + unsigned short dac_ctrl; /* Mirror of the DAC_CONTROL register */ }; static inline void sleep(unsigned sec) @@ -196,15 +175,15 @@ static int me_dio_insn_config(struct comedi_device *dev, return ret; if (s->io_bits & 0x0000ffff) - devpriv->control_2 |= ENABLE_PORT_A; + devpriv->ctrl2 |= ME_CTRL2_PORT_A_ENA; else - devpriv->control_2 &= ~ENABLE_PORT_A; + devpriv->ctrl2 &= ~ME_CTRL2_PORT_A_ENA; if (s->io_bits & 0xffff0000) - devpriv->control_2 |= ENABLE_PORT_B; + devpriv->ctrl2 |= ME_CTRL2_PORT_B_ENA; else - devpriv->control_2 &= ~ENABLE_PORT_B; + devpriv->ctrl2 &= ~ME_CTRL2_PORT_B_ENA; - writew(devpriv->control_2, dev->mmio + ME_CONTROL_2); + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); return insn->n; } @@ -214,8 +193,8 @@ static int me_dio_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - void __iomem *mmio_porta = dev->mmio + ME_DIO_PORT_A; - void __iomem *mmio_portb = dev->mmio + ME_DIO_PORT_B; + void __iomem *mmio_porta = dev->mmio + ME_DIO_PORT_A_REG; + void __iomem *mmio_portb = dev->mmio + ME_DIO_PORT_B_REG; unsigned int mask; unsigned int val; @@ -249,8 +228,8 @@ static int me_ai_eoc(struct comedi_device *dev, { unsigned int status; - status = readw(dev->mmio + ME_STATUS); - if ((status & 0x0004) == 0) + status = readw(dev->mmio + ME_STATUS_REG); + if ((status & ME_STATUS_ADFIFO_EMPTY) == 0) return 0; return -EBUSY; } @@ -260,57 +239,66 @@ static int me_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); - unsigned short val; - int ret; + unsigned int val; + int ret = 0; + int i; - /* stop any running conversion */ - dev_private->control_1 &= 0xFFFC; - writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); + /* + * For differential operation, there are only 8 input channels + * and only bipolar ranges are available. + */ + if (aref & AREF_DIFF) { + if (chan > 7 || comedi_range_is_unipolar(s, range)) + return -EINVAL; + } /* clear chanlist and ad fifo */ - dev_private->control_2 &= ~(ENABLE_ADFIFO | ENABLE_CHANLIST); - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 &= ~(ME_CTRL2_ADFIFO_ENA | ME_CTRL2_CHANLIST_ENA); + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); - /* reset any pending interrupt */ - writew(0x00, dev->mmio + ME_RESET_INTERRUPT); + writew(0x00, dev->mmio + ME_STATUS_REG); /* clear interrupts */ /* enable the chanlist and ADC fifo */ - dev_private->control_2 |= (ENABLE_ADFIFO | ENABLE_CHANLIST); - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 |= (ME_CTRL2_ADFIFO_ENA | ME_CTRL2_CHANLIST_ENA); + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); /* write to channel list fifo */ - val = chan & 0x0f; /* b3:b0 channel */ - val |= (rang & 0x03) << 4; /* b5:b4 gain */ - val |= (rang & 0x04) << 4; /* b6 polarity */ - val |= ((aref & AREF_DIFF) ? 0x80 : 0); /* b7 differential */ - writew(val & 0xff, dev->mmio + ME_CHANNEL_LIST); + val = ME_AI_FIFO_CHANLIST_CHAN(chan) | ME_AI_FIFO_CHANLIST_GAIN(range); + if (comedi_range_is_unipolar(s, range)) + val |= ME_AI_FIFO_CHANLIST_UNIPOLAR; + if (aref & AREF_DIFF) + val |= ME_AI_FIFO_CHANLIST_DIFF; + writew(val, dev->mmio + ME_AI_FIFO_REG); /* set ADC mode to software trigger */ - dev_private->control_1 |= SOFTWARE_TRIGGERED_ADC; - writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); + devpriv->ctrl1 |= ME_CTRL1_ADC_MODE_SOFT_TRIG; + writew(devpriv->ctrl1, dev->mmio + ME_CTRL1_REG); + + for (i = 0; i < insn->n; i++) { + /* start ai conversion */ + readw(dev->mmio + ME_CTRL1_REG); - /* start conversion by reading from ADC_START */ - readw(dev->mmio + ME_ADC_START); + /* wait for ADC fifo not empty flag */ + ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); + if (ret) + break; - /* wait for ADC fifo not empty flag */ - ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); - if (ret) - return ret; + /* get value from ADC fifo */ + val = readw(dev->mmio + ME_AI_FIFO_REG) & s->maxdata; - /* get value from ADC fifo */ - val = readw(dev->mmio + ME_READ_AD_FIFO); - val = (val ^ 0x800) & 0x0fff; - data[0] = val; + /* munge 2's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); + } /* stop any running conversion */ - dev_private->control_1 &= 0xFFFC; - writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); + devpriv->ctrl1 &= ~ME_CTRL1_ADC_MODE_MASK; + writew(devpriv->ctrl1, dev->mmio + ME_CTRL1_REG); - return 1; + return ret ? ret : insn->n; } static int me_ao_insn_write(struct comedi_device *dev, @@ -318,46 +306,41 @@ static int me_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned int val = s->readback[chan]; int i; /* Enable all DAC */ - dev_private->control_2 |= ENABLE_DAC; - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 |= ME_CTRL2_DAC_ENA; + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); /* and set DAC to "buffered" mode */ - dev_private->control_2 |= BUFFERED_DAC; - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 |= ME_CTRL2_BUFFERED_DAC; + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); /* Set dac-control register */ - for (i = 0; i < insn->n; i++) { - /* clear bits for this channel */ - dev_private->dac_control &= ~(0x0880 >> chan); - if (rang == 0) - dev_private->dac_control |= - ((DAC_BIPOLAR_A | DAC_GAIN_1_A) >> chan); - else if (rang == 1) - dev_private->dac_control |= - ((DAC_BIPOLAR_A | DAC_GAIN_0_A) >> chan); - } - writew(dev_private->dac_control, dev->mmio + ME_DAC_CONTROL); + devpriv->dac_ctrl &= ~ME_DAC_CTRL_MASK(chan); + if (range == 0) + devpriv->dac_ctrl |= ME_DAC_CTRL_GAIN(chan); + if (comedi_range_is_bipolar(s, range)) + devpriv->dac_ctrl |= ME_DAC_CTRL_BIPOLAR(chan); + writew(devpriv->dac_ctrl, dev->mmio + ME_DAC_CTRL_REG); /* Update dac-control register */ - readw(dev->mmio + ME_DAC_CONTROL_UPDATE); + readw(dev->mmio + ME_DAC_CTRL_REG); /* Set data register */ for (i = 0; i < insn->n; i++) { val = data[i]; - writew(val, dev->mmio + ME_DAC_DATA_A + (chan << 1)); + writew(val, dev->mmio + ME_AO_DATA_REG(chan)); } s->readback[chan] = val; /* Update dac with data registers */ - readw(dev->mmio + ME_DAC_UPDATE); + readw(dev->mmio + ME_CTRL2_REG); return insn->n; } @@ -366,13 +349,13 @@ static int me2600_xilinx_download(struct comedi_device *dev, const u8 *data, size_t size, unsigned long context) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; unsigned int value; unsigned int file_length; unsigned int i; /* disable irq's on PLX */ - writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); + writel(0x00, devpriv->plx_regbase + PLX9052_INTCSR); /* First, make a dummy read to reset xilinx */ value = readw(dev->mmio + XILINX_DOWNLOAD_RESET); @@ -412,10 +395,10 @@ static int me2600_xilinx_download(struct comedi_device *dev, writeb(0x00, dev->mmio + 0x0); /* Test if there was an error during download -> INTB was thrown */ - value = readl(dev_private->plx_regbase + PLX9052_INTCSR); + value = readl(devpriv->plx_regbase + PLX9052_INTCSR); if (value & PLX9052_INTCSR_LI2STAT) { /* Disable interrupt */ - writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); + writel(0x00, devpriv->plx_regbase + PLX9052_INTCSR); dev_err(dev->class_dev, "Xilinx download failed\n"); return -EIO; } @@ -427,25 +410,25 @@ static int me2600_xilinx_download(struct comedi_device *dev, writel(PLX9052_INTCSR_LI1ENAB | PLX9052_INTCSR_LI1POL | PLX9052_INTCSR_PCIENAB, - dev_private->plx_regbase + PLX9052_INTCSR); + devpriv->plx_regbase + PLX9052_INTCSR); return 0; } static int me_reset(struct comedi_device *dev) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; /* Reset board */ - writew(0x00, dev->mmio + ME_CONTROL_1); - writew(0x00, dev->mmio + ME_CONTROL_2); - writew(0x00, dev->mmio + ME_RESET_INTERRUPT); - writew(0x00, dev->mmio + ME_DAC_CONTROL); + writew(0x00, dev->mmio + ME_CTRL1_REG); + writew(0x00, dev->mmio + ME_CTRL2_REG); + writew(0x00, dev->mmio + ME_STATUS_REG); /* clear interrupts */ + writew(0x00, dev->mmio + ME_DAC_CTRL_REG); /* Save values in the board context */ - dev_private->dac_control = 0; - dev_private->control_1 = 0; - dev_private->control_2 = 0; + devpriv->dac_ctrl = 0; + devpriv->ctrl1 = 0; + devpriv->ctrl2 = 0; return 0; } @@ -455,7 +438,7 @@ static int me_auto_attach(struct comedi_device *dev, { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct me_board *board = NULL; - struct me_private_data *dev_private; + struct me_private_data *devpriv; struct comedi_subdevice *s; int ret; @@ -466,16 +449,16 @@ static int me_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); - if (!dev_private) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; ret = comedi_pci_enable(dev); if (ret) return ret; - dev_private->plx_regbase = pci_ioremap_bar(pcidev, 0); - if (!dev_private->plx_regbase) + devpriv->plx_regbase = pci_ioremap_bar(pcidev, 0); + if (!devpriv->plx_regbase) return -ENOMEM; dev->mmio = pci_ioremap_bar(pcidev, 2); @@ -498,7 +481,7 @@ static int me_auto_attach(struct comedi_device *dev, s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_DIFF; s->n_chan = 16; s->maxdata = 0x0fff; s->len_chanlist = 16; @@ -537,13 +520,13 @@ static int me_auto_attach(struct comedi_device *dev, static void me_detach(struct comedi_device *dev) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; - if (dev_private) { + if (devpriv) { if (dev->mmio) me_reset(dev); - if (dev_private->plx_regbase) - iounmap(dev_private->plx_regbase); + if (devpriv->plx_regbase) + iounmap(devpriv->plx_regbase); } comedi_pci_detach(dev); } diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c index a675e2ef9..fbdf181d8 100644 --- a/drivers/staging/comedi/drivers/mf6x4.c +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -31,36 +31,24 @@ #include "../comedi_pci.h" /* Registers present in BAR0 memory region */ -#define MF624_GPIOC_R 0x54 +#define MF624_GPIOC_REG 0x54 -#define MF6X4_GPIOC_EOLC /* End Of Last Conversion */ (1 << 17) -#define MF6X4_GPIOC_LDAC /* Load DACs */ (1 << 23) -#define MF6X4_GPIOC_DACEN (1 << 26) +#define MF6X4_GPIOC_EOLC BIT(17) /* End Of Last Conversion */ +#define MF6X4_GPIOC_LDAC BIT(23) /* Load DACs */ +#define MF6X4_GPIOC_DACEN BIT(26) /* BAR1 registers */ -#define MF6X4_DIN_R 0x10 -#define MF6X4_DIN_M 0xff -#define MF6X4_DOUT_R 0x10 -#define MF6X4_DOUT_M 0xff - -#define MF6X4_ADSTART_R 0x20 -#define MF6X4_ADDATA_R 0x00 -#define MF6X4_ADCTRL_R 0x00 -#define MF6X4_ADCTRL_M 0xff - -#define MF6X4_DA0_R 0x20 -#define MF6X4_DA1_R 0x22 -#define MF6X4_DA2_R 0x24 -#define MF6X4_DA3_R 0x26 -#define MF6X4_DA4_R 0x28 -#define MF6X4_DA5_R 0x2a -#define MF6X4_DA6_R 0x2c -#define MF6X4_DA7_R 0x2e -/* Map DAC cahnnel id to real HW-dependent offset value */ -#define MF6X4_DAC_R(x) (0x20 + ((x) * 2)) +#define MF6X4_ADDATA_REG 0x00 +#define MF6X4_ADCTRL_REG 0x00 +#define MF6X4_ADCTRL_CHAN(x) BIT(chan) +#define MF6X4_DIN_REG 0x10 +#define MF6X4_DIN_MASK 0xff +#define MF6X4_DOUT_REG 0x10 +#define MF6X4_ADSTART_REG 0x20 +#define MF6X4_DAC_REG(x) (0x20 + ((x) * 2)) /* BAR2 registers */ -#define MF634_GPIOC_R 0x68 +#define MF634_GPIOC_REG 0x68 enum mf6x4_boardid { BOARD_MF634, @@ -69,8 +57,8 @@ enum mf6x4_boardid { struct mf6x4_board { const char *name; - unsigned int bar_nums[3]; /* We need to keep track of the - order of BARs used by the cards */ + /* We need to keep track of the order of BARs used by the cards */ + unsigned int bar_nums[3]; }; static const struct mf6x4_board mf6x4_boards[] = { @@ -99,7 +87,7 @@ struct mf6x4_private { * for both cards however it lies in different BARs on different * offsets -- this variable makes the access easier */ - void __iomem *gpioc_R; + void __iomem *gpioc_reg; }; static int mf6x4_di_insn_bits(struct comedi_device *dev, @@ -107,7 +95,7 @@ static int mf6x4_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - data[1] = ioread16(dev->mmio + MF6X4_DIN_R) & MF6X4_DIN_M; + data[1] = ioread16(dev->mmio + MF6X4_DIN_REG) & MF6X4_DIN_MASK; return insn->n; } @@ -118,7 +106,7 @@ static int mf6x4_do_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - iowrite16(s->state & MF6X4_DOUT_M, dev->mmio + MF6X4_DOUT_R); + iowrite16(s->state, dev->mmio + MF6X4_DOUT_REG); data[1] = s->state; @@ -133,7 +121,7 @@ static int mf6x4_ai_eoc(struct comedi_device *dev, struct mf6x4_private *devpriv = dev->private; unsigned int status; - status = ioread32(devpriv->gpioc_R); + status = ioread32(devpriv->gpioc_reg); if (status & MF6X4_GPIOC_EOLC) return 0; return -EBUSY; @@ -144,29 +132,30 @@ static int mf6x4_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int d; int ret; int i; - int d; /* Set the ADC channel number in the scan list */ - iowrite16((1 << chan) & MF6X4_ADCTRL_M, dev->mmio + MF6X4_ADCTRL_R); + iowrite16(MF6X4_ADCTRL_CHAN(chan), dev->mmio + MF6X4_ADCTRL_REG); for (i = 0; i < insn->n; i++) { /* Trigger ADC conversion by reading ADSTART */ - ioread16(dev->mmio + MF6X4_ADSTART_R); + ioread16(dev->mmio + MF6X4_ADSTART_REG); ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0); if (ret) return ret; /* Read the actual value */ - d = ioread16(dev->mmio + MF6X4_ADDATA_R); + d = ioread16(dev->mmio + MF6X4_ADDATA_REG); d &= s->maxdata; - data[i] = d; + /* munge the 2's complement data to offset binary */ + data[i] = comedi_offset_munge(s, d); } - iowrite16(0x0, dev->mmio + MF6X4_ADCTRL_R); + iowrite16(0x0, dev->mmio + MF6X4_ADCTRL_REG); return insn->n; } @@ -179,17 +168,17 @@ static int mf6x4_ao_insn_write(struct comedi_device *dev, struct mf6x4_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int val = s->readback[chan]; - uint32_t gpioc; + unsigned int gpioc; int i; /* Enable instantaneous update of converters outputs + Enable DACs */ - gpioc = ioread32(devpriv->gpioc_R); + gpioc = ioread32(devpriv->gpioc_reg); iowrite32((gpioc & ~MF6X4_GPIOC_LDAC) | MF6X4_GPIOC_DACEN, - devpriv->gpioc_R); + devpriv->gpioc_reg); for (i = 0; i < insn->n; i++) { val = data[i]; - iowrite16(val, dev->mmio + MF6X4_DAC_R(chan)); + iowrite16(val, dev->mmio + MF6X4_DAC_REG(chan)); } s->readback[chan] = val; @@ -233,53 +222,53 @@ static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context) return -ENODEV; if (board == &mf6x4_boards[BOARD_MF634]) - devpriv->gpioc_R = devpriv->bar2_mem + MF634_GPIOC_R; + devpriv->gpioc_reg = devpriv->bar2_mem + MF634_GPIOC_REG; else - devpriv->gpioc_R = devpriv->bar0_mem + MF624_GPIOC_R; + devpriv->gpioc_reg = devpriv->bar0_mem + MF624_GPIOC_REG; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - /* ADC */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - s->maxdata = 0x3fff; /* 14 bits ADC */ - s->range_table = &range_bipolar10; - s->insn_read = mf6x4_ai_insn_read; - - /* DAC */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = 0x3fff; + s->range_table = &range_bipolar10; + s->insn_read = mf6x4_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 0x3fff; /* 14 bits DAC */ - s->range_table = &range_bipolar10; - s->insn_write = mf6x4_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 0x3fff; + s->range_table = &range_bipolar10; + s->insn_write = mf6x4_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) return ret; - /* DIN */ + /* Digital Input subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = mf6x4_di_insn_bits; - - /* DOUT */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = mf6x4_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = mf6x4_do_insn_bits; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = mf6x4_do_insn_bits; return 0; } diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index 0207b8edf..826e4399c 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -1,55 +1,56 @@ /* - comedi/drivers/mpc624.c - Hardware driver for a Micro/sys inc. MPC-624 PC/104 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - 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. -*/ + * mpc624.c + * Hardware driver for a Micro/sys inc. MPC-624 PC/104 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * 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: mpc624 -Description: Micro/sys MPC-624 PC/104 board -Devices: [Micro/sys] MPC-624 (mpc624) -Author: Stanislaw Raczynski -Updated: Thu, 15 Sep 2005 12:01:18 +0200 -Status: working - - The Micro/sys MPC-624 board is based on the LTC2440 24-bit sigma-delta - ADC chip. - - Subdevices supported by the driver: - - Analog In: supported - - Digital I/O: not supported - - LEDs: not supported - - EEPROM: not supported - -Configuration Options: - [0] - I/O base address - [1] - conversion rate - Conversion rate RMS noise Effective Number Of Bits - 0 3.52kHz 23uV 17 - 1 1.76kHz 3.5uV 20 - 2 880Hz 2uV 21.3 - 3 440Hz 1.4uV 21.8 - 4 220Hz 1uV 22.4 - 5 110Hz 750uV 22.9 - 6 55Hz 510nV 23.4 - 7 27.5Hz 375nV 24 - 8 13.75Hz 250nV 24.4 - 9 6.875Hz 200nV 24.6 - [2] - voltage range - 0 -1.01V .. +1.01V - 1 -10.1V .. +10.1V -*/ + * Driver: mpc624 + * Description: Micro/sys MPC-624 PC/104 board + * Devices: [Micro/sys] MPC-624 (mpc624) + * Author: Stanislaw Raczynski + * Updated: Thu, 15 Sep 2005 12:01:18 +0200 + * Status: working + * + * The Micro/sys MPC-624 board is based on the LTC2440 24-bit sigma-delta + * ADC chip. + * + * Subdevices supported by the driver: + * - Analog In: supported + * - Digital I/O: not supported + * - LEDs: not supported + * - EEPROM: not supported + * + * Configuration Options: + * [0] - I/O base address + * [1] - conversion rate + * Conversion rate RMS noise Effective Number Of Bits + * 0 3.52kHz 23uV 17 + * 1 1.76kHz 3.5uV 20 + * 2 880Hz 2uV 21.3 + * 3 440Hz 1.4uV 21.8 + * 4 220Hz 1uV 22.4 + * 5 110Hz 750uV 22.9 + * 6 55Hz 510nV 23.4 + * 7 27.5Hz 375nV 24 + * 8 13.75Hz 250nV 24.4 + * 9 6.875Hz 200nV 24.6 + * [2] - voltage range + * 0 -1.01V .. +1.01V + * 1 -10.1V .. +10.1V + */ #include #include "../comedidev.h" @@ -58,65 +59,41 @@ Configuration Options: /* Offsets of different ports */ #define MPC624_MASTER_CONTROL 0 /* not used */ -#define MPC624_GNMUXCH 1 /* Gain, Mux, Channel of ADC */ -#define MPC624_ADC 2 /* read/write to/from ADC */ -#define MPC624_EE 3 /* read/write to/from serial EEPROM via I2C */ -#define MPC624_LEDS 4 /* write to LEDs */ -#define MPC624_DIO 5 /* read/write to/from digital I/O ports */ -#define MPC624_IRQ_MASK 6 /* IRQ masking enable/disable */ +#define MPC624_GNMUXCH 1 /* Gain, Mux, Channel of ADC */ +#define MPC624_ADC 2 /* read/write to/from ADC */ +#define MPC624_EE 3 /* read/write to/from serial EEPROM via I2C */ +#define MPC624_LEDS 4 /* write to LEDs */ +#define MPC624_DIO 5 /* read/write to/from digital I/O ports */ +#define MPC624_IRQ_MASK 6 /* IRQ masking enable/disable */ /* Register bits' names */ -#define MPC624_ADBUSY (1<<5) -#define MPC624_ADSDO (1<<4) -#define MPC624_ADFO (1<<3) -#define MPC624_ADCS (1<<2) -#define MPC624_ADSCK (1<<1) -#define MPC624_ADSDI (1<<0) - -/* SDI Speed/Resolution Programming bits */ -#define MPC624_OSR4 (1<<31) -#define MPC624_OSR3 (1<<30) -#define MPC624_OSR2 (1<<29) -#define MPC624_OSR1 (1<<28) -#define MPC624_OSR0 (1<<27) +#define MPC624_ADBUSY BIT(5) +#define MPC624_ADSDO BIT(4) +#define MPC624_ADFO BIT(3) +#define MPC624_ADCS BIT(2) +#define MPC624_ADSCK BIT(1) +#define MPC624_ADSDI BIT(0) /* 32-bit output value bits' names */ -#define MPC624_EOC_BIT (1<<31) -#define MPC624_DMY_BIT (1<<30) -#define MPC624_SGN_BIT (1<<29) - -/* Conversion speeds */ -/* OSR4 OSR3 OSR2 OSR1 OSR0 Conversion rate RMS noise ENOB^ - * X 0 0 0 1 3.52kHz 23uV 17 - * X 0 0 1 0 1.76kHz 3.5uV 20 - * X 0 0 1 1 880Hz 2uV 21.3 - * X 0 1 0 0 440Hz 1.4uV 21.8 - * X 0 1 0 1 220Hz 1uV 22.4 - * X 0 1 1 0 110Hz 750uV 22.9 - * X 0 1 1 1 55Hz 510nV 23.4 - * X 1 0 0 0 27.5Hz 375nV 24 - * X 1 0 0 1 13.75Hz 250nV 24.4 - * X 1 1 1 1 6.875Hz 200nV 24.6 - * - * ^ - Effective Number Of Bits - */ +#define MPC624_EOC_BIT BIT(31) +#define MPC624_DMY_BIT BIT(30) +#define MPC624_SGN_BIT BIT(29) + +/* SDI Speed/Resolution Programming bits */ +#define MPC624_OSR(x) (((x) & 0x1f) << 27) +#define MPC624_SPEED_3_52_KHZ MPC624_OSR(0x11) +#define MPC624_SPEED_1_76_KHZ MPC624_OSR(0x12) +#define MPC624_SPEED_880_HZ MPC624_OSR(0x13) +#define MPC624_SPEED_440_HZ MPC624_OSR(0x14) +#define MPC624_SPEED_220_HZ MPC624_OSR(0x15) +#define MPC624_SPEED_110_HZ MPC624_OSR(0x16) +#define MPC624_SPEED_55_HZ MPC624_OSR(0x17) +#define MPC624_SPEED_27_5_HZ MPC624_OSR(0x18) +#define MPC624_SPEED_13_75_HZ MPC624_OSR(0x19) +#define MPC624_SPEED_6_875_HZ MPC624_OSR(0x1f) -#define MPC624_SPEED_3_52_kHz (MPC624_OSR4 | MPC624_OSR0) -#define MPC624_SPEED_1_76_kHz (MPC624_OSR4 | MPC624_OSR1) -#define MPC624_SPEED_880_Hz (MPC624_OSR4 | MPC624_OSR1 | MPC624_OSR0) -#define MPC624_SPEED_440_Hz (MPC624_OSR4 | MPC624_OSR2) -#define MPC624_SPEED_220_Hz (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR0) -#define MPC624_SPEED_110_Hz (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR1) -#define MPC624_SPEED_55_Hz \ - (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR1 | MPC624_OSR0) -#define MPC624_SPEED_27_5_Hz (MPC624_OSR4 | MPC624_OSR3) -#define MPC624_SPEED_13_75_Hz (MPC624_OSR4 | MPC624_OSR3 | MPC624_OSR0) -#define MPC624_SPEED_6_875_Hz \ - (MPC624_OSR4 | MPC624_OSR3 | MPC624_OSR2 | MPC624_OSR1 | MPC624_OSR0) -/* -------------------------------------------------------------------------- */ struct mpc624_private { - /* set by mpc624_attach() from driver's parameters */ - unsigned long int ulConvertionRate; + unsigned int ai_speed; }; /* -------------------------------------------------------------------------- */ @@ -138,6 +115,85 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { } }; +static unsigned int mpc624_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct mpc624_private *devpriv = dev->private; + unsigned int data_out = devpriv->ai_speed; + unsigned int data_in = 0; + unsigned int bit; + int i; + + /* Start reading data */ + udelay(1); + for (i = 0; i < 32; i++) { + /* Set the clock low */ + outb(0, dev->iobase + MPC624_ADC); + udelay(1); + + /* Set the ADSDI line for the next bit (send to MPC624) */ + bit = (data_out & BIT(31)) ? MPC624_ADSDI : 0; + outb(bit, dev->iobase + MPC624_ADC); + udelay(1); + + /* Set the clock high */ + outb(MPC624_ADSCK | bit, dev->iobase + MPC624_ADC); + udelay(1); + + /* Read ADSDO on high clock (receive from MPC624) */ + data_in <<= 1; + data_in |= (inb(dev->iobase + MPC624_ADC) & MPC624_ADSDO) >> 4; + udelay(1); + + data_out <<= 1; + } + + /* + * Received 32-bit long value consist of: + * 31: EOC - (End Of Transmission) bit - should be 0 + * 30: DMY - (Dummy) bit - should be 0 + * 29: SIG - (Sign) bit - 1 if positive, 0 if negative + * 28: MSB - (Most Significant Bit) - the first bit of the + * conversion result + * .... + * 05: LSB - (Least Significant Bit)- the last bit of the + * conversion result + * 04-00: sub-LSB - sub-LSBs are basically noise, but when + * averaged properly, they can increase + * conversion precision up to 29 bits; + * they can be discarded without loss of + * resolution. + */ + if (data_in & MPC624_EOC_BIT) + dev_dbg(dev->class_dev, "EOC bit is set!"); + if (data_in & MPC624_DMY_BIT) + dev_dbg(dev->class_dev, "DMY bit is set!"); + + if (data_in & MPC624_SGN_BIT) { + /* + * Voltage is positive + * + * comedi operates on unsigned numbers, so mask off EOC + * and DMY and don't clear the SGN bit + */ + data_in &= 0x3fffffff; + } else { + /* + * The voltage is negative + * + * data_in contains a number in 30-bit two's complement + * code and we must deal with it + */ + data_in |= MPC624_SGN_BIT; + data_in = ~data_in; + data_in += 1; + /* clear EOC and DMY bits */ + data_in &= ~(MPC624_EOC_BIT | MPC624_DMY_BIT); + data_in = 0x20000000 - data_in; + } + return data_in; +} + static int mpc624_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -151,14 +207,13 @@ static int mpc624_ai_eoc(struct comedi_device *dev, return -EBUSY; } -static int mpc624_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int mpc624_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct mpc624_private *devpriv = dev->private; - int n, i; - unsigned long int data_in, data_out; int ret; + int i; /* * WARNING: @@ -166,7 +221,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, */ outb(insn->chanspec, dev->iobase + MPC624_GNMUXCH); - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { /* Trigger the conversion */ outb(MPC624_ADSCK, dev->iobase + MPC624_ADC); udelay(1); @@ -180,93 +235,10 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, if (ret) return ret; - /* Start reading data */ - data_in = 0; - data_out = devpriv->ulConvertionRate; - udelay(1); - for (i = 0; i < 32; i++) { - /* Set the clock low */ - outb(0, dev->iobase + MPC624_ADC); - udelay(1); - - if (data_out & (1 << 31)) { /* the next bit is a 1 */ - /* Set the ADSDI line (send to MPC624) */ - outb(MPC624_ADSDI, dev->iobase + MPC624_ADC); - udelay(1); - /* Set the clock high */ - outb(MPC624_ADSCK | MPC624_ADSDI, - dev->iobase + MPC624_ADC); - } else { /* the next bit is a 0 */ - - /* Set the ADSDI line (send to MPC624) */ - outb(0, dev->iobase + MPC624_ADC); - udelay(1); - /* Set the clock high */ - outb(MPC624_ADSCK, dev->iobase + MPC624_ADC); - } - /* Read ADSDO on high clock (receive from MPC624) */ - udelay(1); - data_in <<= 1; - data_in |= - (inb(dev->iobase + MPC624_ADC) & MPC624_ADSDO) >> 4; - udelay(1); - - data_out <<= 1; - } - - /* - * Received 32-bit long value consist of: - * 31: EOC - - * (End Of Transmission) bit - should be 0 - * 30: DMY - * (Dummy) bit - should be 0 - * 29: SIG - * (Sign) bit- 1 if the voltage is positive, - * 0 if negative - * 28: MSB - * (Most Significant Bit) - the first bit of - * the conversion result - * .... - * 05: LSB - * (Least Significant Bit)- the last bit of the - * conversion result - * 04-00: sub-LSB - * - sub-LSBs are basically noise, but when - * averaged properly, they can increase conversion - * precision up to 29 bits; they can be discarded - * without loss of resolution. - */ - - if (data_in & MPC624_EOC_BIT) - dev_dbg(dev->class_dev, - "EOC bit is set (data_in=%lu)!", data_in); - if (data_in & MPC624_DMY_BIT) - dev_dbg(dev->class_dev, - "DMY bit is set (data_in=%lu)!", data_in); - if (data_in & MPC624_SGN_BIT) { /* Volatge is positive */ - /* - * comedi operates on unsigned numbers, so mask off EOC - * and DMY and don't clear the SGN bit - */ - data_in &= 0x3FFFFFFF; - data[n] = data_in; - } else { /* The voltage is negative */ - /* - * data_in contains a number in 30-bit two's complement - * code and we must deal with it - */ - data_in |= MPC624_SGN_BIT; - data_in = ~data_in; - data_in += 1; - data_in &= ~(MPC624_EOC_BIT | MPC624_DMY_BIT); - /* clear EOC and DMY bits */ - data_in = 0x20000000 - data_in; - data[n] = data_in; - } + data[i] = mpc624_ai_get_sample(dev, s); } - /* Return the number of samples read/written */ - return n; + return insn->n; } static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -285,61 +257,52 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) switch (it->options[1]) { case 0: - devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; + devpriv->ai_speed = MPC624_SPEED_3_52_KHZ; break; case 1: - devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz; + devpriv->ai_speed = MPC624_SPEED_1_76_KHZ; break; case 2: - devpriv->ulConvertionRate = MPC624_SPEED_880_Hz; + devpriv->ai_speed = MPC624_SPEED_880_HZ; break; case 3: - devpriv->ulConvertionRate = MPC624_SPEED_440_Hz; + devpriv->ai_speed = MPC624_SPEED_440_HZ; break; case 4: - devpriv->ulConvertionRate = MPC624_SPEED_220_Hz; + devpriv->ai_speed = MPC624_SPEED_220_HZ; break; case 5: - devpriv->ulConvertionRate = MPC624_SPEED_110_Hz; + devpriv->ai_speed = MPC624_SPEED_110_HZ; break; case 6: - devpriv->ulConvertionRate = MPC624_SPEED_55_Hz; + devpriv->ai_speed = MPC624_SPEED_55_HZ; break; case 7: - devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz; + devpriv->ai_speed = MPC624_SPEED_27_5_HZ; break; case 8: - devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz; + devpriv->ai_speed = MPC624_SPEED_13_75_HZ; break; case 9: - devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz; + devpriv->ai_speed = MPC624_SPEED_6_875_HZ; break; default: - devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; + devpriv->ai_speed = MPC624_SPEED_3_52_KHZ; } ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF; - s->n_chan = 8; - switch (it->options[1]) { - default: - s->maxdata = 0x3FFFFFFF; - } - - switch (it->options[1]) { - case 0: - s->range_table = &range_mpc624_bipolar1; - break; - default: - s->range_table = &range_mpc624_bipolar10; - } - s->len_chanlist = 1; - s->insn_read = mpc624_ai_rinsn; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = 4; + s->maxdata = 0x3fffffff; + s->range_table = (it->options[1] == 0) ? &range_mpc624_bipolar1 + : &range_mpc624_bipolar10; + s->insn_read = mpc624_ai_insn_read; return 0; } @@ -353,5 +316,5 @@ static struct comedi_driver mpc624_driver = { module_comedi_driver(mpc624_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Micro/sys MPC-624 PC/104 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 847121921..b5a26f7b4 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -1,79 +1,91 @@ /* - comedi/drivers/multiq3.c - Hardware driver for Quanser Consulting MultiQ-3 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Anders Blomdell - - 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. + * multiq3.c + * Hardware driver for Quanser Consulting MultiQ-3 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Anders Blomdell + * + * 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: multiq3 -Description: Quanser Consulting MultiQ-3 -Author: Anders Blomdell -Status: works -Devices: [Quanser Consulting] MultiQ-3 (multiq3) - -*/ - -#include -#include -#include "../comedidev.h" /* - * MULTIQ-3 port offsets + * Driver: multiq3 + * Description: Quanser Consulting MultiQ-3 + * Devices: [Quanser Consulting] MultiQ-3 (multiq3) + * Author: Anders Blomdell + * Status: works + * + * Configuration Options: + * [0] - I/O port base address + * [1] - IRQ (not used) + * [2] - Number of optional encoder chips installed on board + * 0 = none + * 1 = 2 inputs (Model -2E) + * 2 = 4 inputs (Model -4E) + * 3 = 6 inputs (Model -6E) + * 4 = 8 inputs (Model -8E) */ -#define MULTIQ3_DIGIN_PORT 0 -#define MULTIQ3_DIGOUT_PORT 0 -#define MULTIQ3_DAC_DATA 2 -#define MULTIQ3_AD_DATA 4 -#define MULTIQ3_AD_CS 4 -#define MULTIQ3_STATUS 6 -#define MULTIQ3_CONTROL 6 -#define MULTIQ3_CLK_DATA 8 -#define MULTIQ3_ENC_DATA 12 -#define MULTIQ3_ENC_CONTROL 14 -/* - * flags for CONTROL register - */ -#define MULTIQ3_AD_MUX_EN 0x0040 -#define MULTIQ3_AD_AUTOZ 0x0080 -#define MULTIQ3_AD_AUTOCAL 0x0100 -#define MULTIQ3_AD_SH 0x0200 -#define MULTIQ3_AD_CLOCK_4M 0x0400 -#define MULTIQ3_DA_LOAD 0x1800 +#include -#define MULTIQ3_CONTROL_MUST 0x0600 +#include "../comedidev.h" /* - * flags for STATUS register + * Register map */ -#define MULTIQ3_STATUS_EOC 0x008 -#define MULTIQ3_STATUS_EOC_I 0x010 +#define MULTIQ3_DI_REG 0x00 +#define MULTIQ3_DO_REG 0x00 +#define MULTIQ3_AO_REG 0x02 +#define MULTIQ3_AI_REG 0x04 +#define MULTIQ3_AI_CONV_REG 0x04 +#define MULTIQ3_STATUS_REG 0x06 +#define MULTIQ3_STATUS_EOC BIT(3) +#define MULTIQ3_STATUS_EOC_I BIT(4) +#define MULTIQ3_CTRL_REG 0x06 +#define MULTIQ3_CTRL_AO_CHAN(x) (((x) & 0x7) << 0) +#define MULTIQ3_CTRL_RC(x) (((x) & 0x3) << 0) +#define MULTIQ3_CTRL_AI_CHAN(x) (((x) & 0x7) << 3) +#define MULTIQ3_CTRL_E_CHAN(x) (((x) & 0x7) << 3) +#define MULTIQ3_CTRL_EN BIT(6) +#define MULTIQ3_CTRL_AZ BIT(7) +#define MULTIQ3_CTRL_CAL BIT(8) +#define MULTIQ3_CTRL_SH BIT(9) +#define MULTIQ3_CTRL_CLK BIT(10) +#define MULTIQ3_CTRL_LD (3 << 11) +#define MULTIQ3_CLK_REG 0x08 +#define MULTIQ3_ENC_DATA_REG 0x0c +#define MULTIQ3_ENC_CTRL_REG 0x0e /* - * flags for encoder control + * Encoder chip commands (from the programming manual) */ -#define MULTIQ3_CLOCK_DATA 0x00 -#define MULTIQ3_CLOCK_SETUP 0x18 -#define MULTIQ3_INPUT_SETUP 0x41 -#define MULTIQ3_QUAD_X4 0x38 -#define MULTIQ3_BP_RESET 0x01 -#define MULTIQ3_CNTR_RESET 0x02 -#define MULTIQ3_TRSFRPR_CTR 0x08 -#define MULTIQ3_TRSFRCNTR_OL 0x10 -#define MULTIQ3_EFLAG_RESET 0x06 - -#define MULTIQ3_TIMEOUT 30 +#define MULTIQ3_CLOCK_DATA 0x00 /* FCK frequency divider */ +#define MULTIQ3_CLOCK_SETUP 0x18 /* xfer PR0 to PSC */ +#define MULTIQ3_INPUT_SETUP 0x41 /* enable inputs A and B */ +#define MULTIQ3_QUAD_X4 0x38 /* quadrature */ +#define MULTIQ3_BP_RESET 0x01 /* reset byte pointer */ +#define MULTIQ3_CNTR_RESET 0x02 /* reset counter */ +#define MULTIQ3_TRSFRPR_CTR 0x08 /* xfre preset reg to counter */ +#define MULTIQ3_TRSFRCNTR_OL 0x10 /* xfer CNTR to OL (x and y) */ +#define MULTIQ3_EFLAG_RESET 0x06 /* reset E bit of flag reg */ + +static void multiq3_set_ctrl(struct comedi_device *dev, unsigned int bits) +{ + /* + * According to the programming manual, the SH and CLK bits should + * be kept high at all times. + */ + outw(MULTIQ3_CTRL_SH | MULTIQ3_CTRL_CLK | bits, + dev->iobase + MULTIQ3_CTRL_REG); +} static int multiq3_ai_status(struct comedi_device *dev, struct comedi_subdevice *s, @@ -82,7 +94,7 @@ static int multiq3_ai_status(struct comedi_device *dev, { unsigned int status; - status = inw(dev->iobase + MULTIQ3_STATUS); + status = inw(dev->iobase + MULTIQ3_STATUS_REG); if (status & context) return 0; return -EBUSY; @@ -90,36 +102,39 @@ static int multiq3_ai_status(struct comedi_device *dev, static int multiq3_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int n; - int chan; - unsigned int hi, lo; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; int ret; + int i; - chan = CR_CHAN(insn->chanspec); - outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3), - dev->iobase + MULTIQ3_CONTROL); + multiq3_set_ctrl(dev, MULTIQ3_CTRL_EN | MULTIQ3_CTRL_AI_CHAN(chan)); ret = comedi_timeout(dev, s, insn, multiq3_ai_status, MULTIQ3_STATUS_EOC); if (ret) return ret; - for (n = 0; n < insn->n; n++) { - outw(0, dev->iobase + MULTIQ3_AD_CS); + for (i = 0; i < insn->n; i++) { + outw(0, dev->iobase + MULTIQ3_AI_CONV_REG); ret = comedi_timeout(dev, s, insn, multiq3_ai_status, MULTIQ3_STATUS_EOC_I); if (ret) return ret; - hi = inb(dev->iobase + MULTIQ3_AD_CS); - lo = inb(dev->iobase + MULTIQ3_AD_CS); - data[n] = (((hi << 8) | lo) + 0x1000) & 0x1fff; + /* get a 16-bit sample; mask it to the subdevice resolution */ + val = inb(dev->iobase + MULTIQ3_AI_REG) << 8; + val |= inb(dev->iobase + MULTIQ3_AI_REG); + val &= s->maxdata; + + /* munge the 2's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); } - return n; + return insn->n; } static int multiq3_ao_insn_write(struct comedi_device *dev, @@ -133,10 +148,10 @@ static int multiq3_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - outw(MULTIQ3_CONTROL_MUST | MULTIQ3_DA_LOAD | chan, - dev->iobase + MULTIQ3_CONTROL); - outw(val, dev->iobase + MULTIQ3_DAC_DATA); - outw(MULTIQ3_CONTROL_MUST, dev->iobase + MULTIQ3_CONTROL); + multiq3_set_ctrl(dev, MULTIQ3_CTRL_LD | + MULTIQ3_CTRL_AO_CHAN(chan)); + outw(val, dev->iobase + MULTIQ3_AO_REG); + multiq3_set_ctrl(dev, 0); } s->readback[chan] = val; @@ -147,7 +162,7 @@ static int multiq3_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - data[1] = inw(dev->iobase + MULTIQ3_DIGIN_PORT); + data[1] = inw(dev->iobase + MULTIQ3_DI_REG); return insn->n; } @@ -158,7 +173,7 @@ static int multiq3_do_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT); + outw(s->state, dev->iobase + MULTIQ3_DO_REG); data[1] = s->state; @@ -170,41 +185,76 @@ static int multiq3_encoder_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); - int control = MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3); - int value; - int n; - - for (n = 0; n < insn->n; n++) { - outw(control, dev->iobase + MULTIQ3_CONTROL); - outb(MULTIQ3_BP_RESET, dev->iobase + MULTIQ3_ENC_CONTROL); - outb(MULTIQ3_TRSFRCNTR_OL, dev->iobase + MULTIQ3_ENC_CONTROL); - value = inb(dev->iobase + MULTIQ3_ENC_DATA); - value |= (inb(dev->iobase + MULTIQ3_ENC_DATA) << 8); - value |= (inb(dev->iobase + MULTIQ3_ENC_DATA) << 16); - data[n] = (value + 0x800000) & 0xffffff; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + /* select encoder channel */ + multiq3_set_ctrl(dev, MULTIQ3_CTRL_EN | + MULTIQ3_CTRL_E_CHAN(chan)); + + /* reset the byte pointer */ + outb(MULTIQ3_BP_RESET, dev->iobase + MULTIQ3_ENC_CTRL_REG); + + /* latch the data */ + outb(MULTIQ3_TRSFRCNTR_OL, dev->iobase + MULTIQ3_ENC_CTRL_REG); + + /* read the 24-bit encoder data (lsb/mid/msb) */ + val = inb(dev->iobase + MULTIQ3_ENC_DATA_REG); + val |= (inb(dev->iobase + MULTIQ3_ENC_DATA_REG) << 8); + val |= (inb(dev->iobase + MULTIQ3_ENC_DATA_REG) << 16); + + /* + * Munge the data so that the reset value is in the middle + * of the maxdata range, i.e.: + * + * real value comedi value + * 0xffffff 0x7fffff 1 negative count + * 0x000000 0x800000 reset value + * 0x000001 0x800001 1 positive count + * + * It's possible for the 24-bit counter to overflow but it + * would normally take _quite_ a few turns. A 2000 line + * encoder in quadrature results in 8000 counts/rev. So about + * 1048 turns in either direction can be measured without + * an overflow. + */ + data[i] = (val + ((s->maxdata + 1) >> 1)) & s->maxdata; } - return n; + return insn->n; } -static void encoder_reset(struct comedi_device *dev) +static void multiq3_encoder_reset(struct comedi_device *dev, + unsigned int chan) { - struct comedi_subdevice *s = &dev->subdevices[4]; - int chan; - - for (chan = 0; chan < s->n_chan; chan++) { - int control = - MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3); - outw(control, dev->iobase + MULTIQ3_CONTROL); - outb(MULTIQ3_EFLAG_RESET, dev->iobase + MULTIQ3_ENC_CONTROL); - outb(MULTIQ3_BP_RESET, dev->iobase + MULTIQ3_ENC_CONTROL); - outb(MULTIQ3_CLOCK_DATA, dev->iobase + MULTIQ3_ENC_DATA); - outb(MULTIQ3_CLOCK_SETUP, dev->iobase + MULTIQ3_ENC_CONTROL); - outb(MULTIQ3_INPUT_SETUP, dev->iobase + MULTIQ3_ENC_CONTROL); - outb(MULTIQ3_QUAD_X4, dev->iobase + MULTIQ3_ENC_CONTROL); - outb(MULTIQ3_CNTR_RESET, dev->iobase + MULTIQ3_ENC_CONTROL); + multiq3_set_ctrl(dev, MULTIQ3_CTRL_EN | MULTIQ3_CTRL_E_CHAN(chan)); + outb(MULTIQ3_EFLAG_RESET, dev->iobase + MULTIQ3_ENC_CTRL_REG); + outb(MULTIQ3_BP_RESET, dev->iobase + MULTIQ3_ENC_CTRL_REG); + outb(MULTIQ3_CLOCK_DATA, dev->iobase + MULTIQ3_ENC_DATA_REG); + outb(MULTIQ3_CLOCK_SETUP, dev->iobase + MULTIQ3_ENC_CTRL_REG); + outb(MULTIQ3_INPUT_SETUP, dev->iobase + MULTIQ3_ENC_CTRL_REG); + outb(MULTIQ3_QUAD_X4, dev->iobase + MULTIQ3_ENC_CTRL_REG); + outb(MULTIQ3_CNTR_RESET, dev->iobase + MULTIQ3_ENC_CTRL_REG); +} + +static int multiq3_encoder_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + + switch (data[0]) { + case INSN_CONFIG_RESET: + multiq3_encoder_reset(dev, chan); + break; + default: + return -EINVAL; } + + return insn->n; } static int multiq3_attach(struct comedi_device *dev, @@ -212,6 +262,7 @@ static int multiq3_attach(struct comedi_device *dev, { struct comedi_subdevice *s; int ret; + int i; ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) @@ -221,57 +272,58 @@ static int multiq3_attach(struct comedi_device *dev, if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* ai subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - s->insn_read = multiq3_ai_insn_read; - s->maxdata = 0x1fff; - s->range_table = &range_bipolar5; - + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = 0x1fff; + s->range_table = &range_bipolar5; + s->insn_read = multiq3_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 0xfff; - s->range_table = &range_bipolar5; - s->insn_write = multiq3_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->range_table = &range_bipolar5; + s->insn_write = multiq3_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) return ret; + /* Digital Input subdevice */ s = &dev->subdevices[2]; - /* di subdevice */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->insn_bits = multiq3_di_insn_bits; - s->maxdata = 1; - s->range_table = &range_digital; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = multiq3_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - /* do subdevice */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->insn_bits = multiq3_do_insn_bits; - s->maxdata = 1; - s->range_table = &range_digital; - s->state = 0; - + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = multiq3_do_insn_bits; + + /* Encoder (Counter) subdevice */ s = &dev->subdevices[4]; - /* encoder (counter) subdevice */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = it->options[2] * 2; - s->insn_read = multiq3_encoder_insn_read; - s->maxdata = 0xffffff; - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = it->options[2] * 2; + s->maxdata = 0x00ffffff; + s->range_table = &range_unknown; + s->insn_read = multiq3_encoder_insn_read; + s->insn_config = multiq3_encoder_insn_config; - encoder_reset(dev); + for (i = 0; i < s->n_chan; i++) + multiq3_encoder_reset(dev, i); return 0; } @@ -285,5 +337,5 @@ static struct comedi_driver multiq3_driver = { module_comedi_driver(multiq3_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Quanser Consulting MultiQ-3 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c index c20c51bef..b74e44ec5 100644 --- a/drivers/staging/comedi/drivers/ni_tio.c +++ b/drivers/staging/comedi/drivers/ni_tio.c @@ -167,15 +167,15 @@ static inline unsigned GI_HW_ARM_SEL_MASK(enum ni_gpct_variant variant) } } -static int ni_tio_has_gate2_registers(const struct ni_gpct_device *counter_dev) +static bool ni_tio_has_gate2_registers(const struct ni_gpct_device *counter_dev) { switch (counter_dev->variant) { case ni_gpct_variant_e_series: default: - return 0; + return false; case ni_gpct_variant_m_series: case ni_gpct_variant_660x: - return 1; + return true; } } diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 9b124b09e..437f723bb 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -157,12 +157,6 @@ static int ni_tio_output_cmd(struct comedi_subdevice *s) dev_err(counter->counter_dev->dev->class_dev, "output commands not yet implemented.\n"); return -ENOTSUPP; - - counter->mite_chan->dir = COMEDI_OUTPUT; - mite_prep_dma(counter->mite_chan, 32, 32); - ni_tio_configure_dma(counter, true, false); - mite_dma_arm(counter->mite_chan); - return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); } static int ni_tio_cmd_setup(struct comedi_subdevice *s) diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c index 88de8da3e..95b537a8e 100644 --- a/drivers/staging/comedi/drivers/ni_usb6501.c +++ b/drivers/staging/comedi/drivers/ni_usb6501.c @@ -166,7 +166,7 @@ enum commands { struct ni6501_private { struct usb_endpoint_descriptor *ep_rx; struct usb_endpoint_descriptor *ep_tx; - struct semaphore sem; + struct mutex mut; u8 *usb_rx_buf; u8 *usb_tx_buf; }; @@ -183,7 +183,7 @@ static int ni6501_port_command(struct comedi_device *dev, int command, if (command != SET_PORT_DIR && !bitmap) return -EINVAL; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); switch (command) { case READ_PORT: @@ -248,7 +248,7 @@ static int ni6501_port_command(struct comedi_device *dev, int command, ret = -EINVAL; } end: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -265,7 +265,7 @@ static int ni6501_counter_command(struct comedi_device *dev, int command, if ((command == READ_COUNTER || command == WRITE_COUNTER) && !val) return -EINVAL; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); switch (command) { case START_COUNTER: @@ -338,7 +338,7 @@ static int ni6501_counter_command(struct comedi_device *dev, int command, ret = -EINVAL; } end: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -535,7 +535,7 @@ static int ni6501_auto_attach(struct comedi_device *dev, if (ret) return ret; - sema_init(&devpriv->sem, 1); + mutex_init(&devpriv->mut); usb_set_intfdata(intf, devpriv); ret = comedi_alloc_subdevices(dev, 2); @@ -573,14 +573,14 @@ static void ni6501_detach(struct comedi_device *dev) if (!devpriv) return; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); usb_set_intfdata(intf, NULL); kfree(devpriv->usb_rx_buf); kfree(devpriv->usb_tx_buf); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); } static struct comedi_driver ni6501_driver = { diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index cfc3a627d..3774daa9d 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -49,7 +49,7 @@ #define PCL711_TIMER_BASE 0x00 #define PCL711_AI_LSB_REG 0x04 #define PCL711_AI_MSB_REG 0x05 -#define PCL711_AI_MSB_DRDY (1 << 4) +#define PCL711_AI_MSB_DRDY BIT(4) #define PCL711_AO_LSB_REG(x) (0x04 + ((x) * 2)) #define PCL711_AO_MSB_REG(x) (0x05 + ((x) * 2)) #define PCL711_DI_LSB_REG 0x06 @@ -60,16 +60,17 @@ #define PCL711_AI_GAIN(x) (((x) & 0xf) << 0) #define PCL711_MUX_REG 0x0a #define PCL711_MUX_CHAN(x) (((x) & 0xf) << 0) -#define PCL711_MUX_CS0 (1 << 4) -#define PCL711_MUX_CS1 (1 << 5) +#define PCL711_MUX_CS0 BIT(4) +#define PCL711_MUX_CS1 BIT(5) #define PCL711_MUX_DIFF (PCL711_MUX_CS0 | PCL711_MUX_CS1) #define PCL711_MODE_REG 0x0b -#define PCL711_MODE_DEFAULT (0 << 0) -#define PCL711_MODE_SOFTTRIG (1 << 0) -#define PCL711_MODE_EXT (2 << 0) -#define PCL711_MODE_EXT_IRQ (3 << 0) -#define PCL711_MODE_PACER (4 << 0) -#define PCL711_MODE_PACER_IRQ (6 << 0) +#define PCL711_MODE(x) (((x) & 0x7) << 0) +#define PCL711_MODE_DEFAULT PCL711_MODE(0) +#define PCL711_MODE_SOFTTRIG PCL711_MODE(1) +#define PCL711_MODE_EXT PCL711_MODE(2) +#define PCL711_MODE_EXT_IRQ PCL711_MODE(3) +#define PCL711_MODE_PACER PCL711_MODE(4) +#define PCL711_MODE_PACER_IRQ PCL711_MODE(6) #define PCL711_MODE_IRQ(x) (((x) & 0x7) << 4) #define PCL711_SOFTTRIG_REG 0x0c #define PCL711_SOFTTRIG (0 << 0) /* any value will work */ diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 48f6cdf44..9c75065dd 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -119,40 +119,30 @@ #include "comedi_isadma.h" #include "comedi_8254.h" -/* hardware types of the cards */ -#define boardPCL812PG 0 /* and ACL-8112PG */ -#define boardPCL813B 1 -#define boardPCL812 2 -#define boardPCL813 3 -#define boardISO813 5 -#define boardACL8113 6 -#define boardACL8112 7 /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */ -#define boardACL8216 8 /* and ICP DAS A-826PG */ -#define boardA821 9 /* PGH, PGL, PGL/NDA versions */ - /* * Register I/O map */ #define PCL812_TIMER_BASE 0x00 #define PCL812_AI_LSB_REG 0x04 #define PCL812_AI_MSB_REG 0x05 -#define PCL812_AI_MSB_DRDY (1 << 4) +#define PCL812_AI_MSB_DRDY BIT(4) #define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2)) #define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2)) #define PCL812_DI_LSB_REG 0x06 #define PCL812_DI_MSB_REG 0x07 #define PCL812_STATUS_REG 0x08 -#define PCL812_STATUS_DRDY (1 << 5) +#define PCL812_STATUS_DRDY BIT(5) #define PCL812_RANGE_REG 0x09 #define PCL812_MUX_REG 0x0a #define PCL812_MUX_CHAN(x) ((x) << 0) -#define PCL812_MUX_CS0 (1 << 4) -#define PCL812_MUX_CS1 (1 << 5) +#define PCL812_MUX_CS0 BIT(4) +#define PCL812_MUX_CS1 BIT(5) #define PCL812_CTRL_REG 0x0b -#define PCL812_CTRL_DISABLE_TRIG (0 << 0) -#define PCL812_CTRL_SOFT_TRIG (1 << 0) -#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0) -#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0) +#define PCL812_CTRL_TRIG(x) (((x) & 0x7) << 0) +#define PCL812_CTRL_DISABLE_TRIG PCL812_CTRL_TRIG(0) +#define PCL812_CTRL_SOFT_TRIG PCL812_CTRL_TRIG(1) +#define PCL812_CTRL_PACER_DMA_TRIG PCL812_CTRL_TRIG(2) +#define PCL812_CTRL_PACER_EOC_TRIG PCL812_CTRL_TRIG(6) #define PCL812_SOFTTRIG_REG 0x0c #define PCL812_DO_LSB_REG 0x0d #define PCL812_DO_MSB_REG 0x0e @@ -327,14 +317,26 @@ static const struct comedi_lrange range_a821pgh_ai = { } }; +enum pcl812_boardtype { + BOARD_PCL812PG = 0, /* and ACL-8112PG */ + BOARD_PCL813B = 1, + BOARD_PCL812 = 2, + BOARD_PCL813 = 3, + BOARD_ISO813 = 5, + BOARD_ACL8113 = 6, + BOARD_ACL8112 = 7, /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */ + BOARD_ACL8216 = 8, /* and ICP DAS A-826PG */ + BOARD_A821 = 9, /* PGH, PGL, PGL/NDA versions */ +}; + struct pcl812_board { const char *name; - int board_type; + enum pcl812_boardtype board_type; int n_aichan; int n_aochan; unsigned int ai_ns_min; const struct comedi_lrange *rangelist_ai; - unsigned int IRQbits; + unsigned int irq_bits; unsigned int has_dma:1; unsigned int has_16bit_ai:1; unsigned int has_mpc508_mux:1; @@ -344,161 +346,161 @@ struct pcl812_board { static const struct pcl812_board boardtypes[] = { { .name = "pcl812", - .board_type = boardPCL812, + .board_type = BOARD_PCL812, .n_aichan = 16, .n_aochan = 2, .ai_ns_min = 33000, .rangelist_ai = &range_bipolar10, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_dio = 1, }, { .name = "pcl812pg", - .board_type = boardPCL812PG, + .board_type = BOARD_PCL812PG, .n_aichan = 16, .n_aochan = 2, .ai_ns_min = 33000, .rangelist_ai = &range_pcl812pg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_dio = 1, }, { .name = "acl8112pg", - .board_type = boardPCL812PG, + .board_type = BOARD_PCL812PG, .n_aichan = 16, .n_aochan = 2, .ai_ns_min = 10000, .rangelist_ai = &range_pcl812pg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_dio = 1, }, { .name = "acl8112dg", - .board_type = boardACL8112, + .board_type = BOARD_ACL8112, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 10000, .rangelist_ai = &range_acl8112dg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_mpc508_mux = 1, .has_dio = 1, }, { .name = "acl8112hg", - .board_type = boardACL8112, + .board_type = BOARD_ACL8112, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 10000, .rangelist_ai = &range_acl8112hg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_mpc508_mux = 1, .has_dio = 1, }, { .name = "a821pgl", - .board_type = boardA821, + .board_type = BOARD_A821, .n_aichan = 16, /* 8 differential */ .n_aochan = 1, .ai_ns_min = 10000, .rangelist_ai = &range_pcl813b_ai, - .IRQbits = 0x000c, + .irq_bits = 0x000c, .has_dio = 1, }, { .name = "a821pglnda", - .board_type = boardA821, + .board_type = BOARD_A821, .n_aichan = 16, /* 8 differential */ .ai_ns_min = 10000, .rangelist_ai = &range_pcl813b_ai, - .IRQbits = 0x000c, + .irq_bits = 0x000c, }, { .name = "a821pgh", - .board_type = boardA821, + .board_type = BOARD_A821, .n_aichan = 16, /* 8 differential */ .n_aochan = 1, .ai_ns_min = 10000, .rangelist_ai = &range_a821pgh_ai, - .IRQbits = 0x000c, + .irq_bits = 0x000c, .has_dio = 1, }, { .name = "a822pgl", - .board_type = boardACL8112, + .board_type = BOARD_ACL8112, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 10000, .rangelist_ai = &range_acl8112dg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_dio = 1, }, { .name = "a822pgh", - .board_type = boardACL8112, + .board_type = BOARD_ACL8112, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 10000, .rangelist_ai = &range_acl8112hg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_dio = 1, }, { .name = "a823pgl", - .board_type = boardACL8112, + .board_type = BOARD_ACL8112, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 8000, .rangelist_ai = &range_acl8112dg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_dio = 1, }, { .name = "a823pgh", - .board_type = boardACL8112, + .board_type = BOARD_ACL8112, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 8000, .rangelist_ai = &range_acl8112hg_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_dio = 1, }, { .name = "pcl813", - .board_type = boardPCL813, + .board_type = BOARD_PCL813, .n_aichan = 32, .rangelist_ai = &range_pcl813b_ai, }, { .name = "pcl813b", - .board_type = boardPCL813B, + .board_type = BOARD_PCL813B, .n_aichan = 32, .rangelist_ai = &range_pcl813b_ai, }, { .name = "acl8113", - .board_type = boardACL8113, + .board_type = BOARD_ACL8113, .n_aichan = 32, .rangelist_ai = &range_acl8113_1_ai, }, { .name = "iso813", - .board_type = boardISO813, + .board_type = BOARD_ISO813, .n_aichan = 32, .rangelist_ai = &range_iso813_1_ai, }, { .name = "acl8216", - .board_type = boardACL8216, + .board_type = BOARD_ACL8216, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 10000, .rangelist_ai = &range_pcl813b2_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_16bit_ai = 1, .has_mpc508_mux = 1, .has_dio = 1, }, { .name = "a826pg", - .board_type = boardACL8216, + .board_type = BOARD_ACL8216, .n_aichan = 16, /* 8 differential */ .n_aochan = 2, .ai_ns_min = 10000, .rangelist_ai = &range_pcl813b2_ai, - .IRQbits = 0xdcfc, + .irq_bits = 0xdcfc, .has_dma = 1, .has_16bit_ai = 1, .has_dio = 1, @@ -1017,16 +1019,14 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev, const struct pcl812_board *board = dev->board_ptr; struct pcl812_private *devpriv = dev->private; - /* default to the range table from the boardinfo */ - s->range_table = board->rangelist_ai; - - /* now check the user config option based on the boardtype */ switch (board->board_type) { - case boardPCL812PG: + case BOARD_PCL812PG: if (it->options[4] == 1) s->range_table = &range_pcl812pg2_ai; + else + s->range_table = board->rangelist_ai; break; - case boardPCL812: + case BOARD_PCL812: switch (it->options[4]) { case 0: s->range_table = &range_bipolar10; @@ -1051,11 +1051,13 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev, break; } break; - case boardPCL813B: + case BOARD_PCL813B: if (it->options[1] == 1) s->range_table = &range_pcl813b2_ai; + else + s->range_table = board->rangelist_ai; break; - case boardISO813: + case BOARD_ISO813: switch (it->options[1]) { case 0: s->range_table = &range_iso813_1_ai; @@ -1076,7 +1078,7 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev, break; } break; - case boardACL8113: + case BOARD_ACL8113: switch (it->options[1]) { case 0: s->range_table = &range_acl8113_1_ai; @@ -1097,6 +1099,9 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev, break; } break; + default: + s->range_table = board->rangelist_ai; + break; } } @@ -1138,14 +1143,14 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - if (board->IRQbits) { + if (board->irq_bits) { dev->pacer = comedi_8254_init(dev->iobase + PCL812_TIMER_BASE, I8254_OSC_BASE_2MHZ, I8254_IO8, 0); if (!dev->pacer) return -ENOMEM; - if ((1 << it->options[1]) & board->IRQbits) { + if ((1 << it->options[1]) & board->irq_bits) { ret = request_irq(it->options[1], pcl812_interrupt, 0, dev->board_name, dev); if (ret == 0) @@ -1159,15 +1164,17 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* differential analog inputs? */ switch (board->board_type) { - case boardA821: + case BOARD_A821: if (it->options[2] == 1) devpriv->use_diff = 1; break; - case boardACL8112: - case boardACL8216: + case BOARD_ACL8112: + case BOARD_ACL8216: if (it->options[4] == 1) devpriv->use_diff = 1; break; + default: + break; } n_subdevices = 1; /* all boardtypes have analog inputs */ @@ -1220,20 +1227,31 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->subdev_flags = SDF_WRITABLE | SDF_GROUND; s->n_chan = board->n_aochan; s->maxdata = 0xfff; - s->range_table = &range_unipolar5; switch (board->board_type) { - case boardA821: + case BOARD_A821: if (it->options[3] == 1) s->range_table = &range_unipolar10; + else + s->range_table = &range_unipolar5; break; - case boardPCL812: - case boardACL8112: - case boardPCL812PG: - case boardACL8216: - if (it->options[5] == 1) + case BOARD_PCL812: + case BOARD_ACL8112: + case BOARD_PCL812PG: + case BOARD_ACL8216: + switch (it->options[5]) { + case 1: s->range_table = &range_unipolar10; - if (it->options[5] == 2) + break; + case 2: s->range_table = &range_unknown; + break; + default: + s->range_table = &range_unipolar5; + break; + } + break; + default: + s->range_table = &range_unipolar5; break; } s->insn_write = pcl812_ao_insn_write; @@ -1268,23 +1286,23 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) } switch (board->board_type) { - case boardACL8216: - case boardPCL812PG: - case boardPCL812: - case boardACL8112: + case BOARD_ACL8216: + case BOARD_PCL812PG: + case BOARD_PCL812: + case BOARD_ACL8112: devpriv->max_812_ai_mode0_rangewait = 1; if (it->options[3] > 0) /* we use external trigger */ devpriv->use_ext_trg = 1; break; - case boardA821: + case BOARD_A821: devpriv->max_812_ai_mode0_rangewait = 1; devpriv->mode_reg_int = (dev->irq << 4) & 0xf0; break; - case boardPCL813B: - case boardPCL813: - case boardISO813: - case boardACL8113: + case BOARD_PCL813B: + case BOARD_PCL813: + case BOARD_ISO813: + case BOARD_ACL8113: /* maybe there must by greatest timeout */ devpriv->max_812_ai_mode0_rangewait = 5; break; diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index a353d1b15..c00a71f53 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -1,36 +1,33 @@ /* - comedi/drivers/pcl816.c - - Author: Juan Grigera - based on pcl818 by Michal Dobes and bits of pcl812 + * pcl816.c + * Comedi driver for Advantech PCL-816 cards + * + * Author: Juan Grigera + * based on pcl818 by Michal Dobes and bits of pcl812 + */ - hardware driver for Advantech cards: - card: PCL-816, PCL814B - driver: pcl816 -*/ /* -Driver: pcl816 -Description: Advantech PCL-816 cards, PCL-814 -Author: Juan Grigera -Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b) -Status: works -Updated: Tue, 2 Apr 2002 23:15:21 -0800 - -PCL 816 and 814B have 16 SE/DIFF ADCs, 16 DACs, 16 DI and 16 DO. -Differences are at resolution (16 vs 12 bits). - -The driver support AI command mode, other subdevices not written. - -Analog output and digital input and output are not supported. - -Configuration Options: - [0] - IO Base - [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) - [2] - DMA (0=disable, 1, 3) - [3] - 0, 10=10MHz clock for 8254 - 1= 1MHz clock for 8254 - -*/ + * Driver: pcl816 + * Description: Advantech PCL-816 cards, PCL-814 + * Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b) + * Author: Juan Grigera + * Status: works + * Updated: Tue, 2 Apr 2002 23:15:21 -0800 + * + * PCL 816 and 814B have 16 SE/DIFF ADCs, 16 DACs, 16 DI and 16 DO. + * Differences are at resolution (16 vs 12 bits). + * + * The driver support AI command mode, other subdevices not written. + * + * Analog output and digital input and output are not supported. + * + * Configuration Options: + * [0] - IO Base + * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) + * [2] - DMA (0=disable, 1, 3) + * [3] - 0, 10=10MHz clock for 8254 + * 1= 1MHz clock for 8254 + */ #include #include @@ -56,25 +53,20 @@ Configuration Options: #define PCL816_MUX_REG 0x0b #define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) #define PCL816_CTRL_REG 0x0c -#define PCL816_CTRL_DISABLE_TRIG (0 << 0) -#define PCL816_CTRL_SOFT_TRIG (1 << 0) -#define PCL816_CTRL_PACER_TRIG (1 << 1) -#define PCL816_CTRL_EXT_TRIG (1 << 2) -#define PCL816_CTRL_POE (1 << 3) -#define PCL816_CTRL_DMAEN (1 << 4) -#define PCL816_CTRL_INTEN (1 << 5) -#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6) -#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6) -#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6) +#define PCL816_CTRL_SOFT_TRIG BIT(0) +#define PCL816_CTRL_PACER_TRIG BIT(1) +#define PCL816_CTRL_EXT_TRIG BIT(2) +#define PCL816_CTRL_POE BIT(3) +#define PCL816_CTRL_DMAEN BIT(4) +#define PCL816_CTRL_INTEN BIT(5) +#define PCL816_CTRL_DMASRC_SLOT(x) (((x) & 0x3) << 6) #define PCL816_STATUS_REG 0x0d #define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0) -#define PCL816_STATUS_INTSRC_MASK (3 << 4) -#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4) -#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4) -#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4) -#define PCL816_STATUS_INTSRC_DMA (3 << 4) -#define PCL816_STATUS_INTACT (1 << 6) -#define PCL816_STATUS_DRDY (1 << 7) +#define PCL816_STATUS_INTSRC_SLOT(x) (((x) & 0x3) << 4) +#define PCL816_STATUS_INTSRC_DMA PCL816_STATUS_INTSRC_SLOT(3) +#define PCL816_STATUS_INTSRC_MASK PCL816_STATUS_INTSRC_SLOT(3) +#define PCL816_STATUS_INTACT BIT(6) +#define PCL816_STATUS_DRDY BIT(7) #define MAGIC_DMA_WORD 0x5a5a @@ -94,7 +86,6 @@ static const struct comedi_lrange range_pcl816 = { struct pcl816_board { const char *name; int ai_maxdata; - int ao_maxdata; int ai_chanlist; }; @@ -102,12 +93,10 @@ static const struct pcl816_board boardtypes[] = { { .name = "pcl816", .ai_maxdata = 0xffff, - .ao_maxdata = 0xffff, .ai_chanlist = 1024, }, { .name = "pcl814b", .ai_maxdata = 0x3fff, - .ao_maxdata = 0x3fff, .ai_chanlist = 1024, }, }; @@ -443,7 +432,8 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) comedi_8254_update_divisors(dev->pacer); comedi_8254_pacer_enable(dev->pacer, 1, 2, true); - ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0; + ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | + PCL816_CTRL_DMASRC_SLOT(0); if (cmd->convert_src == TRIG_TIMER) ctrl |= PCL816_CTRL_PACER_TRIG; else /* TRIG_EXT */ @@ -497,7 +487,7 @@ static int pcl816_ai_cancel(struct comedi_device *dev, if (!devpriv->ai_cmd_running) return 0; - outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + outb(0, dev->iobase + PCL816_CTRL_REG); pcl816_ai_clear_eoc(dev); comedi_8254_pacer_enable(dev->pacer, 1, 2, false); @@ -533,7 +523,7 @@ static int pcl816_ai_insn_read(struct comedi_device *dev, data[i] = pcl816_ai_get_sample(dev, s); } - outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + outb(0, dev->iobase + PCL816_CTRL_REG); pcl816_ai_clear_eoc(dev); return ret ? ret : insn->n; @@ -567,7 +557,7 @@ static int pcl816_do_insn_bits(struct comedi_device *dev, static void pcl816_reset(struct comedi_device *dev) { - outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + outb(0, dev->iobase + PCL816_CTRL_REG); pcl816_ai_set_chan_range(dev, 0, 0); pcl816_ai_clear_eoc(dev); @@ -652,16 +642,9 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->cancel = pcl816_ai_cancel; } - /* Analog OUtput subdevice */ - s = &dev->subdevices[2]; + /* Piggyback Slot1 subdevice */ + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_UNUSED; -#if 0 - subdevs[1] = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = 1; - s->maxdata = board->ao_maxdata; - s->range_table = &range_pcl816; -#endif /* Digital Input subdevice */ s = &dev->subdevices[2]; diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index e1bdde977..5aeed44df 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -102,15 +102,6 @@ #include "comedi_isadma.h" #include "comedi_8254.h" -/* boards constants */ - -#define boardPCL818L 0 -#define boardPCL818H 1 -#define boardPCL818HD 2 -#define boardPCL818HG 3 -#define boardPCL818 4 -#define boardPCL718 5 - /* * Register I/O map */ @@ -124,23 +115,22 @@ #define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2)) #define PCL818_STATUS_REG 0x08 #define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0) -#define PCL818_STATUS_INT (1 << 4) -#define PCL818_STATUS_MUX (1 << 5) -#define PCL818_STATUS_UNI (1 << 6) -#define PCL818_STATUS_EOC (1 << 7) +#define PCL818_STATUS_INT BIT(4) +#define PCL818_STATUS_MUX BIT(5) +#define PCL818_STATUS_UNI BIT(6) +#define PCL818_STATUS_EOC BIT(7) #define PCL818_CTRL_REG 0x09 -#define PCL818_CTRL_DISABLE_TRIG (0 << 0) -#define PCL818_CTRL_SOFT_TRIG (1 << 0) -#define PCL818_CTRL_EXT_TRIG (2 << 0) -#define PCL818_CTRL_PACER_TRIG (3 << 0) -#define PCL818_CTRL_DMAE (1 << 2) +#define PCL818_CTRL_TRIG(x) (((x) & 0x3) << 0) +#define PCL818_CTRL_DISABLE_TRIG PCL818_CTRL_TRIG(0) +#define PCL818_CTRL_SOFT_TRIG PCL818_CTRL_TRIG(1) +#define PCL818_CTRL_EXT_TRIG PCL818_CTRL_TRIG(2) +#define PCL818_CTRL_PACER_TRIG PCL818_CTRL_TRIG(3) +#define PCL818_CTRL_DMAE BIT(2) #define PCL818_CTRL_IRQ(x) ((x) << 4) -#define PCL818_CTRL_INTE (1 << 7) +#define PCL818_CTRL_INTE BIT(7) #define PCL818_CNTENABLE_REG 0x0a -#define PCL818_CNTENABLE_PACER_ENA (0 << 0) -#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0) -#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1) -#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1) +#define PCL818_CNTENABLE_PACER_TRIG0 BIT(0) +#define PCL818_CNTENABLE_CNT0_INT_CLK BIT(1) /* 0=ext clk */ #define PCL818_DO_DI_MSB_REG 0x0b #define PCL818_TIMER_BASE 0x0c @@ -740,7 +730,7 @@ static int pcl818_ai_cmd(struct comedi_device *dev, else ctrl |= PCL818_CTRL_EXT_TRIG; - outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + outb(0, dev->iobase + PCL818_CNTENABLE_REG); if (dma) { /* setup and enable dma for the first buffer */ @@ -902,7 +892,7 @@ static void pcl818_reset(struct comedi_device *dev) pcl818_ai_set_chan_range(dev, 0, 0); /* stop pacer */ - outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + outb(0, dev->iobase + PCL818_CNTENABLE_REG); /* set analog output channels to 0V */ for (chan = 0; chan < board->n_aochan; chan++) { diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index 6176dfa24..588ae5ece 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -1,31 +1,25 @@ /* - comedi/drivers/pcm724.c - - Drew Csillag - - hardware driver for Advantech card: - card: PCM-3724 - driver: pcm3724 + * pcm3724.c + * Comedi driver for Advantech PCM-3724 Digital I/O board + * + * Drew Csillag + */ - Options for PCM-3724 - [0] - IO Base -*/ -/* -Driver: pcm3724 -Description: Advantech PCM-3724 -Author: Drew Csillag -Devices: [Advantech] PCM-3724 (pcm724) -Status: tested - -This is driver for digital I/O boards PCM-3724 with 48 DIO. -It needs 8255.o for operations and only immediate mode is supported. -See the source for configuration details. - -Copy/pasted/hacked from pcm724.c -*/ /* - * check_driver overrides: - * struct comedi_insn + * Driver: pcm3724 + * Description: Advantech PCM-3724 + * Devices: [Advantech] PCM-3724 (pcm3724) + * Author: Drew Csillag + * Status: tested + * + * This is driver for digital I/O boards PCM-3724 with 48 DIO. + * It needs 8255.o for operations and only immediate mode is supported. + * See the source for configuration details. + * + * Copy/pasted/hacked from pcm724.c + * + * Configuration Options: + * [0] - I/O port base address */ #include @@ -33,19 +27,31 @@ Copy/pasted/hacked from pcm724.c #include "8255.h" -#define BUF_C0 0x1 -#define BUF_B0 0x2 -#define BUF_A0 0x4 -#define BUF_C1 0x8 -#define BUF_B1 0x10 -#define BUF_A1 0x20 - -#define GATE_A0 0x4 -#define GATE_B0 0x2 -#define GATE_C0 0x1 -#define GATE_A1 0x20 -#define GATE_B1 0x10 -#define GATE_C1 0x8 +/* + * Register I/O Map + * + * This board has two standard 8255 devices that provide six 8-bit DIO ports + * (48 channels total). Six 74HCT245 chips (one for each port) buffer the + * I/O lines to increase driving capability. Because the 74HCT245 is a + * bidirectional, tri-state line buffer, two additional I/O ports are used + * to control the direction of data and the enable of each port. + */ +#define PCM3724_8255_0_BASE 0x00 +#define PCM3724_8255_1_BASE 0x04 +#define PCM3724_DIO_DIR_REG 0x08 +#define PCM3724_DIO_DIR_C0_OUT BIT(0) +#define PCM3724_DIO_DIR_B0_OUT BIT(1) +#define PCM3724_DIO_DIR_A0_OUT BIT(2) +#define PCM3724_DIO_DIR_C1_OUT BIT(3) +#define PCM3724_DIO_DIR_B1_OUT BIT(4) +#define PCM3724_DIO_DIR_A1_OUT BIT(5) +#define PCM3724_GATE_CTRL_REG 0x09 +#define PCM3724_GATE_CTRL_C0_ENA BIT(0) +#define PCM3724_GATE_CTRL_B0_ENA BIT(1) +#define PCM3724_GATE_CTRL_A0_ENA BIT(2) +#define PCM3724_GATE_CTRL_C1_ENA BIT(3) +#define PCM3724_GATE_CTRL_B1_ENA BIT(4) +#define PCM3724_GATE_CTRL_A1_ENA BIT(5) /* used to track configured dios */ struct priv_pcm3724 { @@ -58,21 +64,21 @@ static int compute_buffer(int config, int devno, struct comedi_subdevice *s) /* 1 in io_bits indicates output */ if (s->io_bits & 0x0000ff) { if (devno == 0) - config |= BUF_A0; + config |= PCM3724_DIO_DIR_A0_OUT; else - config |= BUF_A1; + config |= PCM3724_DIO_DIR_A1_OUT; } if (s->io_bits & 0x00ff00) { if (devno == 0) - config |= BUF_B0; + config |= PCM3724_DIO_DIR_B0_OUT; else - config |= BUF_B1; + config |= PCM3724_DIO_DIR_B1_OUT; } if (s->io_bits & 0xff0000) { if (devno == 0) - config |= BUF_C0; + config |= PCM3724_DIO_DIR_C0_OUT; else - config |= BUF_C1; + config |= PCM3724_DIO_DIR_C1_OUT; } return config; } @@ -107,7 +113,7 @@ static void do_3724_config(struct comedi_device *dev, else port_8255_cfg = dev->iobase + I8255_SIZE + I8255_CTRL_REG; - outb(buffer_config, dev->iobase + 8); /* update buffer register */ + outb(buffer_config, dev->iobase + PCM3724_DIO_DIR_REG); outb(config, port_8255_cfg); } @@ -129,24 +135,24 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s, priv->dio_2 |= mask; if (priv->dio_1 & 0xff0000) - gatecfg |= GATE_C0; + gatecfg |= PCM3724_GATE_CTRL_C0_ENA; if (priv->dio_1 & 0xff00) - gatecfg |= GATE_B0; + gatecfg |= PCM3724_GATE_CTRL_B0_ENA; if (priv->dio_1 & 0xff) - gatecfg |= GATE_A0; + gatecfg |= PCM3724_GATE_CTRL_A0_ENA; if (priv->dio_2 & 0xff0000) - gatecfg |= GATE_C1; + gatecfg |= PCM3724_GATE_CTRL_C1_ENA; if (priv->dio_2 & 0xff00) - gatecfg |= GATE_B1; + gatecfg |= PCM3724_GATE_CTRL_B1_ENA; if (priv->dio_2 & 0xff) - gatecfg |= GATE_A1; + gatecfg |= PCM3724_GATE_CTRL_A1_ENA; - outb(gatecfg, dev->iobase + 9); + outb(gatecfg, dev->iobase + PCM3724_GATE_CTRL_REG); } /* overriding the 8255 insn config */ @@ -216,5 +222,5 @@ static struct comedi_driver pcm3724_driver = { module_comedi_driver(pcm3724_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Advantech PCM-3724 Digital I/O board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 152cb146f..e9e431391 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -1,149 +1,153 @@ -/*====================================================================== - - comedi/drivers/quatech_daqp_cs.c - - Quatech DAQP PCMCIA data capture cards COMEDI client driver - Copyright (C) 2000, 2003 Brent Baccala - The DAQP interface code in this file is released into the public domain. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef - http://www.comedi.org/ - - quatech_daqp_cs.c 1.10 - - Documentation for the DAQP PCMCIA cards can be found on Quatech's site: - - ftp://ftp.quatech.com/Manuals/daqp-208.pdf - - This manual is for both the DAQP-208 and the DAQP-308. - - What works: - - - A/D conversion - - 8 channels - - 4 gain ranges - - ground ref or differential - - single-shot and timed both supported - - D/A conversion, single-shot - - digital I/O - - What doesn't: - - - any kind of triggering - external or D/A channel 1 - - the card's optional expansion board - - the card's timer (for anything other than A/D conversion) - - D/A update modes other than immediate (i.e, timed) - - fancier timing modes - - setting card's FIFO buffer thresholds to anything but default - -======================================================================*/ +/* + * quatech_daqp_cs.c + * Quatech DAQP PCMCIA data capture cards COMEDI client driver + * Copyright (C) 2000, 2003 Brent Baccala + * The DAQP interface code in this file is released into the public domain. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef + * http://www.comedi.org/ + * + * Documentation for the DAQP PCMCIA cards can be found on Quatech's site: + * ftp://ftp.quatech.com/Manuals/daqp-208.pdf + * + * This manual is for both the DAQP-208 and the DAQP-308. + * + * What works: + * - A/D conversion + * - 8 channels + * - 4 gain ranges + * - ground ref or differential + * - single-shot and timed both supported + * - D/A conversion, single-shot + * - digital I/O + * + * What doesn't: + * - any kind of triggering - external or D/A channel 1 + * - the card's optional expansion board + * - the card's timer (for anything other than A/D conversion) + * - D/A update modes other than immediate (i.e, timed) + * - fancier timing modes + * - setting card's FIFO buffer thresholds to anything but default + */ /* -Driver: quatech_daqp_cs -Description: Quatech DAQP PCMCIA data capture cards -Author: Brent Baccala -Status: works -Devices: [Quatech] DAQP-208 (daqp), DAQP-308 -*/ + * Driver: quatech_daqp_cs + * Description: Quatech DAQP PCMCIA data capture cards + * Devices: [Quatech] DAQP-208 (daqp), DAQP-308 + * Author: Brent Baccala + * Status: works + */ #include -#include -#include #include "../comedi_pcmcia.h" +/* + * Register I/O map + * + * The D/A and timer registers can be accessed with 16-bit or 8-bit I/O + * instructions. All other registers can only use 8-bit instructions. + * + * The FIFO and scanlist registers require two 8-bit instructions to + * access the 16-bit data. Data is transferred LSB then MSB. + */ +#define DAQP_AI_FIFO_REG 0x00 + +#define DAQP_SCANLIST_REG 0x01 +#define DAQP_SCANLIST_DIFFERENTIAL BIT(14) +#define DAQP_SCANLIST_GAIN(x) (((x) & 0x3) << 12) +#define DAQP_SCANLIST_CHANNEL(x) (((x) & 0xf) << 8) +#define DAQP_SCANLIST_START BIT(7) +#define DAQP_SCANLIST_EXT_GAIN(x) (((x) & 0x3) << 4) +#define DAQP_SCANLIST_EXT_CHANNEL(x) (((x) & 0xf) << 0) + +#define DAQP_CTRL_REG 0x02 +#define DAQP_CTRL_PACER_CLK(x) (((x) & 0x3) << 6) +#define DAQP_CTRL_PACER_CLK_EXT DAQP_CTRL_PACER_CLK(0) +#define DAQP_CTRL_PACER_CLK_5MHZ DAQP_CTRL_PACER_CLK(1) +#define DAQP_CTRL_PACER_CLK_1MHZ DAQP_CTRL_PACER_CLK(2) +#define DAQP_CTRL_PACER_CLK_100KHZ DAQP_CTRL_PACER_CLK(3) +#define DAQP_CTRL_EXPANSION BIT(5) +#define DAQP_CTRL_EOS_INT_ENA BIT(4) +#define DAQP_CTRL_FIFO_INT_ENA BIT(3) +#define DAQP_CTRL_TRIG_MODE BIT(2) /* 0=one-shot; 1=continuous */ +#define DAQP_CTRL_TRIG_SRC BIT(1) /* 0=internal; 1=external */ +#define DAQP_CTRL_TRIG_EDGE BIT(0) /* 0=rising; 1=falling */ + +#define DAQP_STATUS_REG 0x02 +#define DAQP_STATUS_IDLE BIT(7) +#define DAQP_STATUS_RUNNING BIT(6) +#define DAQP_STATUS_DATA_LOST BIT(5) +#define DAQP_STATUS_END_OF_SCAN BIT(4) +#define DAQP_STATUS_FIFO_THRESHOLD BIT(3) +#define DAQP_STATUS_FIFO_FULL BIT(2) +#define DAQP_STATUS_FIFO_NEARFULL BIT(1) +#define DAQP_STATUS_FIFO_EMPTY BIT(0) +/* these bits clear when the status register is read */ +#define DAQP_STATUS_EVENTS (DAQP_STATUS_DATA_LOST | \ + DAQP_STATUS_END_OF_SCAN | \ + DAQP_STATUS_FIFO_THRESHOLD) + +#define DAQP_DI_REG 0x03 +#define DAQP_DO_REG 0x03 + +#define DAQP_PACER_LOW_REG 0x04 +#define DAQP_PACER_MID_REG 0x05 +#define DAQP_PACER_HIGH_REG 0x06 + +#define DAQP_CMD_REG 0x07 +/* the monostable bits are self-clearing after the function is complete */ +#define DAQP_CMD_ARM BIT(7) /* monostable */ +#define DAQP_CMD_RSTF BIT(6) /* monostable */ +#define DAQP_CMD_RSTQ BIT(5) /* monostable */ +#define DAQP_CMD_STOP BIT(4) /* monostable */ +#define DAQP_CMD_LATCH BIT(3) /* monostable */ +#define DAQP_CMD_SCANRATE(x) (((x) & 0x3) << 1) +#define DAQP_CMD_SCANRATE_100KHZ DAQP_CMD_SCANRATE(0) +#define DAQP_CMD_SCANRATE_50KHZ DAQP_CMD_SCANRATE(1) +#define DAQP_CMD_SCANRATE_25KHZ DAQP_CMD_SCANRATE(2) +#define DAQP_CMD_FIFO_DATA BIT(0) + +#define DAQP_AO_REG 0x08 /* and 0x09 (16-bit) */ + +#define DAQP_TIMER_REG 0x0a /* and 0x0b (16-bit) */ + +#define DAQP_AUX_REG 0x0f +/* Auxiliary Control register bits (write) */ +#define DAQP_AUX_EXT_ANALOG_TRIG BIT(7) +#define DAQP_AUX_PRETRIG BIT(6) +#define DAQP_AUX_TIMER_INT_ENA BIT(5) +#define DAQP_AUX_TIMER_MODE(x) (((x) & 0x3) << 3) +#define DAQP_AUX_TIMER_MODE_RELOAD DAQP_AUX_TIMER_MODE(0) +#define DAQP_AUX_TIMER_MODE_PAUSE DAQP_AUX_TIMER_MODE(1) +#define DAQP_AUX_TIMER_MODE_GO DAQP_AUX_TIMER_MODE(2) +#define DAQP_AUX_TIMER_MODE_EXT DAQP_AUX_TIMER_MODE(3) +#define DAQP_AUX_TIMER_CLK_SRC_EXT BIT(2) +#define DAQP_AUX_DA_UPDATE(x) (((x) & 0x3) << 0) +#define DAQP_AUX_DA_UPDATE_DIRECT DAQP_AUX_DA_UPDATE(0) +#define DAQP_AUX_DA_UPDATE_OVERFLOW DAQP_AUX_DA_UPDATE(1) +#define DAQP_AUX_DA_UPDATE_EXTERNAL DAQP_AUX_DA_UPDATE(2) +#define DAQP_AUX_DA_UPDATE_PACER DAQP_AUX_DA_UPDATE(3) +/* Auxiliary Status register bits (read) */ +#define DAQP_AUX_RUNNING BIT(7) +#define DAQP_AUX_TRIGGERED BIT(6) +#define DAQP_AUX_DA_BUFFER BIT(5) +#define DAQP_AUX_TIMER_OVERFLOW BIT(4) +#define DAQP_AUX_CONVERSION BIT(3) +#define DAQP_AUX_DATA_LOST BIT(2) +#define DAQP_AUX_FIFO_NEARFULL BIT(1) +#define DAQP_AUX_FIFO_EMPTY BIT(0) + +#define DAQP_FIFO_SIZE 4096 + +#define DAQP_MAX_TIMER_SPEED 10000 /* 100 kHz in nanoseconds */ + struct daqp_private { + unsigned int pacer_div; int stop; - - enum { semaphore, buffer } interrupt_mode; - - struct completion eos; }; -/* The DAQP communicates with the system through a 16 byte I/O window. */ - -#define DAQP_FIFO_SIZE 4096 - -#define DAQP_FIFO 0 -#define DAQP_SCANLIST 1 -#define DAQP_CONTROL 2 -#define DAQP_STATUS 2 -#define DAQP_DIGITAL_IO 3 -#define DAQP_PACER_LOW 4 -#define DAQP_PACER_MID 5 -#define DAQP_PACER_HIGH 6 -#define DAQP_COMMAND 7 -#define DAQP_DA 8 -#define DAQP_TIMER 10 -#define DAQP_AUX 15 - -#define DAQP_SCANLIST_DIFFERENTIAL 0x4000 -#define DAQP_SCANLIST_GAIN(x) ((x)<<12) -#define DAQP_SCANLIST_CHANNEL(x) ((x)<<8) -#define DAQP_SCANLIST_START 0x0080 -#define DAQP_SCANLIST_EXT_GAIN(x) ((x)<<4) -#define DAQP_SCANLIST_EXT_CHANNEL(x) (x) - -#define DAQP_CONTROL_PACER_100kHz 0xc0 -#define DAQP_CONTROL_PACER_1MHz 0x80 -#define DAQP_CONTROL_PACER_5MHz 0x40 -#define DAQP_CONTROL_PACER_EXTERNAL 0x00 -#define DAQP_CONTORL_EXPANSION 0x20 -#define DAQP_CONTROL_EOS_INT_ENABLE 0x10 -#define DAQP_CONTROL_FIFO_INT_ENABLE 0x08 -#define DAQP_CONTROL_TRIGGER_ONESHOT 0x00 -#define DAQP_CONTROL_TRIGGER_CONTINUOUS 0x04 -#define DAQP_CONTROL_TRIGGER_INTERNAL 0x00 -#define DAQP_CONTROL_TRIGGER_EXTERNAL 0x02 -#define DAQP_CONTROL_TRIGGER_RISING 0x00 -#define DAQP_CONTROL_TRIGGER_FALLING 0x01 - -#define DAQP_STATUS_IDLE 0x80 -#define DAQP_STATUS_RUNNING 0x40 -#define DAQP_STATUS_EVENTS 0x38 -#define DAQP_STATUS_DATA_LOST 0x20 -#define DAQP_STATUS_END_OF_SCAN 0x10 -#define DAQP_STATUS_FIFO_THRESHOLD 0x08 -#define DAQP_STATUS_FIFO_FULL 0x04 -#define DAQP_STATUS_FIFO_NEARFULL 0x02 -#define DAQP_STATUS_FIFO_EMPTY 0x01 - -#define DAQP_COMMAND_ARM 0x80 -#define DAQP_COMMAND_RSTF 0x40 -#define DAQP_COMMAND_RSTQ 0x20 -#define DAQP_COMMAND_STOP 0x10 -#define DAQP_COMMAND_LATCH 0x08 -#define DAQP_COMMAND_100kHz 0x00 -#define DAQP_COMMAND_50kHz 0x02 -#define DAQP_COMMAND_25kHz 0x04 -#define DAQP_COMMAND_FIFO_DATA 0x01 -#define DAQP_COMMAND_FIFO_PROGRAM 0x00 - -#define DAQP_AUX_TRIGGER_TTL 0x00 -#define DAQP_AUX_TRIGGER_ANALOG 0x80 -#define DAQP_AUX_TRIGGER_PRETRIGGER 0x40 -#define DAQP_AUX_TIMER_INT_ENABLE 0x20 -#define DAQP_AUX_TIMER_RELOAD 0x00 -#define DAQP_AUX_TIMER_PAUSE 0x08 -#define DAQP_AUX_TIMER_GO 0x10 -#define DAQP_AUX_TIMER_GO_EXTERNAL 0x18 -#define DAQP_AUX_TIMER_EXTERNAL_SRC 0x04 -#define DAQP_AUX_TIMER_INTERNAL_SRC 0x00 -#define DAQP_AUX_DA_DIRECT 0x00 -#define DAQP_AUX_DA_OVERFLOW 0x01 -#define DAQP_AUX_DA_EXTERNAL 0x02 -#define DAQP_AUX_DA_PACER 0x03 - -#define DAQP_AUX_RUNNING 0x80 -#define DAQP_AUX_TRIGGERED 0x40 -#define DAQP_AUX_DA_BUFFER 0x20 -#define DAQP_AUX_TIMER_OVERFLOW 0x10 -#define DAQP_AUX_CONVERSION 0x08 -#define DAQP_AUX_DATA_LOST 0x04 -#define DAQP_AUX_FIFO_NEARFULL 0x02 -#define DAQP_AUX_FIFO_EMPTY 0x01 - static const struct comedi_lrange range_daqp_ai = { 4, { BIP_RANGE(10), @@ -153,38 +157,59 @@ static const struct comedi_lrange range_daqp_ai = { } }; -/* Cancel a running acquisition */ +static int daqp_clear_events(struct comedi_device *dev, int loops) +{ + unsigned int status; -static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) + /* + * Reset any pending interrupts (my card has a tendency to require + * require multiple reads on the status register to achieve this). + */ + while (--loops) { + status = inb(dev->iobase + DAQP_STATUS_REG); + if ((status & DAQP_STATUS_EVENTS) == 0) + return 0; + } + dev_err(dev->class_dev, "couldn't clear events in status register\n"); + return -EBUSY; +} + +static int daqp_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct daqp_private *devpriv = dev->private; if (devpriv->stop) return -EIO; - outb(DAQP_COMMAND_STOP, dev->iobase + DAQP_COMMAND); + /* + * Stop any conversions, disable interrupts, and clear + * the status event flags. + */ + outb(DAQP_CMD_STOP, dev->iobase + DAQP_CMD_REG); + outb(0, dev->iobase + DAQP_CTRL_REG); + inb(dev->iobase + DAQP_STATUS_REG); - /* flush any linguring data in FIFO - superfluous here */ - /* outb(DAQP_COMMAND_RSTF, dev->iobase+DAQP_COMMAND); */ + return 0; +} - devpriv->interrupt_mode = semaphore; +static unsigned int daqp_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; - return 0; + /* + * Get a two's complement sample from the FIFO and + * return the munged offset binary value. + */ + val = inb(dev->iobase + DAQP_AI_FIFO_REG); + val |= inb(dev->iobase + DAQP_AI_FIFO_REG) << 8; + return comedi_offset_munge(s, val); } -/* Interrupt handler - * - * Operates in one of two modes. If devpriv->interrupt_mode is - * 'semaphore', just signal the devpriv->eos completion and return - * (one-shot mode). Otherwise (continuous mode), read data in from - * the card, transfer it to the buffer provided by the higher-level - * comedi kernel module, and signal various comedi callback routines, - * which run pretty quick. - */ -static enum irqreturn daqp_interrupt(int irq, void *dev_id) +static irqreturn_t 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; @@ -193,50 +218,42 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) if (!dev->attached) return IRQ_NONE; - switch (devpriv->interrupt_mode) { - case semaphore: - complete(&devpriv->eos); - break; + status = inb(dev->iobase + DAQP_STATUS_REG); + if (!(status & DAQP_STATUS_EVENTS)) + return IRQ_NONE; - case buffer: - while (!((status = inb(dev->iobase + DAQP_STATUS)) - & DAQP_STATUS_FIFO_EMPTY)) { - unsigned short data; + while (!(status & DAQP_STATUS_FIFO_EMPTY)) { + unsigned short data; - if (status & DAQP_STATUS_DATA_LOST) { - s->async->events |= COMEDI_CB_OVERFLOW; - dev_warn(dev->class_dev, "data lost\n"); - break; - } + if (status & DAQP_STATUS_DATA_LOST) { + s->async->events |= COMEDI_CB_OVERFLOW; + dev_warn(dev->class_dev, "data lost\n"); + break; + } - data = inb(dev->iobase + DAQP_FIFO); - data |= inb(dev->iobase + DAQP_FIFO) << 8; - data ^= 0x8000; + data = daqp_ai_get_sample(dev, s); + comedi_buf_write_samples(s, &data, 1); - 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; + break; + } - /* If there's a limit, decrement it - * and stop conversion if zero - */ + if ((loop_limit--) <= 0) + break; - if (cmd->stop_src == TRIG_COUNT && - s->async->scans_done >= cmd->stop_arg) { - s->async->events |= COMEDI_CB_EOA; - break; - } + status = inb(dev->iobase + DAQP_STATUS_REG); + } - if ((loop_limit--) <= 0) - break; - } + if (loop_limit <= 0) { + dev_warn(dev->class_dev, + "loop_limit reached in daqp_interrupt()\n"); + s->async->events |= COMEDI_CB_ERROR; + } - if (loop_limit <= 0) { - dev_warn(dev->class_dev, - "loop_limit reached in daqp_interrupt()\n"); - s->async->events |= COMEDI_CB_ERROR; - } + comedi_handle_events(dev, s); - comedi_handle_events(dev, s); - } return IRQ_HANDLED; } @@ -257,78 +274,73 @@ static void daqp_ai_set_one_scanlist_entry(struct comedi_device *dev, if (start) val |= DAQP_SCANLIST_START; - outb(val & 0xff, dev->iobase + DAQP_SCANLIST); - outb((val >> 8) & 0xff, dev->iobase + DAQP_SCANLIST); + outb(val & 0xff, dev->iobase + DAQP_SCANLIST_REG); + outb((val >> 8) & 0xff, dev->iobase + DAQP_SCANLIST_REG); } -/* One-shot analog data acquisition routine */ +static int daqp_ai_eos(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAQP_AUX_REG); + if (status & DAQP_AUX_CONVERSION) + return 0; + return -EBUSY; +} static int daqp_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct daqp_private *devpriv = dev->private; + int ret = 0; int i; - int v; - int counter = 10000; if (devpriv->stop) return -EIO; - /* Stop any running conversion */ - daqp_ai_cancel(dev, s); - - outb(0, dev->iobase + DAQP_AUX); + outb(0, dev->iobase + DAQP_AUX_REG); /* Reset scan list queue */ - outb(DAQP_COMMAND_RSTQ, dev->iobase + DAQP_COMMAND); + outb(DAQP_CMD_RSTQ, dev->iobase + DAQP_CMD_REG); /* Program one scan list entry */ daqp_ai_set_one_scanlist_entry(dev, insn->chanspec, 1); /* Reset data FIFO (see page 28 of DAQP User's Manual) */ + outb(DAQP_CMD_RSTF, dev->iobase + DAQP_CMD_REG); - outb(DAQP_COMMAND_RSTF, dev->iobase + DAQP_COMMAND); - - /* Set trigger */ - - v = DAQP_CONTROL_TRIGGER_ONESHOT | DAQP_CONTROL_TRIGGER_INTERNAL - | DAQP_CONTROL_PACER_100kHz | DAQP_CONTROL_EOS_INT_ENABLE; - - outb(v, dev->iobase + DAQP_CONTROL); + /* Set trigger - one-shot, internal, no interrupts */ + outb(DAQP_CTRL_PACER_CLK_100KHZ, dev->iobase + DAQP_CTRL_REG); - /* Reset any pending interrupts (my card has a tendency to require - * require multiple reads on the status register to achieve this) - */ - - while (--counter - && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) - ; - if (!counter) { - dev_err(dev->class_dev, - "couldn't clear interrupts in status register\n"); - return -1; - } - - init_completion(&devpriv->eos); - devpriv->interrupt_mode = semaphore; + ret = daqp_clear_events(dev, 10000); + if (ret) + return ret; for (i = 0; i < insn->n; i++) { /* Start conversion */ - outb(DAQP_COMMAND_ARM | DAQP_COMMAND_FIFO_DATA, - dev->iobase + DAQP_COMMAND); + outb(DAQP_CMD_ARM | DAQP_CMD_FIFO_DATA, + dev->iobase + DAQP_CMD_REG); - /* Wait for interrupt service routine to unblock completion */ - /* Maybe could use a timeout here, but it's interruptible */ - if (wait_for_completion_interruptible(&devpriv->eos)) - return -EINTR; + ret = comedi_timeout(dev, s, insn, daqp_ai_eos, 0); + if (ret) + break; - data[i] = inb(dev->iobase + DAQP_FIFO); - data[i] |= inb(dev->iobase + DAQP_FIFO) << 8; - data[i] ^= 0x8000; + /* clear the status event flags */ + inb(dev->iobase + DAQP_STATUS_REG); + + data[i] = daqp_ai_get_sample(dev, s); } - return insn->n; + /* stop any conversions and clear the status event flags */ + outb(DAQP_CMD_STOP, dev->iobase + DAQP_CMD_REG); + inb(dev->iobase + DAQP_STATUS_REG); + + return ret ? ret : insn->n; } /* This function converts ns nanoseconds to a counter value suitable @@ -348,17 +360,18 @@ static int daqp_ns_to_timer(unsigned int *ns, unsigned int flags) return timer; } -/* cmdtest tests a particular command to see if it is valid. - * Using the cmdtest ioctl, a user can create a valid cmd - * and then have it executed by the cmd ioctl. - * - * cmdtest returns 1,2,3,4 or 0, depending on which tests - * the command passes. - */ +static void daqp_set_pacer(struct comedi_device *dev, unsigned int val) +{ + outb(val & 0xff, dev->iobase + DAQP_PACER_LOW_REG); + outb((val >> 8) & 0xff, dev->iobase + DAQP_PACER_MID_REG); + outb((val >> 16) & 0xff, dev->iobase + DAQP_PACER_HIGH_REG); +} static int daqp_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { + struct daqp_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -383,6 +396,10 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, /* Step 2b : and mutually compatible */ + /* the async command requires a pacer */ + if (cmd->scan_begin_src != TRIG_TIMER && cmd->convert_src != TRIG_TIMER) + err |= -EINVAL; + if (err) return 2; @@ -390,31 +407,31 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); -#define MAX_SPEED 10000 /* 100 kHz - in nanoseconds */ + err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, + cmd->chanlist_len); - if (cmd->scan_begin_src == TRIG_TIMER) { + if (cmd->scan_begin_src == TRIG_TIMER) err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); - } - - /* If both scan_begin and convert are both timer values, the only - * way that can make sense is if the scan time is the number of - * conversions times the convert time - */ - - if (cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER - && cmd->scan_begin_arg != cmd->convert_arg * cmd->scan_end_arg) { - err |= -EINVAL; - } + DAQP_MAX_TIMER_SPEED); if (cmd->convert_src == TRIG_TIMER) { err |= comedi_check_trigger_arg_min(&cmd->convert_arg, - MAX_SPEED); + DAQP_MAX_TIMER_SPEED); + + if (cmd->scan_begin_src == TRIG_TIMER) { + /* + * If both scan_begin and convert are both timer + * values, the only way that can make sense is if + * the scan time is the number of conversions times + * the convert time. + */ + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, + arg); + } } - err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, - cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); else /* TRIG_NONE */ @@ -425,16 +442,14 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->scan_begin_src == TRIG_TIMER) { - arg = cmd->scan_begin_arg; - daqp_ns_to_timer(&arg, cmd->flags); - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); - } - if (cmd->convert_src == TRIG_TIMER) { arg = cmd->convert_arg; - daqp_ns_to_timer(&arg, cmd->flags); + devpriv->pacer_div = daqp_ns_to_timer(&arg, cmd->flags); err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); + } else if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->scan_begin_arg; + devpriv->pacer_div = daqp_ns_to_timer(&arg, cmd->flags); + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) @@ -447,23 +462,18 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct daqp_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int counter; int scanlist_start_on_every_entry; int threshold; - + int ret; int i; - int v; if (devpriv->stop) return -EIO; - /* Stop any running conversion */ - daqp_ai_cancel(dev, s); - - outb(0, dev->iobase + DAQP_AUX); + outb(0, dev->iobase + DAQP_AUX_REG); /* Reset scan list queue */ - outb(DAQP_COMMAND_RSTQ, dev->iobase + DAQP_COMMAND); + outb(DAQP_CMD_RSTQ, dev->iobase + DAQP_CMD_REG); /* Program pacer clock * @@ -477,20 +487,12 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * each scan, so we program the pacer clock to this frequency * and only set the SCANLIST_START bit on the first entry. */ + daqp_set_pacer(dev, devpriv->pacer_div); - if (cmd->convert_src == TRIG_TIMER) { - counter = daqp_ns_to_timer(&cmd->convert_arg, cmd->flags); - outb(counter & 0xff, dev->iobase + DAQP_PACER_LOW); - outb((counter >> 8) & 0xff, dev->iobase + DAQP_PACER_MID); - outb((counter >> 16) & 0xff, dev->iobase + DAQP_PACER_HIGH); + if (cmd->convert_src == TRIG_TIMER) scanlist_start_on_every_entry = 1; - } else { - counter = daqp_ns_to_timer(&cmd->scan_begin_arg, cmd->flags); - outb(counter & 0xff, dev->iobase + DAQP_PACER_LOW); - outb((counter >> 8) & 0xff, dev->iobase + DAQP_PACER_MID); - outb((counter >> 16) & 0xff, dev->iobase + DAQP_PACER_HIGH); + else scanlist_start_on_every_entry = 0; - } /* Program scan list */ for (i = 0; i < cmd->chanlist_len; i++) { @@ -581,7 +583,7 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* Reset data FIFO (see page 28 of DAQP User's Manual) */ - outb(DAQP_COMMAND_RSTF, dev->iobase + DAQP_COMMAND); + outb(DAQP_CMD_RSTF, dev->iobase + DAQP_CMD_REG); /* Set FIFO threshold. First two bytes are near-empty * threshold, which is unused; next two bytes are near-full @@ -591,41 +593,40 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * when the interrupt is to happen. */ - outb(0x00, dev->iobase + DAQP_FIFO); - outb(0x00, dev->iobase + DAQP_FIFO); - - outb((DAQP_FIFO_SIZE - threshold) & 0xff, dev->iobase + DAQP_FIFO); - outb((DAQP_FIFO_SIZE - threshold) >> 8, dev->iobase + DAQP_FIFO); + outb(0x00, dev->iobase + DAQP_AI_FIFO_REG); + outb(0x00, dev->iobase + DAQP_AI_FIFO_REG); - /* Set trigger */ + outb((DAQP_FIFO_SIZE - threshold) & 0xff, + dev->iobase + DAQP_AI_FIFO_REG); + outb((DAQP_FIFO_SIZE - threshold) >> 8, dev->iobase + DAQP_AI_FIFO_REG); - v = DAQP_CONTROL_TRIGGER_CONTINUOUS | DAQP_CONTROL_TRIGGER_INTERNAL - | DAQP_CONTROL_PACER_5MHz | DAQP_CONTROL_FIFO_INT_ENABLE; - - outb(v, dev->iobase + DAQP_CONTROL); - - /* Reset any pending interrupts (my card has a tendency to require - * require multiple reads on the status register to achieve this) - */ - counter = 100; - while (--counter - && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) - ; - if (!counter) { - dev_err(dev->class_dev, - "couldn't clear interrupts in status register\n"); - return -1; - } + /* Set trigger - continuous, internal */ + outb(DAQP_CTRL_TRIG_MODE | DAQP_CTRL_PACER_CLK_5MHZ | + DAQP_CTRL_FIFO_INT_ENA, dev->iobase + DAQP_CTRL_REG); - devpriv->interrupt_mode = buffer; + ret = daqp_clear_events(dev, 100); + if (ret) + return ret; /* Start conversion */ - outb(DAQP_COMMAND_ARM | DAQP_COMMAND_FIFO_DATA, - dev->iobase + DAQP_COMMAND); + outb(DAQP_CMD_ARM | DAQP_CMD_FIFO_DATA, dev->iobase + DAQP_CMD_REG); return 0; } +static int daqp_ao_empty(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAQP_AUX_REG); + if ((status & DAQP_AUX_DA_BUFFER) == 0) + return 0; + return -EBUSY; +} + static int daqp_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -639,18 +640,22 @@ static int daqp_ao_insn_write(struct comedi_device *dev, return -EIO; /* Make sure D/A update mode is direct update */ - outb(0, dev->iobase + DAQP_AUX); + outb(0, dev->iobase + DAQP_AUX_REG); for (i = 0; i > insn->n; i++) { unsigned val = data[i]; + int ret; - s->readback[chan] = val; + /* D/A transfer rate is about 8ms */ + ret = comedi_timeout(dev, s, insn, daqp_ao_empty, 0); + if (ret) + return ret; - val &= 0x0fff; - val ^= 0x0800; /* Flip the sign */ - val |= (chan << 12); + /* write the two's complement value to the channel */ + outw((chan << 12) | comedi_offset_munge(s, val), + dev->iobase + DAQP_AO_REG); - outw(val, dev->iobase + DAQP_DA); + s->readback[chan] = val; } return insn->n; @@ -666,7 +671,7 @@ static int daqp_di_insn_bits(struct comedi_device *dev, if (devpriv->stop) return -EIO; - data[0] = inb(dev->iobase + DAQP_DIGITAL_IO); + data[0] = inb(dev->iobase + DAQP_DI_REG); return insn->n; } @@ -682,7 +687,7 @@ static int daqp_do_insn_bits(struct comedi_device *dev, return -EIO; if (comedi_dio_update_state(s, data)) - outb(s->state, dev->iobase + DAQP_DIGITAL_IO); + outb(s->state, dev->iobase + DAQP_DO_REG); data[1] = s->state; @@ -709,25 +714,28 @@ static int daqp_auto_attach(struct comedi_device *dev, link->priv = dev; ret = pcmcia_request_irq(link, daqp_interrupt); - if (ret) - return ret; + if (ret == 0) + dev->irq = link->irq; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; s->n_chan = 8; - s->len_chanlist = 2048; s->maxdata = 0xffff; s->range_table = &range_daqp_ai; s->insn_read = daqp_ai_insn_read; - s->do_cmdtest = daqp_ai_cmdtest; - s->do_cmd = daqp_ai_cmd; - s->cancel = daqp_ai_cancel; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 2048; + s->do_cmdtest = daqp_ai_cmdtest; + s->do_cmd = daqp_ai_cmd; + s->cancel = daqp_ai_cancel; + } s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; @@ -741,17 +749,35 @@ static int daqp_auto_attach(struct comedi_device *dev, if (ret) return ret; + /* + * Digital Input subdevice + * NOTE: The digital input lines are shared: + * + * Chan Normal Mode Expansion Mode + * ---- ----------------- ---------------------------- + * 0 DI0, ext. trigger Same as normal mode + * 1 DI1 External gain select, lo bit + * 2 DI2, ext. clock Same as normal mode + * 3 DI3 External gain select, hi bit + */ s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; - s->n_chan = 1; + s->n_chan = 4; s->maxdata = 1; s->insn_bits = daqp_di_insn_bits; + /* + * Digital Output subdevice + * NOTE: The digital output lines share the same pins on the + * interface connector as the four external channel selection + * bits. If expansion mode is used the digital outputs do not + * work. + */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; - s->n_chan = 1; + s->n_chan = 4; 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 4c13f5eb0..68ac02b68 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -72,8 +72,6 @@ * As far as I can tell, the About interrupt doesn't work if Sample is * also enabled. It turns out that About really isn't needed, since * we always count down samples read. - * - * There was some timer/counter code, but it didn't follow the right API. */ /* @@ -99,6 +97,7 @@ #include "../comedi_pci.h" +#include "comedi_8254.h" #include "plx9080.h" /* @@ -106,39 +105,38 @@ */ #define LAS0_USER_IO 0x0008 /* User I/O */ #define LAS0_ADC 0x0010 /* FIFO Status/Software A/D Start */ -#define FS_DAC1_NOT_EMPTY (1 << 0) /* DAC1 FIFO not empty */ -#define FS_DAC1_HEMPTY (1 << 1) /* DAC1 FIFO half empty */ -#define FS_DAC1_NOT_FULL (1 << 2) /* DAC1 FIFO not full */ -#define FS_DAC2_NOT_EMPTY (1 << 4) /* DAC2 FIFO not empty */ -#define FS_DAC2_HEMPTY (1 << 5) /* DAC2 FIFO half empty */ -#define FS_DAC2_NOT_FULL (1 << 6) /* DAC2 FIFO not full */ -#define FS_ADC_NOT_EMPTY (1 << 8) /* ADC FIFO not empty */ -#define FS_ADC_HEMPTY (1 << 9) /* ADC FIFO half empty */ -#define FS_ADC_NOT_FULL (1 << 10) /* ADC FIFO not full */ -#define FS_DIN_NOT_EMPTY (1 << 12) /* DIN FIFO not empty */ -#define FS_DIN_HEMPTY (1 << 13) /* DIN FIFO half empty */ -#define FS_DIN_NOT_FULL (1 << 14) /* DIN FIFO not full */ -#define LAS0_DAC1 0x0014 /* Software D/A1 Update (w) */ -#define LAS0_DAC2 0x0018 /* Software D/A2 Update (w) */ +#define FS_DAC1_NOT_EMPTY BIT(0) /* DAC1 FIFO not empty */ +#define FS_DAC1_HEMPTY BIT(1) /* DAC1 FIFO half empty */ +#define FS_DAC1_NOT_FULL BIT(2) /* DAC1 FIFO not full */ +#define FS_DAC2_NOT_EMPTY BIT(4) /* DAC2 FIFO not empty */ +#define FS_DAC2_HEMPTY BIT(5) /* DAC2 FIFO half empty */ +#define FS_DAC2_NOT_FULL BIT(6) /* DAC2 FIFO not full */ +#define FS_ADC_NOT_EMPTY BIT(8) /* ADC FIFO not empty */ +#define FS_ADC_HEMPTY BIT(9) /* ADC FIFO half empty */ +#define FS_ADC_NOT_FULL BIT(10) /* ADC FIFO not full */ +#define FS_DIN_NOT_EMPTY BIT(12) /* DIN FIFO not empty */ +#define FS_DIN_HEMPTY BIT(13) /* DIN FIFO half empty */ +#define FS_DIN_NOT_FULL BIT(14) /* DIN FIFO not full */ +#define LAS0_UPDATE_DAC(x) (0x0014 + ((x) * 0x4)) /* D/Ax Update (w) */ #define LAS0_DAC 0x0024 /* Software Simultaneous Update (w) */ #define LAS0_PACER 0x0028 /* Software Pacer Start/Stop */ #define LAS0_TIMER 0x002c /* Timer Status/HDIN Software Trig. */ #define LAS0_IT 0x0030 /* Interrupt Status/Enable */ -#define IRQM_ADC_FIFO_WRITE (1 << 0) /* ADC FIFO Write */ -#define IRQM_CGT_RESET (1 << 1) /* Reset CGT */ -#define IRQM_CGT_PAUSE (1 << 3) /* Pause CGT */ -#define IRQM_ADC_ABOUT_CNT (1 << 4) /* About Counter out */ -#define IRQM_ADC_DELAY_CNT (1 << 5) /* Delay Counter out */ -#define IRQM_ADC_SAMPLE_CNT (1 << 6) /* ADC Sample Counter */ -#define IRQM_DAC1_UCNT (1 << 7) /* DAC1 Update Counter */ -#define IRQM_DAC2_UCNT (1 << 8) /* DAC2 Update Counter */ -#define IRQM_UTC1 (1 << 9) /* User TC1 out */ -#define IRQM_UTC1_INV (1 << 10) /* User TC1 out, inverted */ -#define IRQM_UTC2 (1 << 11) /* User TC2 out */ -#define IRQM_DIGITAL_IT (1 << 12) /* Digital Interrupt */ -#define IRQM_EXTERNAL_IT (1 << 13) /* External Interrupt */ -#define IRQM_ETRIG_RISING (1 << 14) /* Ext Trigger rising-edge */ -#define IRQM_ETRIG_FALLING (1 << 15) /* Ext Trigger falling-edge */ +#define IRQM_ADC_FIFO_WRITE BIT(0) /* ADC FIFO Write */ +#define IRQM_CGT_RESET BIT(1) /* Reset CGT */ +#define IRQM_CGT_PAUSE BIT(3) /* Pause CGT */ +#define IRQM_ADC_ABOUT_CNT BIT(4) /* About Counter out */ +#define IRQM_ADC_DELAY_CNT BIT(5) /* Delay Counter out */ +#define IRQM_ADC_SAMPLE_CNT BIT(6) /* ADC Sample Counter */ +#define IRQM_DAC1_UCNT BIT(7) /* DAC1 Update Counter */ +#define IRQM_DAC2_UCNT BIT(8) /* DAC2 Update Counter */ +#define IRQM_UTC1 BIT(9) /* User TC1 out */ +#define IRQM_UTC1_INV BIT(10) /* User TC1 out, inverted */ +#define IRQM_UTC2 BIT(11) /* User TC2 out */ +#define IRQM_DIGITAL_IT BIT(12) /* Digital Interrupt */ +#define IRQM_EXTERNAL_IT BIT(13) /* External Interrupt */ +#define IRQM_ETRIG_RISING BIT(14) /* Ext Trigger rising-edge */ +#define IRQM_ETRIG_FALLING BIT(15) /* Ext Trigger falling-edge */ #define LAS0_CLEAR 0x0034 /* Clear/Set Interrupt Clear Mask */ #define LAS0_OVERRUN 0x0038 /* Pending interrupts/Clear Overrun */ #define LAS0_PCLK 0x0040 /* Pacer Clock (24bit) */ @@ -149,10 +147,7 @@ #define LAS0_DCNT 0x0054 /* Delay counter (16 bit) */ #define LAS0_ACNT 0x0058 /* About counter (16 bit) */ #define LAS0_DAC_CLK 0x005c /* DAC clock (16bit) */ -#define LAS0_UTC0 0x0060 /* 8254 TC Counter 0 */ -#define LAS0_UTC1 0x0064 /* 8254 TC Counter 1 */ -#define LAS0_UTC2 0x0068 /* 8254 TC Counter 2 */ -#define LAS0_UTC_CTRL 0x006c /* 8254 TC Control */ +#define LAS0_8254_TIMER_BASE 0x0060 /* 8254 timer/counter base */ #define LAS0_DIO0 0x0070 /* Digital I/O Port 0 */ #define LAS0_DIO1 0x0074 /* Digital I/O Port 1 */ #define LAS0_DIO0_CTRL 0x0078 /* Digital I/O Control */ @@ -177,16 +172,11 @@ #define LAS0_CGT_PAUSE 0x0144 /* Table Pause Enable */ #define LAS0_CGT_RESET 0x0148 /* Reset Channel Gain Table */ #define LAS0_CGT_CLEAR 0x014c /* Clear Channel Gain Table */ -#define LAS0_DAC1_CTRL 0x0150 /* D/A1 output type/range */ -#define LAS0_DAC1_SRC 0x0154 /* D/A1 update source */ -#define LAS0_DAC1_CYCLE 0x0158 /* D/A1 cycle mode */ -#define LAS0_DAC1_RESET 0x015c /* D/A1 FIFO reset */ -#define LAS0_DAC1_FIFO_CLEAR 0x0160 /* D/A1 FIFO clear */ -#define LAS0_DAC2_CTRL 0x0164 /* D/A2 output type/range */ -#define LAS0_DAC2_SRC 0x0168 /* D/A2 update source */ -#define LAS0_DAC2_CYCLE 0x016c /* D/A2 cycle mode */ -#define LAS0_DAC2_RESET 0x0170 /* D/A2 FIFO reset */ -#define LAS0_DAC2_FIFO_CLEAR 0x0174 /* D/A2 FIFO clear */ +#define LAS0_DAC_CTRL(x) (0x0150 + ((x) * 0x14)) /* D/Ax type/range */ +#define LAS0_DAC_SRC(x) (0x0154 + ((x) * 0x14)) /* D/Ax update source */ +#define LAS0_DAC_CYCLE(x) (0x0158 + ((x) * 0x14)) /* D/Ax cycle mode */ +#define LAS0_DAC_RESET(x) (0x015c + ((x) * 0x14)) /* D/Ax FIFO reset */ +#define LAS0_DAC_FIFO_CLEAR(x) (0x0160 + ((x) * 0x14)) /* D/Ax FIFO clear */ #define LAS0_ADC_SCNT_SRC 0x0178 /* A/D Sample Counter Source select */ #define LAS0_PACER_SELECT 0x0180 /* Pacer Clock select */ #define LAS0_SBUS0_SRC 0x0184 /* SyncBus 0 Source select */ @@ -197,12 +187,8 @@ #define LAS0_SBUS2_ENABLE 0x019c /* SyncBus 2 enable */ #define LAS0_ETRG_POLARITY 0x01a4 /* Ext. Trigger polarity select */ #define LAS0_EINT_POLARITY 0x01a8 /* Ext. Interrupt polarity select */ -#define LAS0_UTC0_CLOCK 0x01ac /* UTC0 Clock select */ -#define LAS0_UTC0_GATE 0x01b0 /* UTC0 Gate select */ -#define LAS0_UTC1_CLOCK 0x01b4 /* UTC1 Clock select */ -#define LAS0_UTC1_GATE 0x01b8 /* UTC1 Gate select */ -#define LAS0_UTC2_CLOCK 0x01bc /* UTC2 Clock select */ -#define LAS0_UTC2_GATE 0x01c0 /* UTC2 Gate select */ +#define LAS0_8254_CLK_SEL(x) (0x01ac + ((x) * 0x8)) /* 8254 clock select */ +#define LAS0_8254_GATE_SEL(x) (0x01b0 + ((x) * 0x8)) /* 8254 gate select */ #define LAS0_UOUT0_SELECT 0x01c4 /* User Output 0 source select */ #define LAS0_UOUT1_SELECT 0x01c8 /* User Output 1 source select */ #define LAS0_DMA0_RESET 0x01cc /* DMA0 Request state machine reset */ @@ -213,15 +199,16 @@ */ #define LAS1_ADC_FIFO 0x0000 /* A/D FIFO (16bit) */ #define LAS1_HDIO_FIFO 0x0004 /* HiSpd DI FIFO (16bit) */ -#define LAS1_DAC1_FIFO 0x0008 /* D/A1 FIFO (16bit) */ -#define LAS1_DAC2_FIFO 0x000c /* D/A2 FIFO (16bit) */ +#define LAS1_DAC_FIFO(x) (0x0008 + ((x) * 0x4)) /* D/Ax FIFO (16bit) */ -/*====================================================================== - Driver specific stuff (tunable) -======================================================================*/ +/* + * Driver specific stuff (tunable) + */ -/* We really only need 2 buffers. More than that means being much - smarter about knowing which ones are full. */ +/* + * We really only need 2 buffers. More than that means being much + * smarter about knowing which ones are full. + */ #define DMA_CHAIN_COUNT 2 /* max DMA segments/buffers in a ring (min 2) */ /* Target period for periodic transfers. This sets the user read latency. */ @@ -233,9 +220,9 @@ /* The board support a channel list up to the FIFO length (1K or 8K) */ #define RTD_MAX_CHANLIST 128 /* max channel list that we allow */ -/*====================================================================== - Board specific stuff -======================================================================*/ +/* + * Board specific stuff + */ #define RTD_CLOCK_RATE 8000000 /* 8Mhz onboard clock */ #define RTD_CLOCK_BASE 125 /* clock period in ns */ @@ -264,9 +251,9 @@ /* interrupt at end of block */ | PLX_INTR_TERM_COUNT \ /* from board to PCI */ | PLX_XFER_LOCAL_TO_PCI) -/*====================================================================== - Comedi specific stuff -======================================================================*/ +/* + * Comedi specific stuff + */ /* * The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128) @@ -352,7 +339,7 @@ struct rtd_boardinfo { const struct comedi_lrange *ai_range; }; -static const struct rtd_boardinfo rtd520Boards[] = { +static const struct rtd_boardinfo rtd520_boards[] = { [BOARD_DM7520] = { .name = "DM7520", .range_bip10 = 6, @@ -376,6 +363,10 @@ struct rtd_private { int xfer_count; /* # to transfer data. 0->1/2FIFO */ int flags; /* flag event modes */ unsigned fifosz; + + /* 8254 Timer/Counter gate and clock sources */ + unsigned char timer_gate_src[3]; + unsigned char timer_clk_src[3]; }; /* bit defines for "flags" */ @@ -384,11 +375,11 @@ struct rtd_private { #define DMA1_ACTIVE 0x04 /* DMA1 is active */ /* - Given a desired period and the clock period (both in ns), - return the proper counter value (divider-1). - Sets the original period to be the true value. - Note: you have to check if the value is larger than the counter range! -*/ + * Given a desired period and the clock period (both in ns), return the + * proper counter value (divider-1). Sets the original period to be the + * true value. + * Note: you have to check if the value is larger than the counter range! + */ static int rtd_ns_to_timer_base(unsigned int *nanosec, unsigned int flags, int base) { @@ -397,38 +388,38 @@ static int rtd_ns_to_timer_base(unsigned int *nanosec, 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; } if (divider < 2) divider = 2; /* min is divide by 2 */ - /* Note: we don't check for max, because different timers - have different ranges */ + /* + * Note: we don't check for max, because different timers + * have different ranges + */ *nanosec = base * divider; return divider - 1; /* countdown is divisor+1 */ } /* - Given a desired period (in ns), - return the proper counter value (divider-1) for the internal clock. - Sets the original period to be the true value. -*/ + * Given a desired period (in ns), return the proper counter value + * (divider-1) for the internal clock. Sets the original period to + * be the true value. + */ static int rtd_ns_to_timer(unsigned int *ns, unsigned int flags) { return rtd_ns_to_timer_base(ns, flags, RTD_CLOCK_BASE); } -/* - Convert a single comedi channel-gain entry to a RTD520 table entry -*/ +/* Convert a single comedi channel-gain entry to a RTD520 table entry */ static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, unsigned int chanspec, int index) { @@ -473,9 +464,7 @@ static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, return r; } -/* - Setup the channel-gain table from a comedi list -*/ +/* Setup the channel-gain table from a comedi list */ static void rtd_load_channelgain_list(struct comedi_device *dev, unsigned int n_chan, unsigned int *list) { @@ -495,8 +484,10 @@ static void rtd_load_channelgain_list(struct comedi_device *dev, } } -/* determine fifo size by doing adc conversions until the fifo half -empty status flag clears */ +/* + * Determine fifo size by doing adc conversions until the fifo half + * empty status flag clears. + */ static int rtd520_probe_fifo_depth(struct comedi_device *dev) { unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND); @@ -513,7 +504,7 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) unsigned fifo_status; /* trigger conversion */ writew(0, dev->mmio + LAS0_ADC); - udelay(1); + usleep_range(1, 1000); fifo_status = readl(dev->mmio + LAS0_ADC); if ((fifo_status & FS_ADC_HEMPTY) == 0) { fifo_size = 2 * i; @@ -590,12 +581,6 @@ static int rtd_ai_rinsn(struct comedi_device *dev, return n; } -/* - Get what we know is there.... Fast! - This uses 1/2 the bus cycles of read_dregs (below). - - The manual claims that we can do a lword read, but it doesn't work here. -*/ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, int count) { @@ -608,7 +593,7 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int range = CR_RANGE(cmd->chanlist[async->cur_chan]); unsigned short d; - if (0 == devpriv->ai_count) { /* done */ + if (devpriv->ai_count == 0) { /* done */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); continue; } @@ -630,12 +615,6 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* - Handle all rtd520 interrupts. - Runs atomically and is never re-entered. - This is a "slow handler"; other interrupts may be active. - The data conversion may someday happen in a "bottom half". -*/ static irqreturn_t rtd_interrupt(int irq, void *d) { struct comedi_device *dev = d; @@ -655,7 +634,7 @@ static irqreturn_t rtd_interrupt(int irq, void *d) status = readw(dev->mmio + LAS0_IT); /* if interrupt was not caused by our board, or handled above */ - if (0 == status) + if (status == 0) return IRQ_HANDLED; if (status & IRQM_ADC_ABOUT_CNT) { /* sample count -> read FIFO */ @@ -670,7 +649,7 @@ static irqreturn_t rtd_interrupt(int irq, void *d) if (ai_read_n(dev, s, devpriv->fifosz / 2) < 0) goto xfer_abort; - if (0 == devpriv->ai_count) + if (devpriv->ai_count == 0) goto xfer_done; } else if (devpriv->xfer_count > 0) { if (fifo_status & FS_ADC_NOT_EMPTY) { @@ -678,7 +657,7 @@ static irqreturn_t rtd_interrupt(int irq, void *d) if (ai_read_n(dev, s, devpriv->xfer_count) < 0) goto xfer_abort; - if (0 == devpriv->ai_count) + if (devpriv->ai_count == 0) goto xfer_done; } } @@ -715,15 +694,6 @@ xfer_done: return IRQ_HANDLED; } -/* - cmdtest tests a particular command to see if it is valid. - Using the cmdtest ioctl, a user can create a valid cmd - and then have it executed by the cmd ioctl (asynchronously). - - cmdtest returns 1,2,3,4 or 0, depending on which tests - the command passes. -*/ - static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -760,7 +730,7 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) { /* Note: these are time periods, not actual rates */ - if (1 == cmd->chanlist_len) { /* no scanning */ + if (cmd->chanlist_len == 1) { /* no scanning */ if (comedi_check_trigger_arg_min(&cmd->scan_begin_arg, RTD_MAX_SPEED_1)) { rtd_ns_to_timer(&cmd->scan_begin_arg, @@ -795,7 +765,7 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, } if (cmd->convert_src == TRIG_TIMER) { - if (1 == cmd->chanlist_len) { /* no scanning */ + if (cmd->chanlist_len == 1) { /* no scanning */ if (comedi_check_trigger_arg_min(&cmd->convert_arg, RTD_MAX_SPEED_1)) { rtd_ns_to_timer(&cmd->convert_arg, @@ -866,12 +836,6 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, return 0; } -/* - Execute a analog in command with many possible triggering options. - The data get stored in the async structure of the subdevice. - This is usually done by an interrupt handler. - Userland gets to the data using read calls. -*/ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct rtd_private *devpriv = dev->private; @@ -907,7 +871,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } writel((devpriv->fifosz / 2 - 1) & 0xffff, dev->mmio + LAS0_ACNT); - if (TRIG_TIMER == cmd->scan_begin_src) { + if (cmd->scan_begin_src == TRIG_TIMER) { /* scan_begin_arg is in nanoseconds */ /* find out how many samples to wait before transferring */ if (cmd->flags & CMDF_WAKE_EOS) { @@ -959,8 +923,8 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) switch (cmd->stop_src) { case TRIG_COUNT: /* stop after N scans */ devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len; - if ((devpriv->xfer_count > 0) - && (devpriv->xfer_count > devpriv->ai_count)) { + if ((devpriv->xfer_count > 0) && + (devpriv->xfer_count > devpriv->ai_count)) { devpriv->xfer_count = devpriv->ai_count; } break; @@ -1006,8 +970,10 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* end configuration */ - /* This doesn't seem to work. There is no way to clear an interrupt - that the priority controller has queued! */ + /* + * This doesn't seem to work. There is no way to clear an interrupt + * that the priority controller has queued! + */ writew(~0, dev->mmio + LAS0_CLEAR); readw(dev->mmio + LAS0_CLEAR); @@ -1021,9 +987,6 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* - Stop a running data acquisition. -*/ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct rtd_private *devpriv = dev->private; @@ -1053,49 +1016,43 @@ static int rtd_ao_eoc(struct comedi_device *dev, return -EBUSY; } -static int rtd_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int rtd_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct rtd_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - int range = CR_RANGE(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); int ret; + int i; /* Configure the output range (table index matches the range values) */ - writew(range & 7, - dev->mmio + ((chan == 0) ? LAS0_DAC1_CTRL : LAS0_DAC2_CTRL)); + writew(range & 7, dev->mmio + LAS0_DAC_CTRL(chan)); - /* Writing a list of values to an AO channel is probably not - * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; ++i) { - int val = data[i] << 3; + unsigned int val = data[i]; - /* VERIFY: comedi range and offset conversions */ - - if ((range > 1) /* bipolar */ - && (data[i] < 2048)) { - /* offset and sign extend */ - val = (((int)data[i]) - 2048) << 3; - } else { /* unipolor */ - val = data[i] << 3; + /* bipolar uses 2's complement values with an extended sign */ + if (comedi_range_is_bipolar(s, range)) { + val = comedi_offset_munge(s, val); + val |= (val & ((s->maxdata + 1) >> 1)) << 1; } - /* a typical programming sequence */ - writew(val, devpriv->las1 + - ((chan == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO)); - writew(0, dev->mmio + ((chan == 0) ? LAS0_DAC1 : LAS0_DAC2)); + /* shift the 12-bit data (+ sign) to match the register */ + val <<= 3; - s->readback[chan] = data[i]; + writew(val, devpriv->las1 + LAS1_DAC_FIFO(chan)); + writew(0, dev->mmio + LAS0_UPDATE_DAC(chan)); ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0); if (ret) return ret; + + s->readback[chan] = data[i]; } - /* return the number of samples read/written */ - return i; + return insn->n; } static int rtd_dio_insn_bits(struct comedi_device *dev, @@ -1138,12 +1095,87 @@ static int rtd_dio_insn_config(struct comedi_device *dev, return insn->n; } +static int rtd_counter_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct rtd_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int max_src; + unsigned int src; + + switch (data[0]) { + case INSN_CONFIG_SET_GATE_SRC: + /* + * 8254 Timer/Counter gate sources: + * + * 0 = Not gated, free running (reset state) + * 1 = Gated, off + * 2 = Ext. TC Gate 1 + * 3 = Ext. TC Gate 2 + * 4 = Previous TC out (chan 1 and 2 only) + */ + src = data[2]; + max_src = (chan == 0) ? 3 : 4; + if (src > max_src) + return -EINVAL; + + devpriv->timer_gate_src[chan] = src; + writeb(src, dev->mmio + LAS0_8254_GATE_SEL(chan)); + break; + case INSN_CONFIG_GET_GATE_SRC: + data[2] = devpriv->timer_gate_src[chan]; + break; + case INSN_CONFIG_SET_CLOCK_SRC: + /* + * 8254 Timer/Counter clock sources: + * + * 0 = 8 MHz (reset state) + * 1 = Ext. TC Clock 1 + * 2 = Ext. TX Clock 2 + * 3 = Ext. Pacer Clock + * 4 = Previous TC out (chan 1 and 2 only) + * 5 = High-Speed Digital Input Sampling signal (chan 1 only) + */ + src = data[1]; + switch (chan) { + case 0: + max_src = 3; + break; + case 1: + max_src = 5; + break; + case 2: + max_src = 4; + break; + default: + return -EINVAL; + } + if (src > max_src) + return -EINVAL; + + devpriv->timer_clk_src[chan] = src; + writeb(src, dev->mmio + LAS0_8254_CLK_SEL(chan)); + break; + case INSN_CONFIG_GET_CLOCK_SRC: + src = devpriv->timer_clk_src[chan]; + data[1] = devpriv->timer_clk_src[chan]; + data[2] = (src == 0) ? RTD_CLOCK_BASE : 0; + break; + default: + return -EINVAL; + } + + return insn->n; +} + static void rtd_reset(struct comedi_device *dev) { struct rtd_private *devpriv = dev->private; writel(0, dev->mmio + LAS0_BOARD_RESET); - udelay(100); /* needed? */ + usleep_range(100, 1000); /* needed? */ writel(0, devpriv->lcfg + PLX_INTRCS_REG); writew(0, dev->mmio + LAS0_IT); writew(~0, dev->mmio + LAS0_CLEAR); @@ -1161,14 +1193,10 @@ static void rtd_init_board(struct comedi_device *dev) writel(0, dev->mmio + LAS0_OVERRUN); writel(0, dev->mmio + LAS0_CGT_CLEAR); writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR); - writel(0, dev->mmio + LAS0_DAC1_RESET); - writel(0, dev->mmio + LAS0_DAC2_RESET); + writel(0, dev->mmio + LAS0_DAC_RESET(0)); + writel(0, dev->mmio + LAS0_DAC_RESET(1)); /* clear digital IO fifo */ writew(0, dev->mmio + LAS0_DIO_STATUS); - writeb((0 << 6) | 0x30, dev->mmio + LAS0_UTC_CTRL); - writeb((1 << 6) | 0x30, dev->mmio + LAS0_UTC_CTRL); - writeb((2 << 6) | 0x30, dev->mmio + LAS0_UTC_CTRL); - writeb((3 << 6) | 0x00, dev->mmio + LAS0_UTC_CTRL); /* TODO: set user out source ??? */ } @@ -1196,8 +1224,8 @@ static int rtd_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - if (context < ARRAY_SIZE(rtd520Boards)) - board = &rtd520Boards[context]; + if (context < ARRAY_SIZE(rtd520_boards)) + board = &rtd520_boards[context]; if (!board) return -ENODEV; dev->board_ptr = board; @@ -1254,7 +1282,7 @@ static int rtd_auto_attach(struct comedi_device *dev, s->n_chan = 2; s->maxdata = 0x0fff; s->range_table = &rtd_ao_range; - s->insn_write = rtd_ao_winsn; + s->insn_write = rtd_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) @@ -1271,12 +1299,15 @@ static int rtd_auto_attach(struct comedi_device *dev, s->insn_bits = rtd_dio_insn_bits; s->insn_config = rtd_dio_insn_config; - /* timer/counter subdevices (not currently supported) */ + /* 8254 Timer/Counter subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 3; - s->maxdata = 0xffff; + dev->pacer = comedi_8254_mm_init(dev->mmio + LAS0_8254_TIMER_BASE, + RTD_CLOCK_BASE, I8254_IO8, 2); + if (!dev->pacer) + return -ENOMEM; + + comedi_8254_subdevice_init(s, dev->pacer); + dev->pacer->insn_config = rtd_counter_insn_config; rtd_init_board(dev); diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index 340ac776e..cd61d2645 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -57,14 +57,14 @@ * Register map */ #define RTI800_CSR 0x00 -#define RTI800_CSR_BUSY (1 << 7) -#define RTI800_CSR_DONE (1 << 6) -#define RTI800_CSR_OVERRUN (1 << 5) -#define RTI800_CSR_TCR (1 << 4) -#define RTI800_CSR_DMA_ENAB (1 << 3) -#define RTI800_CSR_INTR_TC (1 << 2) -#define RTI800_CSR_INTR_EC (1 << 1) -#define RTI800_CSR_INTR_OVRN (1 << 0) +#define RTI800_CSR_BUSY BIT(7) +#define RTI800_CSR_DONE BIT(6) +#define RTI800_CSR_OVERRUN BIT(5) +#define RTI800_CSR_TCR BIT(4) +#define RTI800_CSR_DMA_ENAB BIT(3) +#define RTI800_CSR_INTR_TC BIT(2) +#define RTI800_CSR_INTR_EC BIT(1) +#define RTI800_CSR_INTR_OVRN BIT(0) #define RTI800_MUXGAIN 0x01 #define RTI800_CONVERT 0x02 #define RTI800_ADCLO 0x03 @@ -189,17 +189,21 @@ static int rti800_ai_insn_read(struct comedi_device *dev, } for (i = 0; i < insn->n; i++) { + unsigned int val; + outb(0, dev->iobase + RTI800_CONVERT); ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0); if (ret) return ret; - data[i] = inb(dev->iobase + RTI800_ADCLO); - data[i] |= (inb(dev->iobase + RTI800_ADCHI) & 0xf) << 8; + val = inb(dev->iobase + RTI800_ADCLO); + val |= (inb(dev->iobase + RTI800_ADCHI) & 0xf) << 8; if (devpriv->adc_2comp) - data[i] ^= 0x800; + val = comedi_offset_munge(s, val); + + data[i] = val; } return insn->n; @@ -222,7 +226,7 @@ static int rti800_ao_insn_write(struct comedi_device *dev, s->readback[chan] = val; if (devpriv->dac_2comp[chan]) - val ^= 0x800; + val = comedi_offset_munge(s, val); outb(val & 0xff, dev->iobase + reg_lo); outb((val >> 8) & 0xff, dev->iobase + reg_hi); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 6f3e8a08e..d70c97947 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -1,79 +1,96 @@ /* - comedi/drivers/s526.c - Sensoray s526 Comedi driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - 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: s526 -Description: Sensoray 526 driver -Devices: [Sensoray] 526 (s526) -Author: Richie - Everett Wang -Updated: Thu, 14 Sep. 2006 -Status: experimental - -Encoder works -Analog input works -Analog output works -PWM output works -Commands are not supported yet. - -Configuration Options: + * s526.c + * Sensoray s526 Comedi driver + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * 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_config /dev/comedi0 s526 0x2C0,0x3 - -*/ +/* + * Driver: s526 + * Description: Sensoray 526 driver + * Devices: [Sensoray] 526 (s526) + * Author: Richie + * Everett Wang + * Updated: Thu, 14 Sep. 2006 + * Status: experimental + * + * Encoder works + * Analog input works + * Analog output works + * PWM output works + * Commands are not supported yet. + * + * Configuration Options: + * [0] - I/O port base address + */ #include #include "../comedidev.h" #include -#define S526_START_AI_CONV 0 -#define S526_AI_READ 0 - -/* Ports */ -#define S526_NUM_PORTS 27 - -/* registers */ -#define REG_TCR 0x00 -#define REG_WDC 0x02 -#define REG_DAC 0x04 -#define REG_ADC 0x06 -#define REG_ADD 0x08 -#define REG_DIO 0x0A -#define REG_IER 0x0C -#define REG_ISR 0x0E -#define REG_MSC 0x10 -#define REG_C0L 0x12 -#define REG_C0H 0x14 -#define REG_C0M 0x16 -#define REG_C0C 0x18 -#define REG_C1L 0x1A -#define REG_C1H 0x1C -#define REG_C1M 0x1E -#define REG_C1C 0x20 -#define REG_C2L 0x22 -#define REG_C2H 0x24 -#define REG_C2M 0x26 -#define REG_C2C 0x28 -#define REG_C3L 0x2A -#define REG_C3H 0x2C -#define REG_C3M 0x2E -#define REG_C3C 0x30 -#define REG_EED 0x32 -#define REG_EEC 0x34 +/* + * Register I/O map + */ +#define S526_TIMER_REG 0x00 +#define S526_TIMER_LOAD(x) (((x) & 0xff) << 8) +#define S526_TIMER_MODE ((x) << 1) +#define S526_TIMER_MANUAL S526_TIMER_MODE(0) +#define S526_TIMER_AUTO S526_TIMER_MODE(1) +#define S526_TIMER_RESTART BIT(0) +#define S526_WDOG_REG 0x02 +#define S526_WDOG_INVERTED BIT(4) +#define S526_WDOG_ENA BIT(3) +#define S526_WDOG_INTERVAL(x) (((x) & 0x7) << 0) +#define S526_AO_CTRL_REG 0x04 +#define S526_AO_CTRL_RESET BIT(3) +#define S526_AO_CTRL_CHAN(x) (((x) & 0x3) << 1) +#define S526_AO_CTRL_START BIT(0) +#define S526_AI_CTRL_REG 0x06 +#define S526_AI_CTRL_DELAY BIT(15) +#define S526_AI_CTRL_CONV(x) (1 << (5 + ((x) & 0x9))) +#define S526_AI_CTRL_READ(x) (((x) & 0xf) << 1) +#define S526_AI_CTRL_START BIT(0) +#define S526_AO_REG 0x08 +#define S526_AI_REG 0x08 +#define S526_DIO_CTRL_REG 0x0a +#define S526_DIO_CTRL_DIO3_NEG BIT(15) /* irq on DIO3 neg/pos edge */ +#define S526_DIO_CTRL_DIO2_NEG BIT(14) /* irq on DIO2 neg/pos edge */ +#define S526_DIO_CTRL_DIO1_NEG BIT(13) /* irq on DIO1 neg/pos edge */ +#define S526_DIO_CTRL_DIO0_NEG BIT(12) /* irq on DIO0 neg/pos edge */ +#define S526_DIO_CTRL_GRP2_OUT BIT(11) +#define S526_DIO_CTRL_GRP1_OUT BIT(10) +#define S526_DIO_CTRL_GRP2_NEG BIT(8) /* irq on DIO[4-7] neg/pos edge */ +#define S526_INT_ENA_REG 0x0c +#define S526_INT_STATUS_REG 0x0e +#define S526_INT_DIO(x) BIT(8 + ((x) & 0x7)) +#define S526_INT_EEPROM BIT(7) /* status only */ +#define S526_INT_CNTR(x) BIT(3 + (3 - ((x) & 0x3))) +#define S526_INT_AI BIT(2) +#define S526_INT_AO BIT(1) +#define S526_INT_TIMER BIT(0) +#define S526_MISC_REG 0x10 +#define S526_MISC_LED_OFF BIT(0) +#define S526_GPCT_LSB_REG(x) (0x12 + ((x) * 8)) +#define S526_GPCT_MSB_REG(x) (0x14 + ((x) * 8)) +#define S526_GPCT_MODE_REG(x) (0x16 + ((x) * 8)) +#define S526_GPCT_CTRL_REG(x) (0x18 + ((x) * 8)) +#define S526_EEPROM_DATA_REG 0x32 +#define S526_EEPROM_CTRL_REG 0x34 +#define S526_EEPROM_CTRL_ADDR(x) (((x) & 0x3f) << 3) +#define S526_EEPROM_CTRL(x) (((x) & 0x3) << 1) +#define S526_EEPROM_CTRL_READ S526_EEPROM_CTRL(2) +#define S526_EEPROM_CTRL_START BIT(0) struct counter_mode_register_t { #if defined(__LITTLE_ENDIAN_BITFIELD) @@ -112,27 +129,39 @@ union cmReg { struct s526_private { unsigned int gpct_config[4]; - unsigned short ai_config; + unsigned short ai_ctrl; }; +static void s526_gpct_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) +{ + /* write high word then low word */ + outw((val >> 16) & 0xffff, dev->iobase + S526_GPCT_MSB_REG(chan)); + outw(val & 0xffff, dev->iobase + S526_GPCT_LSB_REG(chan)); +} + +static unsigned int s526_gpct_read(struct comedi_device *dev, + unsigned int chan) +{ + unsigned int val; + + /* read the low word then high word */ + val = inw(dev->iobase + S526_GPCT_LSB_REG(chan)) & 0xffff; + val |= (inw(dev->iobase + S526_GPCT_MSB_REG(chan)) & 0xff) << 16; + + return val; +} + static int s526_gpct_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned long chan_iobase = dev->iobase + chan * 8; - unsigned int lo; - unsigned int hi; int i; - for (i = 0; i < insn->n; i++) { - /* Read the low word first */ - lo = inw(chan_iobase + REG_C0L) & 0xffff; - hi = inw(chan_iobase + REG_C0H) & 0xff; - - data[i] = (hi << 16) | lo; - } + for (i = 0; i < insn->n; i++) + data[i] = s526_gpct_read(dev, chan); return insn->n; } @@ -144,63 +173,34 @@ static int s526_gpct_insn_config(struct comedi_device *dev, { struct s526_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned long chan_iobase = dev->iobase + chan * 8; unsigned int val; union cmReg cmReg; - /* Check what type of Counter the user requested, data[0] contains */ - /* the Application type */ + /* + * Check what type of Counter the user requested + * data[0] contains the Application type + */ switch (data[0]) { case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: /* - data[0]: Application Type - data[1]: Counter Mode Register Value - data[2]: Pre-load Register Value - data[3]: Conter Control Register + * data[0]: Application Type + * data[1]: Counter Mode Register Value + * data[2]: Pre-load Register Value + * data[3]: Conter Control Register */ devpriv->gpct_config[chan] = data[0]; -#if 0 - /* Example of Counter Application */ - /* One-shot (software trigger) */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 1; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 0;/* Auto load disabled */ - cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 2; /* Hardware */ - cmReg.reg.clockSource = 2; /* Internal */ - cmReg.reg.countDir = 1; /* Down */ - cmReg.reg.countDirCtrl = 1; /* Software */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - outw(cmReg.value, chan_iobase + REG_C0M); - - outw(0x0001, chan_iobase + REG_C0H); - outw(0x3C68, chan_iobase + REG_C0L); - - /* Reset the counter */ - outw(0x8000, chan_iobase + REG_C0C); - /* Load the counter from PR0 */ - outw(0x4000, chan_iobase + REG_C0C); - - /* Reset RCAP (fires one-shot) */ - outw(0x0008, chan_iobase + REG_C0C); - -#endif - #if 1 /* Set Counter Mode Register */ cmReg.value = data[1] & 0xffff; - outw(cmReg.value, chan_iobase + REG_C0M); + outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan)); /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, chan_iobase + REG_C0C); + outw(0x8000, dev->iobase + S526_GPCT_CTRL_REG(chan)); /* Load the counter from PR0 - * outw(0x4000, chan_iobase + REG_C0C); + * outw(0x4000, dev->iobase + S526_GPCT_CTRL_REG(chan)); */ } #else @@ -216,11 +216,13 @@ static int s526_gpct_insn_config(struct comedi_device *dev, cmReg.reg.clockSource = 0; /* When to take into account the indexpulse: */ - /*if (data[2] == GPCT_IndexPhaseLowLow) { - } else if (data[2] == GPCT_IndexPhaseLowHigh) { - } else if (data[2] == GPCT_IndexPhaseHighLow) { - } else if (data[2] == GPCT_IndexPhaseHighHigh) { - }*/ + /* + * if (data[2] == GPCT_IndexPhaseLowLow) { + * } else if (data[2] == GPCT_IndexPhaseLowHigh) { + * } else if (data[2] == GPCT_IndexPhaseHighLow) { + * } else if (data[2] == GPCT_IndexPhaseHighHigh) { + * } + */ /* Take into account the index pulse? */ if (data[3] == GPCT_RESET_COUNTER_ON_INDEX) /* Auto load with INDEX^ */ @@ -228,114 +230,89 @@ static int s526_gpct_insn_config(struct comedi_device *dev, /* Set Counter Mode Register */ cmReg.value = data[1] & 0xffff; - outw(cmReg.value, chan_iobase + REG_C0M); - - /* Load the pre-load register high word */ - val = (data[2] >> 16) & 0xffff; - outw(val, chan_iobase + REG_C0H); + outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan)); - /* Load the pre-load register low word */ - val = data[2] & 0xffff; - outw(val, chan_iobase + REG_C0L); + /* Load the pre-load register */ + s526_gpct_write(dev, chan, data[2]); /* Write the Counter Control Register */ - if (data[3]) { - val = data[3] & 0xffff; - outw(val, chan_iobase + REG_C0C); - } + if (data[3]) + outw(data[3] & 0xffff, + dev->iobase + S526_GPCT_CTRL_REG(chan)); + /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, chan_iobase + REG_C0C); + outw(0x8000, dev->iobase + S526_GPCT_CTRL_REG(chan)); /* Load the counter from PR0 */ - outw(0x4000, chan_iobase + REG_C0C); + outw(0x4000, dev->iobase + S526_GPCT_CTRL_REG(chan)); } #endif break; case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR: /* - data[0]: Application Type - data[1]: Counter Mode Register Value - data[2]: Pre-load Register 0 Value - data[3]: Pre-load Register 1 Value - data[4]: Conter Control Register + * data[0]: Application Type + * data[1]: Counter Mode Register Value + * data[2]: Pre-load Register 0 Value + * data[3]: Pre-load Register 1 Value + * data[4]: Conter Control Register */ devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, chan_iobase + REG_C0M); + outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan)); - /* Load the pre-load register 0 high word */ - val = (data[2] >> 16) & 0xffff; - outw(val, chan_iobase + REG_C0H); - - /* Load the pre-load register 0 low word */ - val = data[2] & 0xffff; - outw(val, chan_iobase + REG_C0L); + /* Load the pre-load register 0 */ + s526_gpct_write(dev, chan, data[2]); /* Set Counter Mode Register */ cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, chan_iobase + REG_C0M); - - /* Load the pre-load register 1 high word */ - val = (data[3] >> 16) & 0xffff; - outw(val, chan_iobase + REG_C0H); + outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan)); - /* Load the pre-load register 1 low word */ - val = data[3] & 0xffff; - outw(val, chan_iobase + REG_C0L); + /* Load the pre-load register 1 */ + s526_gpct_write(dev, chan, data[3]); /* Write the Counter Control Register */ if (data[4]) { val = data[4] & 0xffff; - outw(val, chan_iobase + REG_C0C); + outw(val, dev->iobase + S526_GPCT_CTRL_REG(chan)); } break; case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR: /* - data[0]: Application Type - data[1]: Counter Mode Register Value - data[2]: Pre-load Register 0 Value - data[3]: Pre-load Register 1 Value - data[4]: Conter Control Register + * data[0]: Application Type + * data[1]: Counter Mode Register Value + * data[2]: Pre-load Register 0 Value + * data[3]: Pre-load Register 1 Value + * data[4]: Conter Control Register */ devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, chan_iobase + REG_C0M); + outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan)); - /* Load the pre-load register 0 high word */ - val = (data[2] >> 16) & 0xffff; - outw(val, chan_iobase + REG_C0H); - - /* Load the pre-load register 0 low word */ - val = data[2] & 0xffff; - outw(val, chan_iobase + REG_C0L); + /* Load the pre-load register 0 */ + s526_gpct_write(dev, chan, data[2]); /* Set Counter Mode Register */ cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, chan_iobase + REG_C0M); - - /* Load the pre-load register 1 high word */ - val = (data[3] >> 16) & 0xffff; - outw(val, chan_iobase + REG_C0H); + outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan)); - /* Load the pre-load register 1 low word */ - val = data[3] & 0xffff; - outw(val, chan_iobase + REG_C0L); + /* Load the pre-load register 1 */ + s526_gpct_write(dev, chan, data[3]); /* Write the Counter Control Register */ if (data[4]) { val = data[4] & 0xffff; - outw(val, chan_iobase + REG_C0C); + outw(val, dev->iobase + S526_GPCT_CTRL_REG(chan)); } break; @@ -353,18 +330,18 @@ static int s526_gpct_winsn(struct comedi_device *dev, { struct s526_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned long chan_iobase = dev->iobase + chan * 8; - inw(chan_iobase + REG_C0M); /* Is this read required? */ + inw(dev->iobase + S526_GPCT_MODE_REG(chan)); /* Is this required? */ /* Check what Application of Counter this channel is configured for */ switch (devpriv->gpct_config[chan]) { case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR: - /* data[0] contains the PULSE_WIDTH - data[1] contains the PULSE_PERIOD - @pre PULSE_PERIOD > PULSE_WIDTH > 0 - The above periods must be expressed as a multiple of the - pulse frequency on the selected source + /* + * data[0] contains the PULSE_WIDTH + * data[1] contains the PULSE_PERIOD + * @pre PULSE_PERIOD > PULSE_WIDTH > 0 + * The above periods must be expressed as a multiple of the + * pulse frequency on the selected source */ if ((data[1] <= data[0]) || !data[0]) return -EINVAL; @@ -373,8 +350,7 @@ static int s526_gpct_winsn(struct comedi_device *dev, case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR: - outw((data[0] >> 16) & 0xffff, chan_iobase + REG_C0H); - outw(data[0] & 0xffff, chan_iobase + REG_C0L); + s526_gpct_write(dev, chan, data[0]); break; default: @@ -384,86 +360,60 @@ static int s526_gpct_winsn(struct comedi_device *dev, return insn->n; } -#define ISR_ADC_DONE 0x4 -static int s526_ai_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct s526_private *devpriv = dev->private; - int result = -EINVAL; - - if (insn->n < 1) - return result; - - result = insn->n; - - /* data[0] : channels was set in relevant bits. - data[1] : delay - */ - /* COMMENT: abbotti 2008-07-24: I don't know why you'd want to - * enable channels here. The channel should be enabled in the - * INSN_READ handler. */ - - /* Enable ADC interrupt */ - outw(ISR_ADC_DONE, dev->iobase + REG_IER); - devpriv->ai_config = (data[0] & 0x3ff) << 5; - if (data[1] > 0) - devpriv->ai_config |= 0x8000; /* set the delay */ - - devpriv->ai_config |= 0x0001; /* ADC start bit */ - - return result; -} - -static int s526_ai_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned long context) +static int s526_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; - status = inw(dev->iobase + REG_ISR); - if (status & ISR_ADC_DONE) + status = inw(dev->iobase + S526_INT_STATUS_REG); + if (status & context) { + /* we got our eoc event, clear it */ + outw(context, dev->iobase + S526_INT_STATUS_REG); return 0; + } return -EBUSY; } -static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int s526_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct s526_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - int n; - unsigned short value; - unsigned int d; + unsigned int ctrl; + unsigned int val; int ret; + int i; - /* Set configured delay, enable channel for this channel only, - * select "ADC read" channel, set "ADC start" bit. */ - value = (devpriv->ai_config & 0x8000) | - ((1 << 5) << chan) | (chan << 1) | 0x0001; + ctrl = S526_AI_CTRL_CONV(chan) | S526_AI_CTRL_READ(chan) | + S526_AI_CTRL_START; + if (ctrl != devpriv->ai_ctrl) { + /* + * The multiplexor needs to change, enable the 15us + * delay for the first sample. + */ + devpriv->ai_ctrl = ctrl; + ctrl |= S526_AI_CTRL_DELAY; + } - /* convert n samples */ - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { /* trigger conversion */ - outw(value, dev->iobase + REG_ADC); + outw(ctrl, dev->iobase + S526_AI_CTRL_REG); + ctrl &= ~S526_AI_CTRL_DELAY; /* wait for conversion to end */ - ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0); + ret = comedi_timeout(dev, s, insn, s526_eoc, S526_INT_AI); if (ret) return ret; - outw(ISR_ADC_DONE, dev->iobase + REG_ISR); - - /* read data */ - d = inw(dev->iobase + REG_ADD); - - /* munge data */ - data[n] = d ^ 0x8000; + val = inw(dev->iobase + S526_AI_REG); + data[i] = comedi_offset_munge(s, val); } - /* return the number of samples read/written */ - return n; + return insn->n; } static int s526_ao_insn_write(struct comedi_device *dev, @@ -472,16 +422,23 @@ static int s526_ao_insn_write(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int ctrl = S526_AO_CTRL_CHAN(chan); unsigned int val = s->readback[chan]; + int ret; int i; - outw(chan << 1, dev->iobase + REG_DAC); + outw(ctrl, dev->iobase + S526_AO_CTRL_REG); + ctrl |= S526_AO_CTRL_START; for (i = 0; i < insn->n; i++) { val = data[i]; - outw(val, dev->iobase + REG_ADD); - /* starts the D/A conversion */ - outw((chan << 1) | 1, dev->iobase + REG_DAC); + outw(val, dev->iobase + S526_AO_REG); + outw(ctrl, dev->iobase + S526_AO_CTRL_REG); + + /* wait for conversion to end */ + ret = comedi_timeout(dev, s, insn, s526_eoc, S526_INT_AO); + if (ret) + return ret; } s->readback[chan] = val; @@ -494,9 +451,9 @@ static int s526_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outw(s->state, dev->iobase + REG_DIO); + outw(s->state, dev->iobase + S526_DIO_CTRL_REG); - data[1] = inw(dev->iobase + REG_DIO) & 0xff; + data[1] = inw(dev->iobase + S526_DIO_CTRL_REG) & 0xff; return insn->n; } @@ -510,6 +467,10 @@ static int s526_dio_insn_config(struct comedi_device *dev, unsigned int mask; int ret; + /* + * Digital I/O can be configured as inputs or outputs in + * groups of 4; DIO group 1 (DIO0-3) and DIO group 2 (DIO4-7). + */ if (chan < 4) mask = 0x0f; else @@ -519,17 +480,16 @@ static int s526_dio_insn_config(struct comedi_device *dev, if (ret) return ret; - /* bit 10/11 set the group 1/2's mode */ if (s->io_bits & 0x0f) - s->state |= (1 << 10); + s->state |= S526_DIO_CTRL_GRP1_OUT; else - s->state &= ~(1 << 10); + s->state &= ~S526_DIO_CTRL_GRP1_OUT; if (s->io_bits & 0xf0) - s->state |= (1 << 11); + s->state |= S526_DIO_CTRL_GRP2_OUT; else - s->state &= ~(1 << 11); + s->state &= ~S526_DIO_CTRL_GRP2_OUT; - outw(s->state, dev->iobase + REG_DIO); + outw(s->state, dev->iobase + S526_DIO_CTRL_REG); return insn->n; } @@ -552,51 +512,53 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; + /* General-Purpose Counter/Timer (GPCT) */ s = &dev->subdevices[0]; - /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; - s->n_chan = 4; - s->maxdata = 0x00ffffff; /* 24 bit counter */ - s->insn_read = s526_gpct_rinsn; - s->insn_config = s526_gpct_insn_config; - s->insn_write = s526_gpct_winsn; - + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; + s->n_chan = 4; + s->maxdata = 0x00ffffff; + s->insn_read = s526_gpct_rinsn; + s->insn_config = s526_gpct_insn_config; + s->insn_write = s526_gpct_winsn; + + /* + * Analog Input subdevice + * channels 0 to 7 are the regular differential inputs + * channel 8 is "reference 0" (+10V) + * channel 9 is "reference 1" (0V) + */ s = &dev->subdevices[1]; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF; - /* channels 0 to 7 are the regular differential inputs */ - /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ - s->n_chan = 10; - s->maxdata = 0xffff; - s->range_table = &range_bipolar10; - s->len_chanlist = 16; - s->insn_read = s526_ai_rinsn; - s->insn_config = s526_ai_insn_config; - + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = 10; + s->maxdata = 0xffff; + s->range_table = &range_bipolar10; + s->len_chanlist = 16; + s->insn_read = s526_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[2]; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->range_table = &range_bipolar10; - s->insn_write = s526_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->range_table = &range_bipolar10; + s->insn_write = s526_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) return ret; + /* Digital I/O subdevice */ s = &dev->subdevices[3]; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = s526_dio_insn_bits; - s->insn_config = s526_dio_insn_config; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = s526_dio_insn_bits; + s->insn_config = s526_dio_insn_config; return 0; } diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index 5f19374c4..7a1defcf2 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -1,30 +1,29 @@ /* - comedi/drivers/serial2002.c - Skeleton code for a Comedi driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2002 Anders Blomdell - - 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. -*/ + * serial2002.c + * Comedi driver for serial connected hardware + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2002 Anders Blomdell + * + * 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: serial2002 -Description: Driver for serial connected hardware -Devices: -Author: Anders Blomdell -Updated: Fri, 7 Jun 2002 12:56:45 -0700 -Status: in development - -*/ + * Driver: serial2002 + * Description: Driver for serial connected hardware + * Devices: + * Author: Anders Blomdell + * Updated: Fri, 7 Jun 2002 12:56:45 -0700 + * Status: in development + */ #include #include "../comedidev.h" @@ -102,7 +101,7 @@ static long serial2002_tty_ioctl(struct file *f, unsigned op, if (f->f_op->unlocked_ioctl) return f->f_op->unlocked_ioctl(f, op, param); - return -ENOSYS; + return -ENOTTY; } static int serial2002_tty_write(struct file *f, unsigned char *buf, int count) @@ -176,7 +175,7 @@ static int serial2002_tty_read(struct file *f, int timeout) result = ch; break; } - udelay(100); + usleep_range(100, 1000); } } set_fs(oldfs); diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index acc7f3445..f9f634fd5 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -1,28 +1,29 @@ /* - comedi/drivers/ssv_dnp.c - generic comedi driver for SSV Embedded Systems' DIL/Net-PCs - Copyright (C) 2001 Robert Schwebel - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - 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. -*/ + * ssv_dnp.c + * generic comedi driver for SSV Embedded Systems' DIL/Net-PCs + * Copyright (C) 2001 Robert Schwebel + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * 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: ssv_dnp -Description: SSV Embedded Systems DIL/Net-PC -Author: Robert Schwebel -Devices: [SSV Embedded Systems] DIL/Net-PC 1486 (dnp-1486) -Status: unknown -*/ + * Driver: ssv_dnp + * Description: SSV Embedded Systems DIL/Net-PC + * Author: Robert Schwebel + * Devices: [SSV Embedded Systems] DIL/Net-PC 1486 (dnp-1486) + * Status: unknown + */ /* include files ----------------------------------------------------------- */ @@ -134,6 +135,12 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; int ret; + /* + * We use I/O ports 0x22, 0x23 and 0xa3-0xa9, which are always + * allocated for the primary 8259, so we don't need to allocate + * them ourselves. + */ + ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; @@ -148,10 +155,6 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = dnp_dio_insn_bits; s->insn_config = dnp_dio_insn_config; - /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always - * allocated for the primary 8259, so we don't need to allocate them - * ourselves. */ - /* configure all ports as input (default) */ outb(PAMR, CSCIR); outb(0x00, CSCDR); diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c deleted file mode 100644 index 51498b889..000000000 --- a/drivers/staging/comedi/drivers/unioxx5.c +++ /dev/null @@ -1,506 +0,0 @@ -/*************************************************************************** - * * - * comedi/drivers/unioxx5.c * - * Driver for Fastwel UNIOxx-5 (analog and digital i/o) boards. * - * * - * Copyright (C) 2006 Kruchinin Daniil (asgard) [asgard@etersoft.ru] * - * * - * COMEDI - Linux Control and Measurement Device Interface * - * Copyright (C) 1998,2000 David A. Schleef * - * * - * 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: unioxx5 -Description: Driver for Fastwel UNIOxx-5 (analog and digital i/o) boards. -Author: Kruchinin Daniil (asgard) -Status: unknown -Updated: 2006-10-09 -Devices: [Fastwel] UNIOxx-5 (unioxx5), - - This card supports digital and analog I/O. It written for g01 - subdevices only. - channels range: 0 .. 23 dio channels - and 0 .. 11 analog modules range - During attaching unioxx5 module displays modules identifiers - (see dmesg after comedi_config) in format: - | [module_number] module_id | - -*/ - -#include -#include -#include "../comedidev.h" - -#define UNIOXX5_SIZE 0x10 -#define UNIOXX5_SUBDEV_BASE 0xA000 /* base addr of first subdev */ -#define UNIOXX5_SUBDEV_ODDS 0x400 - -/* modules types */ -#define MODULE_DIGITAL 0 -#define MODULE_OUTPUT_MASK 0x80 /* analog input/output */ - -/* constants for digital i/o */ -#define UNIOXX5_NUM_OF_CHANS 24 - -/* constants for analog i/o */ -#define TxBE 0x10 /* transmit buffer enable */ -#define RxCA 0x20 /* 1 receive character available */ -#define Rx2CA 0x40 /* 2 receive character available */ -#define Rx4CA 0x80 /* 4 receive character available */ - -/* bytes mask errors */ -#define Rx2CA_ERR_MASK 0x04 /* 2 bytes receiving error */ -#define Rx4CA_ERR_MASK 0x08 /* 4 bytes receiving error */ - -/* channel modes */ -#define ALL_2_INPUT 0 /* config all digital channels to input */ -#define ALL_2_OUTPUT 1 /* config all digital channels to output */ - -/* 'private' structure for each subdevice */ -struct unioxx5_subd_priv { - int usp_iobase; - /* 12 modules. each can be 70L or 73L */ - unsigned char usp_module_type[12]; - /* for saving previous written value for analog modules */ - unsigned char usp_extra_data[12][4]; - unsigned char usp_prev_wr_val[3]; /* previous written value */ - unsigned char usp_prev_cn_val[3]; /* previous channel value */ -}; - -static int __unioxx5_define_chan_offset(int chan_num) -{ - if (chan_num < 0 || chan_num > 23) - return -1; - - return (chan_num >> 3) + 1; -} - -#if 0 /* not used? */ -static void __unioxx5_digital_config(struct comedi_subdevice *s, int mode) -{ - struct unioxx5_subd_priv *usp = s->private; - struct device *csdev = s->device->class_dev; - int i, mask; - - mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00; - dev_dbg(csdev, "mode = %d\n", mask); - - outb(1, usp->usp_iobase + 0); - - for (i = 0; i < 3; i++) - outb(mask, usp->usp_iobase + i); - - outb(0, usp->usp_iobase + 0); -} -#endif - -/* configure channels for analog i/o (even to output, odd to input) */ -static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel) -{ - int chan_a, chan_b, conf, channel_offset; - - channel_offset = __unioxx5_define_chan_offset(channel); - conf = usp->usp_prev_cn_val[channel_offset - 1]; - chan_a = chan_b = 1; - - /* setting channel A and channel B mask */ - if (channel % 2 == 0) { - chan_a <<= channel & 0x07; - chan_b <<= (channel + 1) & 0x07; - } else { - chan_a <<= (channel - 1) & 0x07; - chan_b <<= channel & 0x07; - } - - conf |= chan_a; /* even channel ot output */ - conf &= ~chan_b; /* odd channel to input */ - - outb(1, usp->usp_iobase + 0); - outb(conf, usp->usp_iobase + channel_offset); - outb(0, usp->usp_iobase + 0); - - usp->usp_prev_cn_val[channel_offset - 1] = conf; -} - -static int __unioxx5_digital_read(struct comedi_subdevice *s, - unsigned int *data, int channel, int minor) -{ - struct unioxx5_subd_priv *usp = s->private; - struct device *csdev = s->device->class_dev; - int channel_offset, mask = 1 << (channel & 0x07); - - channel_offset = __unioxx5_define_chan_offset(channel); - if (channel_offset < 0) { - dev_err(csdev, - "undefined channel %d. channel range is 0 .. 23\n", - channel); - return 0; - } - - *data = inb(usp->usp_iobase + channel_offset); - *data &= mask; - - /* correct the read value to 0 or 1 */ - if (channel_offset > 1) - channel -= 2 << channel_offset; - *data >>= channel; - return 1; -} - -static int __unioxx5_analog_read(struct comedi_subdevice *s, - unsigned int *data, int channel, int minor) -{ - struct unioxx5_subd_priv *usp = s->private; - struct device *csdev = s->device->class_dev; - int module_no, read_ch; - char control; - - module_no = channel / 2; - read_ch = channel % 2; /* depend on type of channel (A or B) */ - - /* defining if given module can work on input */ - if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) { - dev_err(csdev, - "module in position %d with id 0x%02x is for output only", - module_no, usp->usp_module_type[module_no]); - return 0; - } - - __unioxx5_analog_config(usp, channel); - /* sends module number to card(1 .. 12) */ - outb(module_no + 1, usp->usp_iobase + 5); - outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */ - control = inb(usp->usp_iobase); /* get control register byte */ - - /* waits while reading four bytes will be allowed */ - while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA)) - ; - - /* if four bytes readding error occurs - return 0(false) */ - if ((control & Rx4CA_ERR_MASK)) { - dev_err(csdev, "4 bytes error\n"); - return 0; - } - - if (read_ch) - *data = inw(usp->usp_iobase + 6); /* channel B */ - else - *data = inw(usp->usp_iobase + 4); /* channel A */ - - return 1; -} - -static int __unioxx5_digital_write(struct comedi_subdevice *s, - unsigned int *data, int channel, int minor) -{ - struct unioxx5_subd_priv *usp = s->private; - struct device *csdev = s->device->class_dev; - int channel_offset, val; - int mask = 1 << (channel & 0x07); - - channel_offset = __unioxx5_define_chan_offset(channel); - if (channel_offset < 0) { - dev_err(csdev, - "undefined channel %d. channel range is 0 .. 23\n", - channel); - return 0; - } - - /* getting previous written value */ - val = usp->usp_prev_wr_val[channel_offset - 1]; - - if (*data) - val |= mask; - else - val &= ~mask; - - outb(val, usp->usp_iobase + channel_offset); - /* saving new written value */ - usp->usp_prev_wr_val[channel_offset - 1] = val; - - return 1; -} - -static int __unioxx5_analog_write(struct comedi_subdevice *s, - unsigned int *data, int channel, int minor) -{ - struct unioxx5_subd_priv *usp = s->private; - struct device *csdev = s->device->class_dev; - int module, i; - - module = channel / 2; /* definig module number(0 .. 11) */ - i = (channel % 2) << 1; /* depends on type of channel (A or B) */ - - /* defining if given module can work on output */ - if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) { - dev_err(csdev, - "module in position %d with id 0x%0x is for input only!\n", - module, usp->usp_module_type[module]); - return 0; - } - - __unioxx5_analog_config(usp, channel); - /* saving minor byte */ - usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF); - /* saving major byte */ - usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8); - - /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */ - /* sending module number to card(1 .. 12) */ - outb(module + 1, usp->usp_iobase + 5); - outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */ - - /* sending for bytes to module(one byte per cycle iteration) */ - for (i = 0; i < 4; i++) { - while (!((inb(usp->usp_iobase + 0)) & TxBE)) - ; /* waits while writing will be allowed */ - outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6); - } - - return 1; -} - -static int unioxx5_subdev_read(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data) -{ - struct unioxx5_subd_priv *usp = subdev->private; - int channel, type; - - channel = CR_CHAN(insn->chanspec); - /* defining module type(analog or digital) */ - type = usp->usp_module_type[channel / 2]; - - if (type == MODULE_DIGITAL) { - if (!__unioxx5_digital_read(subdev, data, channel, dev->minor)) - return -1; - } else { - if (!__unioxx5_analog_read(subdev, data, channel, dev->minor)) - return -1; - } - - return 1; -} - -static int unioxx5_subdev_write(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data) -{ - struct unioxx5_subd_priv *usp = subdev->private; - int channel, type; - - channel = CR_CHAN(insn->chanspec); - /* defining module type(analog or digital) */ - type = usp->usp_module_type[channel / 2]; - - if (type == MODULE_DIGITAL) { - if (!__unioxx5_digital_write(subdev, data, channel, dev->minor)) - return -1; - } else { - if (!__unioxx5_analog_write(subdev, data, channel, dev->minor)) - return -1; - } - - return 1; -} - -/* for digital modules only */ -static int unioxx5_insn_config(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data) -{ - int channel_offset, flags, channel = CR_CHAN(insn->chanspec), type; - struct unioxx5_subd_priv *usp = subdev->private; - int mask = 1 << (channel & 0x07); - - type = usp->usp_module_type[channel / 2]; - - if (type != MODULE_DIGITAL) { - dev_err(dev->class_dev, - "channel configuration accessible only for digital modules\n"); - return -1; - } - - channel_offset = __unioxx5_define_chan_offset(channel); - if (channel_offset < 0) { - dev_err(dev->class_dev, - "undefined channel %d. channel range is 0 .. 23\n", - channel); - return -1; - } - - /* gets previously written value */ - flags = usp->usp_prev_cn_val[channel_offset - 1]; - - switch (*data) { - case COMEDI_INPUT: - flags &= ~mask; - break; - case COMEDI_OUTPUT: - flags |= mask; - break; - default: - dev_err(dev->class_dev, "unknown flag\n"); - return -1; - } - - /* *\ - * sets channels buffer to 1(after this we are allowed to * - * change channel type on input or output) * - \* */ - outb(1, usp->usp_iobase + 0); - /* changes type of _one_ channel */ - outb(flags, usp->usp_iobase + channel_offset); - /* sets channels bank to 0(allows directly input/output) */ - outb(0, usp->usp_iobase + 0); - /* saves written value */ - usp->usp_prev_cn_val[channel_offset - 1] = flags; - - return 0; -} - -/* initializing subdevice with given address */ -static int __unioxx5_subdev_init(struct comedi_device *dev, - struct comedi_subdevice *s, - int iobase) -{ - struct unioxx5_subd_priv *usp; - int i, to, ndef_flag = 0; - int ret; - - usp = comedi_alloc_spriv(s, sizeof(*usp)); - if (!usp) - return -ENOMEM; - - ret = __comedi_request_region(dev, iobase, UNIOXX5_SIZE); - if (ret) - return ret; - usp->usp_iobase = iobase; - - /* defining modules types */ - for (i = 0; i < 12; i++) { - to = 10000; - - __unioxx5_analog_config(usp, i * 2); - /* sends channel number to card */ - outb(i + 1, iobase + 5); - outb('H', iobase + 6); /* requests EEPROM world */ - while (!(inb(iobase + 0) & TxBE)) - ; /* waits while writing will be allowed */ - outb(0, iobase + 6); - - /* waits while reading of two bytes will be allowed */ - while (!(inb(iobase + 0) & Rx2CA)) { - if (--to <= 0) { - ndef_flag = 1; - break; - } - } - - if (ndef_flag) { - usp->usp_module_type[i] = 0; - ndef_flag = 0; - } else { - usp->usp_module_type[i] = inb(iobase + 6); - } - - udelay(1); - } - - /* initial subdevice for digital or analog i/o */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = UNIOXX5_NUM_OF_CHANS; - s->maxdata = 0xFFF; - s->range_table = &range_digital; - s->insn_read = unioxx5_subdev_read; - s->insn_write = unioxx5_subdev_write; - /* for digital modules only!!! */ - s->insn_config = unioxx5_insn_config; - - return 0; -} - -static int unioxx5_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int iobase, i, n_subd; - int id, num, ba; - int ret; - - iobase = it->options[0]; - - dev->iobase = iobase; - iobase += UNIOXX5_SUBDEV_BASE; - n_subd = 0; - - /* getting number of subdevices with types 'g01' */ - for (i = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) { - id = inb(ba + 0xE); - num = inb(ba + 0xF); - - if (id != 'g' || num != 1) - continue; - - n_subd++; - } - - /* unioxx5 can has from two to four subdevices */ - if (n_subd < 2) { - dev_err(dev->class_dev, - "your card must has at least 2 'g01' subdevices\n"); - return -1; - } - - ret = comedi_alloc_subdevices(dev, n_subd); - if (ret) - return ret; - - /* initializing each of for same subdevices */ - for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) { - s = &dev->subdevices[i]; - ret = __unioxx5_subdev_init(dev, s, iobase); - if (ret) - return ret; - } - - return 0; -} - -static void unioxx5_detach(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - struct unioxx5_subd_priv *spriv; - int i; - - for (i = 0; i < dev->n_subdevices; i++) { - s = &dev->subdevices[i]; - spriv = s->private; - if (spriv && spriv->usp_iobase) - release_region(spriv->usp_iobase, UNIOXX5_SIZE); - } -} - -static struct comedi_driver unioxx5_driver = { - .driver_name = "unioxx5", - .module = THIS_MODULE, - .attach = unioxx5_attach, - .detach = unioxx5_detach, -}; -module_comedi_driver(unioxx5_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index ced05e581..f4f05d29d 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -108,55 +108,55 @@ #define BULK_TIMEOUT 1000 /* 300Hz max frequ under PWM */ -#define MIN_PWM_PERIOD ((long)(1E9/300)) +#define MIN_PWM_PERIOD ((long)(1E9 / 300)) /* Default PWM frequency */ -#define PWM_DEFAULT_PERIOD ((long)(1E9/100)) +#define PWM_DEFAULT_PERIOD ((long)(1E9 / 100)) /* Size of one A/D value */ -#define SIZEADIN ((sizeof(uint16_t))) +#define SIZEADIN ((sizeof(u16))) /* * Size of the input-buffer IN BYTES * Always multiple of 8 for 8 microframes which is needed in the highspeed mode */ -#define SIZEINBUF ((8*SIZEADIN)) +#define SIZEINBUF (8 * SIZEADIN) /* 16 bytes. */ -#define SIZEINSNBUF 16 +#define SIZEINSNBUF 16 /* size of one value for the D/A converter: channel and value */ -#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) +#define SIZEDAOUT ((sizeof(u8) + sizeof(u16))) /* * Size of the output-buffer in bytes * Actually only the first 4 triplets are used but for the * high speed mode we need to pad it to 8 (microframes). */ -#define SIZEOUTBUF ((8*SIZEDAOUT)) +#define SIZEOUTBUF (8 * SIZEDAOUT) /* * Size of the buffer for the dux commands: just now max size is determined * by the analogue out + command byte + panic bytes... */ -#define SIZEOFDUXBUFFER ((8*SIZEDAOUT+2)) +#define SIZEOFDUXBUFFER (8 * SIZEDAOUT + 2) /* Number of in-URBs which receive the data: min=2 */ -#define NUMOFINBUFFERSFULL 5 +#define NUMOFINBUFFERSFULL 5 /* Number of out-URBs which send the data: min=2 */ -#define NUMOFOUTBUFFERSFULL 5 +#define NUMOFOUTBUFFERSFULL 5 /* Number of in-URBs which receive the data: min=5 */ /* must have more buffers due to buggy USB ctr */ -#define NUMOFINBUFFERSHIGH 10 +#define NUMOFINBUFFERSHIGH 10 /* Number of out-URBs which send the data: min=5 */ /* must have more buffers due to buggy USB ctr */ -#define NUMOFOUTBUFFERSHIGH 10 +#define NUMOFOUTBUFFERSHIGH 10 /* number of retries to get the right dux command */ -#define RETRIES 10 +#define RETRIES 10 static const struct comedi_lrange range_usbdux_ai_range = { 4, { @@ -187,7 +187,7 @@ struct usbdux_private { /* PWM period */ unsigned int pwm_period; /* PWM internal delay for the GPIF in the FX2 */ - uint8_t pwm_delay; + u8 pwm_delay; /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */ @@ -209,8 +209,8 @@ struct usbdux_private { /* interval in frames/uframes */ unsigned int ai_interval; /* commands */ - uint8_t *dux_commands; - struct semaphore sem; + u8 *dux_commands; + struct mutex mut; }; static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs) @@ -237,10 +237,10 @@ static int usbdux_ai_cancel(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; /* prevent other CPUs from submitting new commands just now */ - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* unlink only if the urb really has been submitted */ usbdux_ai_stop(dev, devpriv->ai_cmd_running); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 0; } @@ -262,11 +262,11 @@ static void usbduxsub_ai_handle_urb(struct comedi_device *dev, /* 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]); + u16 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); + val = comedi_offset_munge(s, val); /* transfer data */ if (!comedi_buf_write_samples(s, &val, 1)) @@ -365,10 +365,10 @@ static int usbdux_ao_cancel(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; /* prevent other CPUs from submitting a command just now */ - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* unlink only if it is really running */ usbdux_ao_stop(dev, devpriv->ao_cmd_running); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 0; } @@ -380,7 +380,7 @@ static void usbduxsub_ao_handle_urb(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - uint8_t *datap; + u8 *datap; int ret; int i; @@ -516,9 +516,8 @@ static int usbdux_submit_urbs(struct comedi_device *dev, static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - struct usbdux_private *this_usbduxsub = dev->private; - int err = 0, i; - unsigned int tmp_timer; + struct usbdux_private *devpriv = dev->private; + int err = 0; /* Step 1 : check if triggers are trivially valid */ @@ -549,40 +548,31 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); if (cmd->scan_begin_src == TRIG_TIMER) { - if (this_usbduxsub->high_speed) { + /* full speed does 1kHz scans every USB frame */ + unsigned int arg = 1000000; + unsigned int min_arg = arg; + + if (devpriv->high_speed) { /* * In high speed mode microframes are possible. * However, during one microframe we can roughly * sample one channel. Thus, the more channels * are in the channel list the more time we need. */ - i = 1; + int i = 1; + /* find a power of 2 for the number of channels */ - while (i < (cmd->chanlist_len)) + while (i < cmd->chanlist_len) i = i * 2; - err |= comedi_check_trigger_arg_min(&cmd-> - scan_begin_arg, - 1000000 / 8 * i); - /* now calc the real sampling rate with all the - * rounding errors */ - tmp_timer = - ((unsigned int)(cmd->scan_begin_arg / 125000)) * - 125000; - } else { - /* full speed */ - /* 1kHz scans every USB frame */ - err |= comedi_check_trigger_arg_min(&cmd-> - scan_begin_arg, - 1000000); - /* - * calc the real sampling rate with the rounding errors - */ - tmp_timer = ((unsigned int)(cmd->scan_begin_arg / - 1000000)) * 1000000; + arg /= 8; + min_arg = arg * i; } - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, - tmp_timer); + err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, + min_arg); + /* calc the real sampling rate with the rounding errors */ + arg = (cmd->scan_begin_arg / arg) * arg; + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, @@ -603,10 +593,10 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, * creates the ADC command for the MAX1271 * range is the range value from comedi */ -static uint8_t create_adc_command(unsigned int chan, unsigned int range) +static u8 create_adc_command(unsigned int chan, unsigned int range) { - uint8_t p = (range <= 1); - uint8_t r = ((range % 2) == 0); + u8 p = (range <= 1); + u8 r = ((range % 2) == 0); return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3); } @@ -656,7 +646,7 @@ static int usbdux_ai_inttrig(struct comedi_device *dev, if (trig_num != cmd->start_arg) return -EINVAL; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (!devpriv->ai_cmd_running) { devpriv->ai_cmd_running = 1; @@ -672,7 +662,7 @@ static int usbdux_ai_inttrig(struct comedi_device *dev, } ai_trig_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -685,7 +675,7 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) int i; /* block other CPUs from starting an ai_cmd */ - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ai_cmd_running) goto ai_cmd_exit; @@ -746,7 +736,7 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } ai_cmd_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -764,7 +754,7 @@ static int usbdux_ai_insn_read(struct comedi_device *dev, int ret = -EBUSY; int i; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ai_cmd_running) goto ai_read_exit; @@ -786,13 +776,13 @@ static int usbdux_ai_insn_read(struct comedi_device *dev, /* bipolar data is two's-complement */ if (comedi_range_is_bipolar(s, range)) - val ^= ((s->maxdata + 1) >> 1); + val = comedi_offset_munge(s, val); data[i] = val; } ai_read_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret ? ret : insn->n; } @@ -805,9 +795,9 @@ static int usbdux_ao_insn_read(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); ret = comedi_readback_insn_read(dev, s, insn, data); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -824,7 +814,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, int ret = -EBUSY; int i; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ao_cmd_running) goto ao_write_exit; @@ -848,7 +838,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, } ao_write_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret ? ret : insn->n; } @@ -864,7 +854,7 @@ static int usbdux_ao_inttrig(struct comedi_device *dev, if (trig_num != cmd->start_arg) return -EINVAL; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (!devpriv->ao_cmd_running) { devpriv->ao_cmd_running = 1; @@ -880,25 +870,21 @@ static int usbdux_ao_inttrig(struct comedi_device *dev, } ao_trig_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - struct usbdux_private *this_usbduxsub = dev->private; int err = 0; unsigned int flags; - if (!this_usbduxsub) - return -EFAULT; - /* Step 1 : check if triggers are trivially valid */ err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - if (0) { /* (this_usbduxsub->high_speed) */ + if (0) { /* (devpriv->high_speed) */ /* the sampling rate is set by the coversion rate */ flags = TRIG_FOLLOW; } else { @@ -907,7 +893,7 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, } err |= comedi_check_trigger_src(&cmd->scan_begin_src, flags); - if (0) { /* (this_usbduxsub->high_speed) */ + if (0) { /* (devpriv->high_speed) */ /* * in usb-2.0 only one conversion it transmitted * but with 8kHz/n @@ -974,7 +960,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct comedi_cmd *cmd = &s->async->cmd; int ret = -EBUSY; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ao_cmd_running) goto ao_cmd_exit; @@ -1016,7 +1002,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } ao_cmd_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -1047,7 +1033,7 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); comedi_dio_update_state(s, data); @@ -1069,7 +1055,7 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev, data[1] = le16_to_cpu(devpriv->insn_buf[1]); dio_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret ? ret : insn->n; } @@ -1084,7 +1070,7 @@ static int usbdux_counter_read(struct comedi_device *dev, int ret = 0; int i; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); for (i = 0; i < insn->n; i++) { ret = send_dux_commands(dev, USBDUX_CMD_TIMER_RD); @@ -1098,7 +1084,7 @@ static int usbdux_counter_read(struct comedi_device *dev, } counter_read_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret ? ret : insn->n; } @@ -1114,7 +1100,7 @@ static int usbdux_counter_write(struct comedi_device *dev, int ret = 0; int i; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); devpriv->dux_commands[1] = chan; @@ -1126,7 +1112,7 @@ static int usbdux_counter_write(struct comedi_device *dev, break; } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret ? ret : insn->n; } @@ -1162,11 +1148,11 @@ static int usbdux_pwm_cancel(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* unlink only if it is really running */ usbdux_pwm_stop(dev, devpriv->pwm_cmd_running); ret = send_dux_commands(dev, USBDUX_CMD_PWM_OFF); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -1271,7 +1257,7 @@ static int usbdux_pwm_start(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; int ret = 0; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->pwm_cmd_running) goto pwm_start_exit; @@ -1290,7 +1276,7 @@ static int usbdux_pwm_start(struct comedi_device *dev, devpriv->pwm_cmd_running = 0; pwm_start_exit: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -1391,8 +1377,8 @@ static int usbdux_firmware_upload(struct comedi_device *dev, unsigned long context) { struct usb_device *usb = comedi_to_usb_dev(dev); - uint8_t *buf; - uint8_t *tmp; + u8 *buf; + u8 *tmp; int ret; if (!data) @@ -1590,7 +1576,7 @@ static int usbdux_auto_attach(struct comedi_device *dev, if (!devpriv) return -ENOMEM; - sema_init(&devpriv->sem, 1); + mutex_init(&devpriv->mut); usb_set_intfdata(intf, devpriv); @@ -1705,7 +1691,7 @@ static void usbdux_detach(struct comedi_device *dev) if (!devpriv) return; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* force unlink all urbs */ usbdux_pwm_stop(dev, 1); @@ -1714,7 +1700,7 @@ static void usbdux_detach(struct comedi_device *dev) usbdux_free_usb_buffers(dev); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); } static struct comedi_driver usbdux_driver = { diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index d90dc5998..10f94ec34 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -97,7 +97,7 @@ /* * size of one A/D value */ -#define SIZEADIN (sizeof(int16_t)) +#define SIZEADIN (sizeof(s16)) /* * size of the input-buffer IN BYTES @@ -156,12 +156,11 @@ static const struct comedi_lrange range_usbduxfast_ai_range = { */ struct usbduxfast_private { struct urb *urb; /* BULK-transfer handling: urb */ - uint8_t *duxbuf; - int8_t *inbuf; + u8 *duxbuf; + s8 *inbuf; short int ai_cmd_running; /* asynchronous command is running */ - int ignore; /* counter which ignores the first - buffers */ - struct semaphore sem; + int ignore; /* counter which ignores the first buffers */ + struct mutex mut; }; /* @@ -190,8 +189,7 @@ static int usbduxfast_send_cmd(struct comedi_device *dev, int cmd_type) } static void usbduxfast_cmd_data(struct comedi_device *dev, int index, - uint8_t len, uint8_t op, uint8_t out, - uint8_t log) + u8 len, u8 op, u8 out, u8 log) { struct usbduxfast_private *devpriv = dev->private; @@ -223,12 +221,9 @@ static int usbduxfast_ai_cancel(struct comedi_device *dev, struct usbduxfast_private *devpriv = dev->private; int ret; - if (!devpriv) - return -EFAULT; - - down(&devpriv->sem); + mutex_lock(&devpriv->mut); ret = usbduxfast_ai_stop(dev, 1); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -317,9 +312,6 @@ static int usbduxfast_submit_urb(struct comedi_device *dev) struct usbduxfast_private *devpriv = dev->private; int ret; - if (!devpriv) - return -EFAULT; - usb_fill_bulk_urb(devpriv->urb, usb, usb_rcvbulkpipe(usb, BULKINEP), devpriv->inbuf, SIZEINBUF, usbduxfast_ai_interrupt, dev); @@ -332,22 +324,50 @@ static int usbduxfast_submit_urb(struct comedi_device *dev) return 0; } +static int usbduxfast_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int gain0 = CR_RANGE(cmd->chanlist[0]); + int i; + + if (cmd->chanlist_len > 3 && cmd->chanlist_len != 16) { + dev_err(dev->class_dev, "unsupported combination of channels\n"); + return -EINVAL; + } + + for (i = 0; i < cmd->chanlist_len; ++i) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int gain = CR_RANGE(cmd->chanlist[i]); + + if (chan != i) { + dev_err(dev->class_dev, + "channels are not consecutive\n"); + return -EINVAL; + } + if (gain != gain0 && cmd->chanlist_len > 3) { + dev_err(dev->class_dev, + "gain must be the same for all channels\n"); + return -EINVAL; + } + } + return 0; +} + static int usbduxfast_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - long int steps, tmp; - int min_sample_period; + unsigned int steps; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT | TRIG_INT); - err |= comedi_check_trigger_src(&cmd->scan_begin_src, - TRIG_FOLLOW | TRIG_EXT); - err |= comedi_check_trigger_src(&cmd->convert_src, - TRIG_TIMER | TRIG_EXT); + err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER); err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -357,16 +377,10 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ err |= comedi_check_trigger_is_unique(cmd->start_src); - err |= comedi_check_trigger_is_unique(cmd->scan_begin_src); - err |= comedi_check_trigger_is_unique(cmd->convert_src); err |= comedi_check_trigger_is_unique(cmd->stop_src); /* Step 2b : and mutually compatible */ - /* can't have external stop and start triggers at once */ - if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT) - err |= -EINVAL; - if (err) return 2; @@ -377,47 +391,44 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, if (!cmd->chanlist_len) err |= -EINVAL; + /* external start trigger is only valid for 1 or 16 channels */ + if (cmd->start_src == TRIG_EXT && + cmd->chanlist_len != 1 && cmd->chanlist_len != 16) + err |= -EINVAL; + err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->chanlist_len == 1) - min_sample_period = 1; - else - min_sample_period = MIN_SAMPLING_PERIOD; - - if (cmd->convert_src == TRIG_TIMER) { - steps = cmd->convert_arg * 30; - if (steps < (min_sample_period * 1000)) - steps = min_sample_period * 1000; - - if (steps > (MAX_SAMPLING_PERIOD * 1000)) - steps = MAX_SAMPLING_PERIOD * 1000; - - /* calc arg again */ - tmp = steps / 30; - err |= comedi_check_trigger_arg_is(&cmd->convert_arg, tmp); - } - - /* stop source */ - switch (cmd->stop_src) { - case TRIG_COUNT: + /* + * Validate the conversion timing: + * for 1 channel the timing in 30MHz "steps" is: + * steps <= MAX_SAMPLING_PERIOD + * for all other chanlist_len it is: + * MIN_SAMPLING_PERIOD <= steps <= MAX_SAMPLING_PERIOD + */ + steps = (cmd->convert_arg * 30) / 1000; + if (cmd->chanlist_len != 1) + err |= comedi_check_trigger_arg_min(&steps, + MIN_SAMPLING_PERIOD); + err |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD); + arg = (steps * 1000) / 30; + err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->stop_src == TRIG_COUNT) err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); - break; - case TRIG_NONE: + else /* TRIG_NONE */ err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - /* - * TRIG_EXT doesn't care since it doesn't trigger - * off a numbered channel - */ - default: - break; - } if (err) return 3; - /* step 4: fix up any arguments */ + /* Step 4: fix up any arguments */ + + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= usbduxfast_ai_check_chanlist(dev, s, cmd); + if (err) + return 5; return 0; } @@ -430,13 +441,10 @@ static int usbduxfast_ai_inttrig(struct comedi_device *dev, struct comedi_cmd *cmd = &s->async->cmd; int ret; - if (!devpriv) - return -EFAULT; - if (trig_num != cmd->start_arg) return -EINVAL; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (!devpriv->ai_cmd_running) { devpriv->ai_cmd_running = 1; @@ -444,14 +452,14 @@ static int usbduxfast_ai_inttrig(struct comedi_device *dev, if (ret < 0) { dev_err(dev->class_dev, "urbSubmit: err=%d\n", ret); devpriv->ai_cmd_running = 0; - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } s->async->inttrig = NULL; } else { dev_err(dev->class_dev, "ai is already running\n"); } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 1; } @@ -460,19 +468,14 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, { struct usbduxfast_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int chan, gain, rngmask = 0xff; - int i, j, ret; - int result; + unsigned int rngmask = 0xff; + int j, ret; long steps, steps_tmp; - if (!devpriv) - return -EFAULT; - - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ai_cmd_running) { - dev_err(dev->class_dev, "ai_cmd not possible\n"); - up(&devpriv->sem); - return -EBUSY; + ret = -EBUSY; + goto cmd_exit; } /* @@ -481,50 +484,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ devpriv->ignore = PACKETS_TO_IGNORE; - gain = CR_RANGE(cmd->chanlist[0]); - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - if (chan != i) { - dev_err(dev->class_dev, - "channels are not consecutive\n"); - up(&devpriv->sem); - return -EINVAL; - } - if ((gain != CR_RANGE(cmd->chanlist[i])) - && (cmd->chanlist_len > 3)) { - dev_err(dev->class_dev, - "gain must be the same for all channels\n"); - up(&devpriv->sem); - return -EINVAL; - } - if (i >= NUMCHANNELS) { - dev_err(dev->class_dev, "chanlist too long\n"); - break; - } - } - steps = 0; - if (cmd->convert_src == TRIG_TIMER) - steps = (cmd->convert_arg * 30) / 1000; - - if ((steps < MIN_SAMPLING_PERIOD) && (cmd->chanlist_len != 1)) { - dev_err(dev->class_dev, - "steps=%ld, scan_begin_arg=%d. Not properly tested by cmdtest?\n", - steps, cmd->scan_begin_arg); - up(&devpriv->sem); - return -EINVAL; - } - if (steps > MAX_SAMPLING_PERIOD) { - dev_err(dev->class_dev, "sampling rate too low\n"); - up(&devpriv->sem); - return -EINVAL; - } - if ((cmd->start_src == TRIG_EXT) && (cmd->chanlist_len != 1) - && (cmd->chanlist_len != 16)) { - dev_err(dev->class_dev, - "TRIG_EXT only with 1 or 16 channels possible\n"); - up(&devpriv->sem); - return -EINVAL; - } + steps = (cmd->convert_arg * 30) / 1000; switch (cmd->chanlist_len) { case 1: @@ -769,19 +729,12 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, usbduxfast_cmd_data(dev, 4, 0x09, 0x01, rngmask, 0xff); break; - - default: - dev_err(dev->class_dev, "unsupported combination of channels\n"); - up(&devpriv->sem); - return -EFAULT; } /* 0 means that the AD commands are sent */ - result = usbduxfast_send_cmd(dev, SENDADCOMMANDS); - if (result < 0) { - up(&devpriv->sem); - return result; - } + ret = usbduxfast_send_cmd(dev, SENDADCOMMANDS); + if (ret < 0) + goto cmd_exit; if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) { /* enable this acquisition operation */ @@ -790,16 +743,17 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, if (ret < 0) { devpriv->ai_cmd_running = 0; /* fixme: unlink here?? */ - up(&devpriv->sem); - return ret; + goto cmd_exit; } s->async->inttrig = NULL; } else { /* TRIG_INT */ s->async->inttrig = usbduxfast_ai_inttrig; } - up(&devpriv->sem); - return 0; +cmd_exit: + mutex_unlock(&devpriv->mut); + + return ret; } /* @@ -814,16 +768,16 @@ static int usbduxfast_ai_insn_read(struct comedi_device *dev, struct usbduxfast_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - uint8_t rngmask = range ? (0xff - 0x04) : 0xff; + u8 rngmask = range ? (0xff - 0x04) : 0xff; int i, j, n, actual_length; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ai_cmd_running) { dev_err(dev->class_dev, "ai_insn_read not possible, async cmd is running\n"); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return -EBUSY; } @@ -845,7 +799,7 @@ static int usbduxfast_ai_insn_read(struct comedi_device *dev, ret = usbduxfast_send_cmd(dev, SENDADCOMMANDS); if (ret < 0) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -855,7 +809,7 @@ static int usbduxfast_ai_insn_read(struct comedi_device *dev, &actual_length, 10000); if (ret < 0) { dev_err(dev->class_dev, "insn timeout, no data\n"); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } } @@ -866,65 +820,32 @@ static int usbduxfast_ai_insn_read(struct comedi_device *dev, &actual_length, 10000); if (ret < 0) { dev_err(dev->class_dev, "insn data error: %d\n", ret); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } - n = actual_length / sizeof(uint16_t); + n = actual_length / sizeof(u16); if ((n % 16) != 0) { dev_err(dev->class_dev, "insn data packet corrupted\n"); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return -EINVAL; } for (j = chan; (j < n) && (i < insn->n); j = j + 16) { - data[i] = ((uint16_t *) (devpriv->inbuf))[j]; + data[i] = ((u16 *)(devpriv->inbuf))[j]; i++; } } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return insn->n; } -static int usbduxfast_attach_common(struct comedi_device *dev) -{ - struct usbduxfast_private *devpriv = dev->private; - struct comedi_subdevice *s; - int ret; - - down(&devpriv->sem); - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) { - up(&devpriv->sem); - return ret; - } - - /* Analog Input subdevice */ - s = &dev->subdevices[0]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - s->n_chan = 16; - s->len_chanlist = 16; - s->insn_read = usbduxfast_ai_insn_read; - s->do_cmdtest = usbduxfast_ai_cmdtest; - s->do_cmd = usbduxfast_ai_cmd; - s->cancel = usbduxfast_ai_cancel; - s->maxdata = 0x1000; - s->range_table = &range_usbduxfast_ai_range; - - up(&devpriv->sem); - - return 0; -} - static int usbduxfast_upload_firmware(struct comedi_device *dev, const u8 *data, size_t size, unsigned long context) { struct usb_device *usb = comedi_to_usb_dev(dev); - uint8_t *buf; + u8 *buf; unsigned char *tmp; int ret; @@ -996,6 +917,7 @@ static int usbduxfast_auto_attach(struct comedi_device *dev, struct usb_interface *intf = comedi_to_usb_interface(dev); struct usb_device *usb = comedi_to_usb_dev(dev); struct usbduxfast_private *devpriv; + struct comedi_subdevice *s; int ret; if (usb->speed != USB_SPEED_HIGH) { @@ -1008,7 +930,7 @@ static int usbduxfast_auto_attach(struct comedi_device *dev, if (!devpriv) return -ENOMEM; - sema_init(&devpriv->sem, 1); + mutex_init(&devpriv->mut); usb_set_intfdata(intf, devpriv); devpriv->duxbuf = kmalloc(SIZEOFDUXBUF, GFP_KERNEL); @@ -1038,7 +960,25 @@ static int usbduxfast_auto_attach(struct comedi_device *dev, if (ret) return ret; - return usbduxfast_attach_common(dev); + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->n_chan = 16; + s->maxdata = 0x1000; /* 12-bit + 1 overflow bit */ + s->range_table = &range_usbduxfast_ai_range; + s->insn_read = usbduxfast_ai_insn_read; + s->len_chanlist = s->n_chan; + s->do_cmdtest = usbduxfast_ai_cmdtest; + s->do_cmd = usbduxfast_ai_cmd; + s->cancel = usbduxfast_ai_cancel; + + return 0; } static void usbduxfast_detach(struct comedi_device *dev) @@ -1049,7 +989,7 @@ static void usbduxfast_detach(struct comedi_device *dev) if (!devpriv) return; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); usb_set_intfdata(intf, NULL); @@ -1058,18 +998,12 @@ static void usbduxfast_detach(struct comedi_device *dev) usb_kill_urb(devpriv->urb); kfree(devpriv->inbuf); - devpriv->inbuf = NULL; - usb_free_urb(devpriv->urb); - devpriv->urb = NULL; } kfree(devpriv->duxbuf); - devpriv->duxbuf = NULL; - - devpriv->ai_cmd_running = 0; - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); } static struct comedi_driver usbduxfast_driver = { diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 649cf4718..456e9f13b 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -66,22 +66,22 @@ #define USBDUXSUB_CPUCS 0xE600 /* 300Hz max frequ under PWM */ -#define MIN_PWM_PERIOD ((long)(1E9/300)) +#define MIN_PWM_PERIOD ((long)(1E9 / 300)) /* Default PWM frequency */ -#define PWM_DEFAULT_PERIOD ((long)(1E9/100)) +#define PWM_DEFAULT_PERIOD ((long)(1E9 / 100)) /* Number of channels (16 AD and offset)*/ #define NUMCHANNELS 16 /* Size of one A/D value */ -#define SIZEADIN ((sizeof(uint32_t))) +#define SIZEADIN ((sizeof(u32))) /* * Size of the async input-buffer IN BYTES, the DIO state is transmitted * as the first byte. */ -#define SIZEINBUF (((NUMCHANNELS+1)*SIZEADIN)) +#define SIZEINBUF (((NUMCHANNELS + 1) * SIZEADIN)) /* 16 bytes. */ #define SIZEINSNBUF 16 @@ -90,20 +90,20 @@ #define NUMOUTCHANNELS 8 /* size of one value for the D/A converter: channel and value */ -#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) +#define SIZEDAOUT ((sizeof(u8) + sizeof(uint16_t))) /* * Size of the output-buffer in bytes * Actually only the first 4 triplets are used but for the * high speed mode we need to pad it to 8 (microframes). */ -#define SIZEOUTBUF ((8*SIZEDAOUT)) +#define SIZEOUTBUF ((8 * SIZEDAOUT)) /* * Size of the buffer for the dux commands: just now max size is determined * by the analogue out + command byte + panic bytes... */ -#define SIZEOFDUXBUFFER ((8*SIZEDAOUT+2)) +#define SIZEOFDUXBUFFER ((8 * SIZEDAOUT + 2)) /* Number of in-URBs which receive the data: min=2 */ #define NUMOFINBUFFERSFULL 5 @@ -150,13 +150,13 @@ struct usbduxsigma_private { /* PWM period */ unsigned int pwm_period; /* PWM internal delay for the GPIF in the FX2 */ - uint8_t pwm_delay; + u8 pwm_delay; /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */ __be32 *in_buf; /* input buffer for single insn */ - uint8_t *insn_buf; + u8 *insn_buf; unsigned high_speed:1; unsigned ai_cmd_running:1; @@ -172,8 +172,8 @@ struct usbduxsigma_private { /* interval in frames/uframes */ unsigned int ai_interval; /* commands */ - uint8_t *dux_commands; - struct semaphore sem; + u8 *dux_commands; + struct mutex mut; }; static void usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs) @@ -199,10 +199,10 @@ static int usbduxsigma_ai_cancel(struct comedi_device *dev, { struct usbduxsigma_private *devpriv = dev->private; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* unlink only if it is really running */ usbduxsigma_ai_stop(dev, devpriv->ai_cmd_running); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 0; } @@ -214,7 +214,7 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - uint32_t val; + u32 val; int ret; int i; @@ -223,15 +223,14 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev, if (devpriv->ai_counter == 0) { devpriv->ai_counter = devpriv->ai_timer; - /* get the data from the USB bus - and hand it over to comedi */ + /* + * Get the data from the USB bus and hand it over + * to comedi. Note, first byte is the DIO state. + */ 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 = be32_to_cpu(devpriv->in_buf[i + 1]); val &= 0x00ffffff; /* strip status byte */ - val ^= 0x00800000; /* convert to unsigned */ - + val = comedi_offset_munge(s, val); if (!comedi_buf_write_samples(s, &val, 1)) return; } @@ -326,10 +325,10 @@ static int usbduxsigma_ao_cancel(struct comedi_device *dev, { struct usbduxsigma_private *devpriv = dev->private; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* unlink only if it is really running */ usbduxsigma_ao_stop(dev, devpriv->ao_cmd_running); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 0; } @@ -341,7 +340,7 @@ static void usbduxsigma_ao_handle_urb(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - uint8_t *datap; + u8 *datap; int ret; int i; @@ -553,13 +552,12 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, * range is the range value from comedi */ static void create_adc_command(unsigned int chan, - uint8_t *muxsg0, - uint8_t *muxsg1) + u8 *muxsg0, u8 *muxsg1) { if (chan < 8) (*muxsg0) = (*muxsg0) | (1 << chan); else if (chan < 16) - (*muxsg1) = (*muxsg1) | (1 << (chan-8)); + (*muxsg1) = (*muxsg1) | (1 << (chan - 8)); } static int usbbuxsigma_send_cmd(struct comedi_device *dev, int cmd_type) @@ -611,19 +609,19 @@ static int usbduxsigma_ai_inttrig(struct comedi_device *dev, if (trig_num != cmd->start_arg) return -EINVAL; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (!devpriv->ai_cmd_running) { devpriv->ai_cmd_running = 1; ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs, devpriv->n_ai_urbs, 1); if (ret < 0) { devpriv->ai_cmd_running = 0; - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } s->async->inttrig = NULL; } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 1; } @@ -634,13 +632,13 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int len = cmd->chanlist_len; - uint8_t muxsg0 = 0; - uint8_t muxsg1 = 0; - uint8_t sysred = 0; + u8 muxsg0 = 0; + u8 muxsg1 = 0; + u8 sysred = 0; int ret; int i; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->high_speed) { /* @@ -675,7 +673,7 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, ret = usbbuxsigma_send_cmd(dev, USBBUXSIGMA_AD_CMD); if (ret < 0) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -688,7 +686,7 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, devpriv->n_ai_urbs, 1); if (ret < 0) { devpriv->ai_cmd_running = 0; - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } s->async->inttrig = NULL; @@ -696,7 +694,7 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, s->async->inttrig = usbduxsigma_ai_inttrig; } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 0; } @@ -708,15 +706,15 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, { struct usbduxsigma_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - uint8_t muxsg0 = 0; - uint8_t muxsg1 = 0; - uint8_t sysred = 0; + u8 muxsg0 = 0; + u8 muxsg1 = 0; + u8 sysred = 0; int ret; int i; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ai_cmd_running) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return -EBUSY; } @@ -733,16 +731,16 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, /* adc commands */ ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); if (ret < 0) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } for (i = 0; i < insn->n; i++) { - uint32_t val; + u32 val; ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); if (ret < 0) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -750,11 +748,9 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, val = be32_to_cpu(get_unaligned((__be32 *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ - val ^= 0x00800000; /* convert to unsigned */ - - data[i] = val; + data[i] = comedi_offset_munge(s, val); } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return insn->n; } @@ -767,9 +763,9 @@ static int usbduxsigma_ao_insn_read(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); ret = comedi_readback_insn_read(dev, s, insn, data); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -784,9 +780,9 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev, int ret; int i; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (devpriv->ao_cmd_running) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return -EBUSY; } @@ -796,12 +792,12 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev, devpriv->dux_commands[3] = chan; /* channel number */ ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_DA_CMD); if (ret < 0) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } s->readback[chan] = data[i]; } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return insn->n; } @@ -817,19 +813,19 @@ static int usbduxsigma_ao_inttrig(struct comedi_device *dev, if (trig_num != cmd->start_arg) return -EINVAL; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); if (!devpriv->ao_cmd_running) { devpriv->ao_cmd_running = 1; ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs, devpriv->n_ao_urbs, 0); if (ret < 0) { devpriv->ao_cmd_running = 0; - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } s->async->inttrig = NULL; } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 1; } @@ -860,7 +856,7 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) { - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 1; } @@ -909,7 +905,7 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, struct comedi_cmd *cmd = &s->async->cmd; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* * For now, only "scan" timing is supported. A future version may @@ -928,7 +924,7 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, devpriv->n_ao_urbs, 0); if (ret < 0) { devpriv->ao_cmd_running = 0; - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } s->async->inttrig = NULL; @@ -936,7 +932,7 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, s->async->inttrig = usbduxsigma_ao_inttrig; } - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return 0; } @@ -967,7 +963,7 @@ static int usbduxsigma_dio_insn_bits(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; int ret; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); comedi_dio_update_state(s, data); @@ -994,7 +990,7 @@ static int usbduxsigma_dio_insn_bits(struct comedi_device *dev, ret = insn->n; done: - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); return ret; } @@ -1220,9 +1216,10 @@ static int usbduxsigma_pwm_config(struct comedi_device *dev, static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) { + struct comedi_subdevice *s = dev->read_subdev; struct usbduxsigma_private *devpriv = dev->private; - uint8_t sysred; - uint32_t val; + u8 sysred; + u32 val; int ret; switch (chan) { @@ -1264,9 +1261,8 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) /* 32 bits big endian from the A/D converter */ val = be32_to_cpu(get_unaligned((__be32 *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ - val ^= 0x00800000; /* convert to unsigned */ - return (int)val; + return (int)comedi_offset_munge(s, val); } static int usbduxsigma_firmware_upload(struct comedi_device *dev, @@ -1274,8 +1270,8 @@ static int usbduxsigma_firmware_upload(struct comedi_device *dev, unsigned long context) { struct usb_device *usb = comedi_to_usb_dev(dev); - uint8_t *buf; - uint8_t *tmp; + u8 *buf; + u8 *tmp; int ret; if (!data) @@ -1466,7 +1462,7 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev, if (!devpriv) return -ENOMEM; - sema_init(&devpriv->sem, 1); + mutex_init(&devpriv->mut); usb_set_intfdata(intf, devpriv); @@ -1580,7 +1576,7 @@ static void usbduxsigma_detach(struct comedi_device *dev) if (!devpriv) return; - down(&devpriv->sem); + mutex_lock(&devpriv->mut); /* force unlink all urbs */ usbduxsigma_ai_stop(dev, 1); @@ -1589,7 +1585,7 @@ static void usbduxsigma_detach(struct comedi_device *dev) usbduxsigma_free_usb_buffers(dev); - up(&devpriv->sem); + mutex_unlock(&devpriv->mut); } static struct comedi_driver usbduxsigma_driver = { diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 3af075aa3..8c7393ef7 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -1,22 +1,23 @@ /* - comedi/drivers/vmk80xx.c - Velleman USB Board Low-Level Driver - - Copyright (C) 2009 Manuel Gebele , Germany - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - 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. + * vmk80xx.c + * Velleman USB Board Low-Level Driver + * + * Copyright (C) 2009 Manuel Gebele , Germany + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * 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: vmk80xx * Description: Velleman USB Board Low-Level Driver @@ -51,52 +52,52 @@ enum { DEVICE_VMK8061 }; -#define VMK8055_DI_REG 0x00 -#define VMK8055_DO_REG 0x01 -#define VMK8055_AO1_REG 0x02 -#define VMK8055_AO2_REG 0x03 -#define VMK8055_AI1_REG 0x02 -#define VMK8055_AI2_REG 0x03 -#define VMK8055_CNT1_REG 0x04 -#define VMK8055_CNT2_REG 0x06 - -#define VMK8061_CH_REG 0x01 -#define VMK8061_DI_REG 0x01 -#define VMK8061_DO_REG 0x01 -#define VMK8061_PWM_REG1 0x01 -#define VMK8061_PWM_REG2 0x02 -#define VMK8061_CNT_REG 0x02 -#define VMK8061_AO_REG 0x02 -#define VMK8061_AI_REG1 0x02 -#define VMK8061_AI_REG2 0x03 - -#define VMK8055_CMD_RST 0x00 -#define VMK8055_CMD_DEB1_TIME 0x01 -#define VMK8055_CMD_DEB2_TIME 0x02 -#define VMK8055_CMD_RST_CNT1 0x03 -#define VMK8055_CMD_RST_CNT2 0x04 -#define VMK8055_CMD_WRT_AD 0x05 - -#define VMK8061_CMD_RD_AI 0x00 -#define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */ -#define VMK8061_CMD_SET_AO 0x02 -#define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */ -#define VMK8061_CMD_OUT_PWM 0x04 -#define VMK8061_CMD_RD_DI 0x05 -#define VMK8061_CMD_DO 0x06 /* !non-active! */ -#define VMK8061_CMD_CLR_DO 0x07 -#define VMK8061_CMD_SET_DO 0x08 -#define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */ -#define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */ -#define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */ -#define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */ -#define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */ -#define VMK8061_CMD_RD_DO 0x0e -#define VMK8061_CMD_RD_AO 0x0f -#define VMK8061_CMD_RD_PWM 0x10 - -#define IC3_VERSION (1 << 0) -#define IC6_VERSION (1 << 1) +#define VMK8055_DI_REG 0x00 +#define VMK8055_DO_REG 0x01 +#define VMK8055_AO1_REG 0x02 +#define VMK8055_AO2_REG 0x03 +#define VMK8055_AI1_REG 0x02 +#define VMK8055_AI2_REG 0x03 +#define VMK8055_CNT1_REG 0x04 +#define VMK8055_CNT2_REG 0x06 + +#define VMK8061_CH_REG 0x01 +#define VMK8061_DI_REG 0x01 +#define VMK8061_DO_REG 0x01 +#define VMK8061_PWM_REG1 0x01 +#define VMK8061_PWM_REG2 0x02 +#define VMK8061_CNT_REG 0x02 +#define VMK8061_AO_REG 0x02 +#define VMK8061_AI_REG1 0x02 +#define VMK8061_AI_REG2 0x03 + +#define VMK8055_CMD_RST 0x00 +#define VMK8055_CMD_DEB1_TIME 0x01 +#define VMK8055_CMD_DEB2_TIME 0x02 +#define VMK8055_CMD_RST_CNT1 0x03 +#define VMK8055_CMD_RST_CNT2 0x04 +#define VMK8055_CMD_WRT_AD 0x05 + +#define VMK8061_CMD_RD_AI 0x00 +#define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */ +#define VMK8061_CMD_SET_AO 0x02 +#define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */ +#define VMK8061_CMD_OUT_PWM 0x04 +#define VMK8061_CMD_RD_DI 0x05 +#define VMK8061_CMD_DO 0x06 /* !non-active! */ +#define VMK8061_CMD_CLR_DO 0x07 +#define VMK8061_CMD_SET_DO 0x08 +#define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */ +#define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */ +#define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */ +#define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */ +#define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */ +#define VMK8061_CMD_RD_DO 0x0e +#define VMK8061_CMD_RD_AO 0x0f +#define VMK8061_CMD_RD_PWM 0x10 + +#define IC3_VERSION BIT(0) +#define IC6_VERSION BIT(1) enum vmk80xx_model { VMK8055_MODEL, diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index 76bf5619f..d0a8a28ed 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -1,20 +1,20 @@ /* - kcomedilib/kcomedilib.c - a comedlib interface for kernel modules - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-2000 David A. Schleef - - 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. -*/ + * kcomedilib/kcomedilib.c + * a comedlib interface for kernel modules + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef + * + * 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 -- cgit v1.2.3-54-g00ecf