aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r--drivers/staging/comedi/Kconfig10
-rw-r--r--drivers/staging/comedi/comedi_buf.c125
-rw-r--r--drivers/staging/comedi/comedi_fops.c180
-rw-r--r--drivers/staging/comedi/comedi_internal.h1
-rw-r--r--drivers/staging/comedi/comedi_pci.c108
-rw-r--r--drivers/staging/comedi/comedi_pcmcia.c104
-rw-r--r--drivers/staging/comedi/comedi_usb.c75
-rw-r--r--drivers/staging/comedi/comedidev.h635
-rw-r--r--drivers/staging/comedi/drivers.c407
-rw-r--r--drivers/staging/comedi/drivers/8255.h12
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c4
-rw-r--r--drivers/staging/comedi/drivers/Makefile1
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c7
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c16
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c59
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c6
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c171
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c289
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c136
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c304
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c33
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c15
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c201
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c284
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c1175
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c565
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c8
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c466
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c66
-rw-r--r--drivers/staging/comedi/drivers/fl512.c2
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c28
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c517
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c84
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c7
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c315
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c137
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c411
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c358
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_usb6501.c16
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c19
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c186
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c109
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c40
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c112
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c684
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c369
-rw-r--r--drivers/staging/comedi/drivers/rti800.c28
-rw-r--r--drivers/staging/comedi/drivers/s526.c560
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c51
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c57
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c506
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c164
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c310
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c142
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c127
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c32
60 files changed, 5540 insertions, 5310 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 57e71f9f14a2..ac0f01007abd 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 19e7b229d15e..90c28016c6c1 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 0e8a45102933..7b4af519e17e 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 cd9437f72c35..3f2c88ae6470 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 027f0f4e59c1..51e023a1c0ee 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 7e784399a16f..d7072a5c1647 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 68b75e8feec0..9c946d40b894 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 28a5d3a037a1..115807215484 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * 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 <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#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 b03bc6639f79..b63dd2ef78b5 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 <ds@schleef.org>
- Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ * module/drivers.c
+ * functions for manipulating drivers
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
-#include <linux/kconfig.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fcntl.h>
#include <linux/ioport.h>
-#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/highmem.h> /* for SuSE brokenness */
-#include <linux/vmalloc.h>
-#include <linux/cdev.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
+#include <linux/dma-direction.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
@@ -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 41823de69b77..55a67af5152d 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 bb9854b56807..38c05d1ec647 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 5764dc9a6893..c3b8f2d7611b 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 b37166d57b64..ccd1a91290bf 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 ad715253bdcc..50f9eb25d7cb 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 5bfd43d5c889..3630d75e36e8 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 bef6efc84efd..995096c78844 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 7ed3fd6fbd3e..ad7e7c4a5232 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 c9df3afe97f6..01d2ee931b28 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 <emmanuel.pacaud@univ-poitiers.fr>
-
-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 <emmanuel.pacaud@univ-poitiers.fr>
+ *
+ * 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 <emmanuel.pacaud@univ-poitiers.fr>
-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 <emmanuel.pacaud@univ-poitiers.fr>
+ * 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 <linux/module.h>
#include <linux/delay.h>
@@ -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 fb3043dcfff1..0dff1dbb53fb 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 bc5f97f50f9a..315050454c26 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: adq12b
-Description: driver for MicroAxial ADQ12-B data acquisition and control card
-Devices: [MicroAxial] ADQ12-B (adq12b)
-Author: jeremy theler <thelerg@ib.cnea.gov.ar>
-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 <thelerg@ib.cnea.gov.ar>
+ * 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 <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
- 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 <thelerg@ib.cnea.gov.ar>
-
- 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 <thelerg@ib.cnea.gov.ar>
+ * 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 <linux/module.h>
#include <linux/delay.h>
@@ -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 0c6aa964c884..399c511cfe0a 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 <dobes@tesnet.cz>
*
* Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
* 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 <dobes@tesnet.cz>
+ * 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 <dobes@tesnet.cz>
-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 <linux/module.h>
#include <linux/interrupt.h>
@@ -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 1921a97cc5ca..f82afd947310 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 9677111f9ab2..bf6a8f10118c 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 fbc3e5aa94cb..43a0ce5721d3 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 <pablo.mejia@cctechnol.com>
-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 <pablo.mejia@cctechnol.com>
+ * 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 <linux/module.h>
#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 5c5c4e2ec3d5..4b39f6960c0a 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 ae84f2c0cc9c..78d098f9e1f2 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 <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ * <dahinds@users.sourceforge.net>. 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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
- <dahinds@users.sourceforge.net>. 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 <linux/module.h>
#include <linux/interrupt.h>
@@ -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 b43e836575fd..3cd008acb657 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 <imr@oersted.dtu.dk>
+ * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
- 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 <imr@oersted.dtu.dk>
- Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: cb_pcidas
-Description: MeasurementComputing PCI-DAS series
- with the AMCC S5933 PCI controller
-Author: Ivan Martinez <imr@oersted.dtu.dk>,
- Frank Mori Hess <fmhess@users.sourceforge.net>
-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 <imr@oersted.dtu.dk>,
+ * Frank Mori Hess <fmhess@users.sourceforge.net>
+ * 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 <linux/module.h>
#include <linux/delay.h>
@@ -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 80d613c0fbc6..4ab186669f0c 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 <Joachim.Wuttke@icn.siemens.de>
+ * Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
- 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 <Joachim.Wuttke@icn.siemens.de>
- Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net>
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
/*
-Driver: comedi_test
-Description: generates fake waveforms
-Author: Joachim Wuttke <Joachim.Wuttke@icn.siemens.de>, Frank Mori Hess
- <fmhess@users.sourceforge.net>, 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 <Joachim.Wuttke@icn.siemens.de>, Frank Mori Hess
+ * <fmhess@users.sourceforge.net>, 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 <linux/module.h>
#include "../comedidev.h"
@@ -52,30 +52,31 @@ zero volts).
#include <linux/timer.h>
#include <linux/ktime.h>
+#include <linux/jiffies.h>
#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 611b0a3ef5d7..57ab6680e3ae 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 8c4f284d1919..ab7a332fbcc4 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: 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 <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
-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 <linux/module.h>
#include <linux/delay.h>
@@ -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 e11c216a4c85..3295bb4ac8c4 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 55cae61458cb..0f278ffdad76 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 e9296182236e..46ca5d938d5b 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 1e104ebf8057..28cf53e48b8d 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * icp_multi.c
+ * Comedi driver for Inova ICP_MULTI board
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2002 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
/*
-Driver: icp_multi
-Description: Inova ICP_MULTI
-Author: Anne Smorthit <anne.smorthit@sfwte.ch>
-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 <anne.smorthit@sfwte.ch>
+ * 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 <linux/module.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
#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 14ef1f67dd42..77e1d891f232 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/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index dc642edf4f65..93198abf0ee5 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 9ea1ba4b1b6f..3bf0caa18ab0 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 a675e2ef9b45..fbdf181d8ccc 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 0207b8edfcb4..826e4399c87e 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * 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 <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
/*
-Driver: mpc624
-Description: Micro/sys MPC-624 PC/104 board
-Devices: [Micro/sys] MPC-624 (mpc624)
-Author: Stanislaw Raczynski <sraczynski@op.pl>
-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 <sraczynski@op.pl>
+ * 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 <linux/module.h>
#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 8471219210b6..b5a26f7b4332 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 <anders.blomdell@control.lth.se>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ * multiq3.c
+ * Hardware driver for Quanser Consulting MultiQ-3 board
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
-/*
-Driver: multiq3
-Description: Quanser Consulting MultiQ-3
-Author: Anders Blomdell <anders.blomdell@control.lth.se>
-Status: works
-Devices: [Quanser Consulting] MultiQ-3 (multiq3)
-
-*/
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include "../comedidev.h"
/*
- * MULTIQ-3 port offsets
+ * Driver: multiq3
+ * Description: Quanser Consulting MultiQ-3
+ * Devices: [Quanser Consulting] MultiQ-3 (multiq3)
+ * Author: Anders Blomdell <anders.blomdell@control.lth.se>
+ * 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 <linux/module.h>
-#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 c20c51bef3e7..b74e44ec521a 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 9b124b09e914..437f723bb34d 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 88de8da3eff3..95b537a8ecdb 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 cfc3a627d0ca..3774daa9d661 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 48f6cdf440b9..9c75065dd26a 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 a353d1b155bb..c00a71f538ef 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 <juan@grigera.com.ar>
- based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
+ * pcl816.c
+ * Comedi driver for Advantech PCL-816 cards
+ *
+ * Author: Juan Grigera <juan@grigera.com.ar>
+ * based on pcl818 by Michal Dobes <dobes@tesnet.cz> 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 <juan@grigera.com.ar>
-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 <juan@grigera.com.ar>
+ * 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 <linux/module.h>
#include <linux/gfp.h>
@@ -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 e1bdde977302..5aeed44dff70 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 6176dfa24801..588ae5ecec66 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 <drew_csillag@yahoo.com>
-
- hardware driver for Advantech card:
- card: PCM-3724
- driver: pcm3724
+ * pcm3724.c
+ * Comedi driver for Advantech PCM-3724 Digital I/O board
+ *
+ * Drew Csillag <drew_csillag@yahoo.com>
+ */
- Options for PCM-3724
- [0] - IO Base
-*/
-/*
-Driver: pcm3724
-Description: Advantech PCM-3724
-Author: Drew Csillag <drew_csillag@yahoo.com>
-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 <drew_csillag@yahoo.com>
+ * 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 <linux/module.h>
@@ -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 152cb146fc16..e9e43139157d 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 <baccala@freesoft.org>
- 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 <ds@schleef.org>
- 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 <baccala@freesoft.org>
+ * 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 <ds@schleef.org>
+ * 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 <baccala@freesoft.org>
-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 <baccala@freesoft.org>
+ * Status: works
+ */
#include <linux/module.h>
-#include <linux/semaphore.h>
-#include <linux/completion.h>
#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 4c13f5eb0c84..68ac02b68cb2 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 340ac776e951..cd61d2645af4 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 6f3e8a08e75c..d70c97947627 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: s526
-Description: Sensoray 526 driver
-Devices: [Sensoray] 526 (s526)
-Author: Richie
- Everett Wang <everett.wang@everteq.com>
-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 <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
-comedi_config /dev/comedi0 s526 0x2C0,0x3
-
-*/
+/*
+ * Driver: s526
+ * Description: Sensoray 526 driver
+ * Devices: [Sensoray] 526 (s526)
+ * Author: Richie
+ * Everett Wang <everett.wang@everteq.com>
+ * 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 <linux/module.h>
#include "../comedidev.h"
#include <asm/byteorder.h>
-#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 5f19374c460d..7a1defcf2102 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 <anders.blomdell@control.lth.se>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * serial2002.c
+ * Comedi driver for serial connected hardware
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2002 Anders Blomdell <anders.blomdell@control.lth.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
/*
-Driver: 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 <linux/module.h>
#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 acc7f3445c58..f9f634fd53cf 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 <robert@schwebel.de>
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * ssv_dnp.c
+ * generic comedi driver for SSV Embedded Systems' DIL/Net-PCs
+ * Copyright (C) 2001 Robert Schwebel <robert@schwebel.de>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
/*
-Driver: ssv_dnp
-Description: SSV Embedded Systems DIL/Net-PC
-Author: Robert Schwebel <robert@schwebel.de>
-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 <robert@schwebel.de>
+ * 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 51498b889c6c..000000000000
--- 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 <ds@schleef.org> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- ***************************************************************************/
-/*
-
-Driver: unioxx5
-Description: Driver for Fastwel UNIOxx-5 (analog and digital i/o) boards.
-Author: Kruchinin Daniil (asgard) <asgard@etersoft.ru>
-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 <linux/module.h>
-#include <linux/delay.h>
-#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 ced05e581620..f4f05d29d30d 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 d90dc59982be..10f94ec34536 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 649cf47184a4..456e9f13becb 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 3af075aa3946..8c7393ef762d 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 <forensixs@gmx.de>, Germany
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ * vmk80xx.c
+ * Velleman USB Board Low-Level Driver
+ *
+ * Copyright (C) 2009 Manuel Gebele <forensixs@gmx.de>, Germany
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
/*
* Driver: 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 76bf5619fdd5..d0a8a28edd36 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 <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * kcomedilib/kcomedilib.c
+ * a comedlib interface for kernel modules
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#include <linux/module.h>