*/
/*
-Driver: amplc_dio200.o
-Description: Amplicon PC272E, PCI272
+Driver: amplc_dio200
+Description: Amplicon 200 Series Digital I/O
Author: Ian Abbott <abbotti@mev.co.uk>
Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e),
- PCI215 (pci215), PC218E (pc218e), PC272E (pc272e), PCI272 (pci272)
-Updated: Fri, 07 Oct 2005 16:59:59 +0100
+ PCI215 (pci215 or amplc_dio200), PC218E (pc218e), PC272E (pc272e),
+ PCI272 (pci272 or amplc_dio200)
+Updated: Wed, 22 Oct 2008 13:36:02 +0100
Status: works
Configuration options - PC212E, PC214E, PC215E, PC218E, PC272E:
Passing a zero for an option is the same as leaving it unspecified.
-
SUBDEVICES
PC218E PC212E PC215E/PCI215
2 CTR-Z1* PPI-Z
3 INTERRUPT* INTERRUPT
-
Each PPI is a 8255 chip providing 24 DIO channels. The DIO channels
are configurable as inputs or outputs in four groups:
data[1]; others return a value in data[1]. The following configuration
instructions are supported:
- INSN_CONFIG_8254_SET_MODE. Sets the counter channel's mode and
+ INSN_CONFIG_SET_COUNTER_MODE. Sets the counter channel's mode and
BCD/binary setting specified in data[1].
INSN_CONFIG_8254_READ_STATUS. Reads the status register value for the
channels on the chip.
INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current
- clock source in data[1].
+ clock source in data[1]. For internal clock sources, data[2] is set
+ to the period in ns.
INSN_CONFIG_SET_GATE_SRC. Sets the counter channel's gate source as
specified in data[2] (this is a hardware-specific value). Not
have an interrupt status register; see notes on 'INTERRUPT SOURCES'
below.
-
INTERRUPT SOURCES
PC218E PC212E PC215E/PCI215
channel and its interrupt source is selected by the position of jumper
J5.
-
COMMANDS
The driver supports a read streaming acquisition command on the
#include <linux/comedidev.h>
-#include <linux/pci.h>
+#include "comedi_pci.h"
#include "8255.h"
#include "8253.h"
/* #define PCI_VENDOR_ID_AMPLICON 0x14dc */
#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
#define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
+#define PCI_DEVICE_ID_INVALID 0xffff
/* 200 series registers */
#define DIO200_IO_SIZE 0x20
#define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
#define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
+/*
+ * Periods of the internal clock sources in nanoseconds.
+ */
+static const unsigned clock_period[8] = {
+ 0, /* dedicated clock input/output pin */
+ 100, /* 10 MHz */
+ 1000, /* 1 MHz */
+ 10000, /* 100 kHz */
+ 100000, /* 10 kHz */
+ 1000000, /* 1 kHz */
+ 0, /* OUT N-1 */
+ 0 /* group clock input pin */
+};
+
/*
* Board descriptions.
*/
-enum dio200_bustype { isa_bustype, pci_bustype };
+enum dio200_bustype { isa_bustype, pci_bustype };
enum dio200_model {
pc212e_model,
pc214e_model,
pc215e_model, pci215_model,
pc218e_model,
- pc272e_model, pci272_model
+ pc272e_model, pci272_model,
+ anypci_model
};
enum dio200_layout {
};
typedef struct dio200_board_struct {
- char *name;
+ const char *name;
+ unsigned short devid;
enum dio200_bustype bustype;
enum dio200_model model;
enum dio200_layout layout;
} dio200_board;
-static dio200_board dio200_boards[] = {
+static const dio200_board dio200_boards[] = {
+ {
+ name: "pc212e",
+ bustype: isa_bustype,
+ model: pc212e_model,
+ layout: pc212_layout,
+ },
{
- name: "pc212e",
- bustype: isa_bustype,
- model: pc212e_model,
- layout: pc212_layout,
- },
+ name: "pc214e",
+ bustype: isa_bustype,
+ model: pc214e_model,
+ layout: pc214_layout,
+ },
{
- name: "pc214e",
- bustype: isa_bustype,
- model: pc214e_model,
- layout: pc214_layout,
- },
+ name: "pc215e",
+ bustype: isa_bustype,
+ model: pc215e_model,
+ layout: pc215_layout,
+ },
+#ifdef CONFIG_COMEDI_PCI
{
- name: "pc215e",
- bustype: isa_bustype,
- model: pc215e_model,
- layout: pc215_layout,
- },
+ name: "pci215",
+ devid: PCI_DEVICE_ID_AMPLICON_PCI215,
+ bustype: pci_bustype,
+ model: pci215_model,
+ layout: pc215_layout,
+ },
+#endif
{
- name: "pci215",
- bustype: pci_bustype,
- model: pci215_model,
- layout: pc215_layout,
- },
+ name: "pc218e",
+ bustype: isa_bustype,
+ model: pc218e_model,
+ layout: pc218_layout,
+ },
{
- name: "pc218e",
- bustype: isa_bustype,
- model: pc218e_model,
- layout: pc218_layout,
- },
+ name: "pc272e",
+ bustype: isa_bustype,
+ model: pc272e_model,
+ layout: pc272_layout,
+ },
+#ifdef CONFIG_COMEDI_PCI
{
- name: "pc272e",
- bustype: isa_bustype,
- model: pc272e_model,
- layout: pc272_layout,
- },
+ name: "pci272",
+ devid: PCI_DEVICE_ID_AMPLICON_PCI272,
+ bustype: pci_bustype,
+ model: pci272_model,
+ layout: pc272_layout,
+ },
+#endif
+#ifdef CONFIG_COMEDI_PCI
{
- name: "pci272",
- bustype: pci_bustype,
- model: pci272_model,
- layout: pc272_layout,
- },
+ name: DIO200_DRIVER_NAME,
+ devid: PCI_DEVICE_ID_INVALID,
+ bustype: pci_bustype,
+ model: anypci_model, /* wildcard */
+ },
+#endif
};
/*
* layout.
*/
-enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 };
+enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 };
#define DIO200_MAX_SUBDEVS 7
#define DIO200_MAX_ISNS 6
typedef struct dio200_layout_struct {
unsigned short n_subdevs; /* number of subdevices */
- unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
- unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
- char has_int_sce; /* has interrupt enable/status register */
- char has_clk_gat_sce; /* has clock/gate selection registers */
+ unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
+ unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
+ char has_int_sce; /* has interrupt enable/status register */
+ char has_clk_gat_sce; /* has clock/gate selection registers */
} dio200_layout;
-static dio200_layout dio200_layouts[] = {
+static const dio200_layout dio200_layouts[] = {
[pc212_layout] = {
- n_subdevs: 6,
- sdtype: { sd_8255, sd_8254, sd_8254, sd_8254, sd_8254, sd_intr },
- sdinfo: { 0x00, 0x08, 0x0C, 0x10, 0x14, 0x3F },
- has_int_sce: 1,
- has_clk_gat_sce: 1,
- },
+ n_subdevs:6,
+ sdtype: {sd_8255, sd_8254, sd_8254, sd_8254,
+ sd_8254,
+ sd_intr},
+ sdinfo: {0x00, 0x08, 0x0C, 0x10, 0x14,
+ 0x3F},
+ has_int_sce:1,
+ has_clk_gat_sce:1,
+ },
[pc214_layout] = {
- n_subdevs: 4,
- sdtype: { sd_8255, sd_8255, sd_8254, sd_intr },
- sdinfo: { 0x00, 0x08, 0x10, 0x01 },
- has_int_sce: 0,
- has_clk_gat_sce: 0,
- },
+ n_subdevs:4,
+ sdtype: {sd_8255, sd_8255, sd_8254,
+ sd_intr},
+ sdinfo: {0x00, 0x08, 0x10, 0x01},
+ has_int_sce:0,
+ has_clk_gat_sce:0,
+ },
[pc215_layout] = {
- n_subdevs: 5,
- sdtype: { sd_8255, sd_8255, sd_8254, sd_8254, sd_intr },
- sdinfo: { 0x00, 0x08, 0x10, 0x14, 0x3F },
- has_int_sce: 1,
- has_clk_gat_sce: 1,
- },
+ n_subdevs:5,
+ sdtype: {sd_8255, sd_8255, sd_8254,
+ sd_8254,
+ sd_intr},
+ sdinfo: {0x00, 0x08, 0x10, 0x14, 0x3F},
+ has_int_sce:1,
+ has_clk_gat_sce:1,
+ },
[pc218_layout] = {
- n_subdevs: 7,
- sdtype: { sd_8254, sd_8254, sd_8255, sd_8254, sd_8254, sd_intr },
- sdinfo: { 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x3F },
- has_int_sce: 1,
- has_clk_gat_sce: 1,
- },
+ n_subdevs:7,
+ sdtype: {sd_8254, sd_8254, sd_8255, sd_8254,
+ sd_8254,
+ sd_intr},
+ sdinfo: {0x00, 0x04, 0x08, 0x0C, 0x10,
+ 0x14,
+ 0x3F},
+ has_int_sce:1,
+ has_clk_gat_sce:1,
+ },
[pc272_layout] = {
- n_subdevs: 4,
- sdtype: { sd_8255, sd_8255, sd_8255, sd_intr },
- sdinfo: { 0x00, 0x08, 0x10, 0x3F },
- has_int_sce: 1,
- has_clk_gat_sce: 0,
- },
+ n_subdevs:4,
+ sdtype: {sd_8255, sd_8255, sd_8255,
+ sd_intr},
+ sdinfo: {0x00, 0x08, 0x10, 0x3F},
+ has_int_sce:1,
+ has_clk_gat_sce:0,
+ },
};
/*
* PCI driver table.
*/
-static struct pci_device_id dio200_pci_table[] __devinitdata = {
- { PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, pci215_model },
- { PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, pci272_model },
- { 0 }
+#ifdef CONFIG_COMEDI_PCI
+static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
+ {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0}
};
+
MODULE_DEVICE_TABLE(pci, dio200_pci_table);
+#endif /* CONFIG_COMEDI_PCI */
/*
* Useful for shorthand access to the particular board structure
*/
-#define thisboard ((dio200_board *)dev->board_ptr)
+#define thisboard ((const dio200_board *)dev->board_ptr)
#define thislayout (&dio200_layouts[((dio200_board *)dev->board_ptr)->layout])
/* this structure is for data unique to this hardware driver. If
several hardware drivers keep similar information in this structure,
feel free to suggest moving the variable to the comedi_device struct. */
typedef struct {
+#ifdef CONFIG_COMEDI_PCI
struct pci_dev *pci_dev; /* PCI device */
+#endif
int intr_sd;
} dio200_private;
#define devpriv ((dio200_private *)dev->private)
typedef struct {
- unsigned long iobase; /* Counter base address */
+ unsigned long iobase; /* Counter base address */
unsigned long clk_sce_iobase; /* CLK_SCE base address */
unsigned long gat_sce_iobase; /* GAT_SCE base address */
- int which; /* Bit 5 of CLK_SCE or GAT_SCE */
- int has_clk_gat_sce;
- unsigned clock_src[3]; /* Current clock sources */
- unsigned gate_src[3]; /* Current gate sources */
+ int which; /* Bit 5 of CLK_SCE or GAT_SCE */
+ unsigned clock_src[3]; /* Current clock sources */
+ unsigned gate_src[3]; /* Current gate sources */
+ spinlock_t spinlock;
} dio200_subdev_8254;
typedef struct {
int continuous;
} dio200_subdev_intr;
-
/*
* The comedi_driver structure tells the Comedi core module
* which functions to call to configure/deconfigure (attach/detach)
* the board, and also about the kernel module that contains
* the device code.
*/
-static int dio200_attach(comedi_device *dev,comedi_devconfig *it);
-static int dio200_detach(comedi_device *dev);
+static int dio200_attach(comedi_device * dev, comedi_devconfig * it);
+static int dio200_detach(comedi_device * dev);
static comedi_driver driver_amplc_dio200 = {
- driver_name: DIO200_DRIVER_NAME,
- module: THIS_MODULE,
- attach: dio200_attach,
- detach: dio200_detach,
- board_name: (const char**)dio200_boards,
- offset: sizeof(dio200_board),
- num_names: sizeof(dio200_boards) / sizeof(dio200_board),
+ driver_name:DIO200_DRIVER_NAME,
+ module:THIS_MODULE,
+ attach:dio200_attach,
+ detach:dio200_detach,
+ board_name:&dio200_boards[0].name,
+ offset:sizeof(dio200_board),
+ num_names:sizeof(dio200_boards) / sizeof(dio200_board),
};
+
+#ifdef CONFIG_COMEDI_PCI
+COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
+#else
COMEDI_INITCLEANUP(driver_amplc_dio200);
+#endif
/*
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
+#ifdef CONFIG_COMEDI_PCI
static int
-dio200_find_pci(comedi_device *dev, int bus, int slot,
- struct pci_dev **pci_dev_p)
+dio200_find_pci(comedi_device * dev, int bus, int slot,
+ struct pci_dev **pci_dev_p)
{
struct pci_dev *pci_dev = NULL;
- struct pci_device_id *pci_id;
*pci_dev_p = NULL;
- /* Look for PCI table entry for this model. */
- for (pci_id = dio200_pci_table; pci_id->vendor != 0; pci_id++) {
- if (pci_id->driver_data == thisboard->model)
- break;
- }
- if (pci_id->vendor == 0) {
- printk(KERN_ERR "comedi%d: %s: BUG! cannot determine board type!\n",
- dev->minor, DIO200_DRIVER_NAME);
- return -EINVAL;
- }
-
/* Look for matching PCI device. */
- for(pci_dev = pci_get_device(pci_id->vendor, pci_id->device, NULL);
- pci_dev != NULL ;
- pci_dev = pci_get_device(pci_id->vendor,
- pci_id->device, pci_dev)) {
+ for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
+ pci_dev != NULL;
+ pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
+ PCI_ANY_ID, pci_dev)) {
/* If bus/slot specified, check them. */
if (bus || slot) {
if (bus != pci_dev->bus->number
- || slot != PCI_SLOT(pci_dev->devfn))
+ || slot != PCI_SLOT(pci_dev->devfn))
continue;
}
-#if 0
- if (pci_id->subvendor != PCI_ANY_ID) {
- if (pci_dev->subsystem_vendor != pci_id->subvendor)
+ if (thisboard->model == anypci_model) {
+ /* Match any supported model. */
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
+ if (dio200_boards[i].bustype != pci_bustype)
+ continue;
+ if (pci_dev->device == dio200_boards[i].devid) {
+ /* Change board_ptr to matched board. */
+ dev->board_ptr = &dio200_boards[i];
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(dio200_boards))
continue;
- }
- if (pci_id->subdevice != PCI_ANY_ID) {
- if (pci_dev->subsystem_device != pci_id->subdevice)
+ } else {
+ /* Match specific model name. */
+ if (pci_dev->device != thisboard->devid)
continue;
}
-#endif
- if (((pci_dev->class ^ pci_id->class) & pci_id->class_mask) != 0)
- continue;
/* Found a match. */
*pci_dev_p = pci_dev;
}
/* No match found. */
if (bus || slot) {
- printk(KERN_ERR "comedi%d: error! no %s found at pci %02x:%02x!\n",
- dev->minor, thisboard->name,
- bus, slot);
+ printk(KERN_ERR
+ "comedi%d: error! no %s found at pci %02x:%02x!\n",
+ dev->minor, thisboard->name, bus, slot);
} else {
printk(KERN_ERR "comedi%d: error! no %s found!\n",
- dev->minor, thisboard->name);
+ dev->minor, thisboard->name);
}
return -EIO;
}
+#endif
/*
* This function checks and requests an I/O region, reporting an error
{
if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
- minor, from, extent);
+ minor, from, extent);
return -EIO;
}
return 0;
* 'insn_bits' function for an 'INTERRUPT' subdevice.
*/
static int
-dio200_subdev_intr_insn_bits(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *data)
+dio200_subdev_intr_insn_bits(comedi_device * dev, comedi_subdevice * s,
+ comedi_insn * insn, lsampl_t * data)
{
dio200_subdev_intr *subpriv = s->private;
/*
* Called to stop acquisition for an 'INTERRUPT' subdevice.
*/
-static void
-dio200_stop_intr(comedi_device *dev, comedi_subdevice *s)
+static void dio200_stop_intr(comedi_device * dev, comedi_subdevice * s)
{
dio200_subdev_intr *subpriv = s->private;
- s->async->inttrig = 0;
subpriv->active = 0;
subpriv->enabled_isns = 0;
if (subpriv->has_int_sce) {
/*
* Called to start acquisition for an 'INTERRUPT' subdevice.
*/
-static int
-dio200_start_intr(comedi_device *dev, comedi_subdevice *s)
+static int dio200_start_intr(comedi_device * dev, comedi_subdevice * s)
{
unsigned int n;
unsigned isn_bits;
* Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
*/
static int
-dio200_inttrig_start_intr(comedi_device *dev, comedi_subdevice *s,
- unsigned int trignum)
+dio200_inttrig_start_intr(comedi_device * dev, comedi_subdevice * s,
+ unsigned int trignum)
{
dio200_subdev_intr *subpriv;
unsigned long flags;
int event = 0;
- if (trignum != 0) return -EINVAL;
+ if (trignum != 0)
+ return -EINVAL;
subpriv = s->private;
comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
if (event) {
- comedi_event(dev, s, s->async->events);
+ comedi_event(dev, s);
}
return 1;
* This is called from the interrupt service routine to handle a read
* scan on an 'INTERRUPT' subdevice.
*/
-static int
-dio200_handle_read_intr(comedi_device *dev, comedi_subdevice *s)
+static int dio200_handle_read_intr(comedi_device * dev, comedi_subdevice * s)
{
dio200_subdev_intr *subpriv = s->private;
unsigned triggered;
*/
cur_enabled = subpriv->enabled_isns;
while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns
- & ~triggered)) != 0) {
+ & ~triggered)) != 0) {
triggered |= intstat;
cur_enabled &= ~triggered;
outb(cur_enabled, subpriv->iobase);
/* Write the scan to the buffer. */
if (comedi_buf_put(s->async, val)) {
s->async->events |= (COMEDI_CB_BLOCK |
- COMEDI_CB_EOS);
+ COMEDI_CB_EOS);
} else {
/* Error! Stop acquisition. */
dio200_stop_intr(dev, s);
+ s->async->events |= COMEDI_CB_ERROR
+ | COMEDI_CB_OVERFLOW;
+ comedi_error(dev, "buffer overflow");
}
/* Check for end of acquisition. */
if (subpriv->stopcount == 0) {
s->async->events |=
COMEDI_CB_EOA;
- dio200_stop_intr(dev, s);
+ dio200_stop_intr(dev,
+ s);
}
}
}
comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
if (oldevents != s->async->events) {
- comedi_event(dev, s, s->async->events);
+ comedi_event(dev, s);
}
return (triggered != 0);
/*
* 'cancel' function for an 'INTERRUPT' subdevice.
*/
-static int
-dio200_subdev_intr_cancel(comedi_device *dev, comedi_subdevice *s)
+static int dio200_subdev_intr_cancel(comedi_device * dev, comedi_subdevice * s)
{
dio200_subdev_intr *subpriv = s->private;
unsigned long flags;
* 'do_cmdtest' function for an 'INTERRUPT' subdevice.
*/
static int
-dio200_subdev_intr_cmdtest(comedi_device *dev, comedi_subdevice *s,
- comedi_cmd *cmd)
+dio200_subdev_intr_cmdtest(comedi_device * dev, comedi_subdevice * s,
+ comedi_cmd * cmd)
{
int err = 0;
unsigned int tmp;
tmp = cmd->start_src;
cmd->start_src &= (TRIG_NOW | TRIG_INT);
- if (!cmd->start_src || tmp != cmd->start_src) err++;
+ if (!cmd->start_src || tmp != cmd->start_src)
+ err++;
tmp = cmd->scan_begin_src;
cmd->scan_begin_src &= TRIG_EXT;
- if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++;
+ if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
+ err++;
tmp = cmd->convert_src;
cmd->convert_src &= TRIG_NOW;
- if (!cmd->convert_src || tmp != cmd->convert_src) err++;
+ if (!cmd->convert_src || tmp != cmd->convert_src)
+ err++;
tmp = cmd->scan_end_src;
cmd->scan_end_src &= TRIG_COUNT;
- if (!cmd->scan_end_src || tmp != cmd->scan_end_src) err++;
+ if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
+ err++;
tmp = cmd->stop_src;
cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
- if (!cmd->stop_src || tmp != cmd->stop_src) err++;
+ if (!cmd->stop_src || tmp != cmd->stop_src)
+ err++;
- if (err) return 1;
+ if (err)
+ return 1;
/* step 2: make sure trigger sources are unique and mutually compatible */
/* these tests are true if more than one _src bit is set */
- if ((cmd->start_src & (cmd->start_src - 1)) != 0) err++;
- if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) err++;
- if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) err++;
- if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) err++;
- if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) err++;
+ if ((cmd->start_src & (cmd->start_src - 1)) != 0)
+ err++;
+ if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
+ err++;
+ if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
+ err++;
+ if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
+ err++;
+ if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
+ err++;
- if (err) return 2;
+ if (err)
+ return 2;
/* step 3: make sure arguments are trivially compatible */
break;
}
- if (err) return 3;
+ if (err)
+ return 3;
/* step 4: fix up any arguments */
/*
* 'do_cmd' function for an 'INTERRUPT' subdevice.
*/
-static int
-dio200_subdev_intr_cmd(comedi_device *dev, comedi_subdevice *s)
+static int dio200_subdev_intr_cmd(comedi_device * dev, comedi_subdevice * s)
{
comedi_cmd *cmd = &s->async->cmd;
dio200_subdev_intr *subpriv = s->private;
comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
if (event) {
- comedi_event(dev, s, s->async->events);
+ comedi_event(dev, s);
}
return 0;
* This function initializes an 'INTERRUPT' subdevice.
*/
static int
-dio200_subdev_intr_init(comedi_device *dev, comedi_subdevice *s,
- unsigned long iobase, unsigned valid_isns, int has_int_sce)
+dio200_subdev_intr_init(comedi_device * dev, comedi_subdevice * s,
+ unsigned long iobase, unsigned valid_isns, int has_int_sce)
{
dio200_subdev_intr *subpriv;
- subpriv = kmalloc(sizeof(*subpriv), GFP_KERNEL);
+ subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
if (!subpriv) {
- printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor);
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
return -ENOMEM;
}
- memset(subpriv, 0, sizeof(*subpriv));
subpriv->iobase = iobase;
subpriv->has_int_sce = has_int_sce;
subpriv->valid_isns = valid_isns;
* This function cleans up an 'INTERRUPT' subdevice.
*/
static void
-dio200_subdev_intr_cleanup(comedi_device *dev, comedi_subdevice *s)
+dio200_subdev_intr_cleanup(comedi_device * dev, comedi_subdevice * s)
{
dio200_subdev_intr *subpriv = s->private;
/*
* Interrupt service routine.
*/
-static irqreturn_t
-dio200_interrupt(int irq, void *d PT_REGS_ARG)
+static irqreturn_t dio200_interrupt(int irq, void *d PT_REGS_ARG)
{
- comedi_device *dev=d;
+ comedi_device *dev = d;
int handled;
+ if (!dev->attached) {
+ return IRQ_NONE;
+ }
+
if (devpriv->intr_sd >= 0) {
handled = dio200_handle_read_intr(dev,
- dev->subdevices + devpriv->intr_sd);
+ dev->subdevices + devpriv->intr_sd);
} else {
handled = 0;
}
* Handle 'insn_read' for an '8254' counter subdevice.
*/
static int
-dio200_subdev_8254_read(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *data)
+dio200_subdev_8254_read(comedi_device * dev, comedi_subdevice * s,
+ comedi_insn * insn, lsampl_t * data)
{
dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
+ unsigned long flags;
+
+ if (insn->n == 0)
+ return 0;
- data[0] = i8254_read(subpriv->iobase, chan);
+ comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
+ data[0] = i8254_read(subpriv->iobase, 0, chan);
+ comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 1;
}
* Handle 'insn_write' for an '8254' counter subdevice.
*/
static int
-dio200_subdev_8254_write(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *data)
+dio200_subdev_8254_write(comedi_device * dev, comedi_subdevice * s,
+ comedi_insn * insn, lsampl_t * data)
{
dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
+ unsigned long flags;
+
+ if (insn->n == 0)
+ return 0;
- i8254_write(subpriv->iobase, chan, data[0]);
+ comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
+ i8254_write(subpriv->iobase, 0, chan, data[0]);
+ comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 1;
}
* Set gate source for an '8254' counter subdevice channel.
*/
static int
-dio200_set_gate_src(dio200_subdev_8254 *subpriv, unsigned int counter_number,
- unsigned int gate_src)
+dio200_subdev_8254_set_gate_src(comedi_device * dev, comedi_subdevice *s,
+ unsigned int counter_number, unsigned int gate_src)
{
+ dio200_subdev_8254 *subpriv = s->private;
unsigned char byte;
- if (!subpriv->has_clk_gat_sce) return -1;
- if (counter_number > 2) return -1;
- if (gate_src > 7) return -1;
+ if (!thislayout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
+ if (gate_src > 7)
+ return -1;
subpriv->gate_src[counter_number] = gate_src;
byte = GAT_SCE(subpriv->which, counter_number, gate_src);
* Get gate source for an '8254' counter subdevice channel.
*/
static int
-dio200_get_gate_src(dio200_subdev_8254 *subpriv, unsigned int counter_number)
+dio200_subdev_8254_get_gate_src(comedi_device * dev, comedi_subdevice *s,
+ unsigned int counter_number)
{
- if (!subpriv->has_clk_gat_sce) return -1;
- if (counter_number > 2) return -1;
+ dio200_subdev_8254 *subpriv = s->private;
+
+ if (!thislayout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
return subpriv->gate_src[counter_number];
}
* Set clock source for an '8254' counter subdevice channel.
*/
static int
-dio200_set_clock_src(dio200_subdev_8254 *subpriv, unsigned int counter_number,
- unsigned int clock_src)
+dio200_subdev_8254_set_clock_src(comedi_device * dev, comedi_subdevice *s,
+ unsigned int counter_number, unsigned int clock_src)
{
+ dio200_subdev_8254 *subpriv = s->private;
unsigned char byte;
- if (!subpriv->has_clk_gat_sce) return -1;
- if (counter_number > 2) return -1;
- if (clock_src > 7) return -1;
+ if (!thislayout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
+ if (clock_src > 7)
+ return -1;
subpriv->clock_src[counter_number] = clock_src;
byte = CLK_SCE(subpriv->which, counter_number, clock_src);
* Get clock source for an '8254' counter subdevice channel.
*/
static int
-dio200_get_clock_src(dio200_subdev_8254 *subpriv, unsigned int counter_number)
+dio200_subdev_8254_get_clock_src(comedi_device * dev, comedi_subdevice *s,
+ unsigned int counter_number, lsampl_t * period_ns)
{
- if (!subpriv->has_clk_gat_sce) return -1;
- if (counter_number > 2) return -1;
+ dio200_subdev_8254 *subpriv = s->private;
+ unsigned clock_src;
+
+ if (!thislayout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
- return subpriv->clock_src[counter_number];
+ clock_src = subpriv->clock_src[counter_number];
+ *period_ns = clock_period[clock_src];
+ return clock_src;
}
/*
* Handle 'insn_config' for an '8254' counter subdevice.
*/
static int
-dio200_subdev_8254_config(comedi_device *dev, comedi_subdevice *s,
- comedi_insn *insn, lsampl_t *data)
+dio200_subdev_8254_config(comedi_device * dev, comedi_subdevice * s,
+ comedi_insn * insn, lsampl_t * data)
{
dio200_subdev_8254 *subpriv = s->private;
- int ret;
+ int ret = 0;
int chan = CR_CHAN(insn->chanspec);
+ unsigned long flags;
+ comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
switch (data[0]) {
- case INSN_CONFIG_8254_SET_MODE:
- ret = i8254_set_mode(subpriv->iobase, chan, data[1]);
- if (ret < 0) return -EINVAL;
+ case INSN_CONFIG_SET_COUNTER_MODE:
+ ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
+ if (ret < 0)
+ ret = -EINVAL;
break;
case INSN_CONFIG_8254_READ_STATUS:
- data[1] = i8254_status(subpriv->iobase, chan);
+ data[1] = i8254_status(subpriv->iobase, 0, chan);
break;
case INSN_CONFIG_SET_GATE_SRC:
- ret = dio200_set_gate_src(subpriv, chan, data[2]);
- if (ret < 0) return -EINVAL;
+ ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
+ if (ret < 0)
+ ret = -EINVAL;
break;
case INSN_CONFIG_GET_GATE_SRC:
- ret = dio200_get_gate_src(subpriv, chan);
- if (ret < 0) return -EINVAL;
+ ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
data[2] = ret;
break;
case INSN_CONFIG_SET_CLOCK_SRC:
- ret = dio200_set_clock_src(subpriv, chan, data[1]);
- if (ret < 0) return -EINVAL;
+ ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
+ if (ret < 0)
+ ret = -EINVAL;
break;
case INSN_CONFIG_GET_CLOCK_SRC:
- ret = dio200_get_clock_src(subpriv, chan);
- if (ret < 0) return -EINVAL;
+ ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
data[1] = ret;
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
break;
}
- return insn->n;
+ comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
+ return ret < 0 ? ret : insn->n;
}
/*
* offset is the offset to the 8254 chip.
*/
static int
-dio200_subdev_8254_init(comedi_device *dev, comedi_subdevice *s,
- unsigned long iobase, unsigned offset, int has_clk_gat_sce)
+dio200_subdev_8254_init(comedi_device * dev, comedi_subdevice * s,
+ unsigned long iobase, unsigned offset)
{
dio200_subdev_8254 *subpriv;
unsigned int chan;
- subpriv = kmalloc(sizeof(*subpriv), GFP_KERNEL);
+ subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
if (!subpriv) {
- printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor);
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
return -ENOMEM;
}
- memset(subpriv, 0, sizeof(*subpriv));
s->private = subpriv;
s->type = COMEDI_SUBD_COUNTER;
s->insn_write = dio200_subdev_8254_write;
s->insn_config = dio200_subdev_8254_config;
+ spin_lock_init(&subpriv->spinlock);
subpriv->iobase = offset + iobase;
- subpriv->has_clk_gat_sce = has_clk_gat_sce;
- if (has_clk_gat_sce) {
+ if (thislayout->has_clk_gat_sce) {
/* Derive CLK_SCE and GAT_SCE register offsets from
* 8254 offset. */
subpriv->clk_sce_iobase =
/* Initialize channels. */
for (chan = 0; chan < 3; chan++) {
- i8254_set_mode(subpriv->iobase, chan,
- I8254_MODE0 | I8254_BINARY);
- if (subpriv->has_clk_gat_sce) {
+ i8254_set_mode(subpriv->iobase, 0, chan,
+ I8254_MODE0 | I8254_BINARY);
+ if (thislayout->has_clk_gat_sce) {
/* Gate source 0 is VCC (logic 1). */
- dio200_set_gate_src(subpriv, chan, 0);
+ dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
/* Clock source 0 is the dedicated clock input. */
- dio200_set_clock_src(subpriv, chan, 0);
+ dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
}
}
* This function cleans up an '8254' counter subdevice.
*/
static void
-dio200_subdev_8254_cleanup(comedi_device *dev, comedi_subdevice *s)
+dio200_subdev_8254_cleanup(comedi_device * dev, comedi_subdevice * s)
{
- dio200_subdev_intr *subpriv = s->private;
+ dio200_subdev_8254 *subpriv = s->private;
if (subpriv) {
kfree(subpriv);
* in the driver structure, dev->board_ptr contains that
* address.
*/
-static int
-dio200_attach(comedi_device *dev,comedi_devconfig *it)
+static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
{
comedi_subdevice *s;
- struct pci_dev *pci_dev = NULL;
unsigned long iobase = 0;
unsigned int irq = 0;
+#ifdef CONFIG_COMEDI_PCI
+ struct pci_dev *pci_dev = NULL;
int bus = 0, slot = 0;
- dio200_layout *layout;
+#endif
+ const dio200_layout *layout;
int share_irq = 0;
int sdx;
unsigned n;
int ret;
printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
- DIO200_DRIVER_NAME);
+ DIO200_DRIVER_NAME);
- if ((ret=alloc_private(dev,sizeof(dio200_private))) < 0) {
- printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor);
+ if ((ret = alloc_private(dev, sizeof(dio200_private))) < 0) {
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
return ret;
}
irq = it->options[1];
share_irq = 0;
break;
+#ifdef CONFIG_COMEDI_PCI
case pci_bustype:
bus = it->options[0];
slot = it->options[1];
share_irq = 1;
- if ((ret=dio200_find_pci(dev, bus, slot, &pci_dev)) < 0)
+ if ((ret = dio200_find_pci(dev, bus, slot, &pci_dev)) < 0)
return ret;
devpriv->pci_dev = pci_dev;
break;
+#endif
default:
- printk(KERN_ERR "comedi%d: %s: BUG! cannot determine board type!\n",
- dev->minor, DIO200_DRIVER_NAME);
+ printk(KERN_ERR
+ "comedi%d: %s: BUG! cannot determine board type!\n",
+ dev->minor, DIO200_DRIVER_NAME);
return -EINVAL;
break;
}
devpriv->intr_sd = -1;
/* Enable device and reserve I/O spaces. */
+#ifdef CONFIG_COMEDI_PCI
if (pci_dev) {
- ret = pci_enable_device(pci_dev);
+ ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
if (ret < 0) {
- printk(KERN_ERR "comedi%d: error! cannot enable PCI device!\n",
- dev->minor);
+ printk(KERN_ERR
+ "comedi%d: error! cannot enable PCI device and request regions!\n",
+ dev->minor);
return ret;
}
iobase = pci_resource_start(pci_dev, 2);
irq = pci_dev->irq;
- ret = pci_request_regions(pci_dev, DIO200_DRIVER_NAME);
- if (ret < 0) {
- printk(KERN_ERR "comedi%d: I/O port conflict (PCI)!\n",
- dev->minor);
- return ret;
- }
- } else {
+ } else
+#endif
+ {
ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
if (ret < 0) {
return ret;
dev->iobase = iobase;
layout = thislayout;
- if ((ret=alloc_subdevices(dev, layout->n_subdevs)) < 0) {
- printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor);
+ if ((ret = alloc_subdevices(dev, layout->n_subdevs)) < 0) {
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
return ret;
}
case sd_8254:
/* counter subdevice (8254) */
ret = dio200_subdev_8254_init(dev, s, iobase,
- layout->sdinfo[n],
- layout->has_clk_gat_sce);
+ layout->sdinfo[n]);
if (ret < 0) {
return ret;
}
case sd_8255:
/* digital i/o subdevice (8255) */
ret = subdev_8255_init(dev, s, 0,
- iobase + layout->sdinfo[n]);
+ iobase + layout->sdinfo[n]);
if (ret < 0) {
return ret;
}
/* 'INTERRUPT' subdevice */
if (irq) {
ret = dio200_subdev_intr_init(dev, s,
- iobase + DIO200_INT_SCE,
- layout->sdinfo[n],
- layout->has_int_sce);
+ iobase + DIO200_INT_SCE,
+ layout->sdinfo[n], layout->has_int_sce);
if (ret < 0) {
return ret;
}
dev->board_name = thisboard->name;
if (irq) {
- unsigned long flags = share_irq ? SA_SHIRQ : 0;
+ unsigned long flags = share_irq ? IRQF_SHARED : 0;
if (comedi_request_irq(irq, dio200_interrupt, flags,
- DIO200_DRIVER_NAME, dev) >= 0) {
+ DIO200_DRIVER_NAME, dev) >= 0) {
dev->irq = irq;
} else {
- printk(KERN_WARNING "comedi%d: warning! irq %u unavailable!\n",
- dev->minor, irq);
+ printk(KERN_WARNING
+ "comedi%d: warning! irq %u unavailable!\n",
+ dev->minor, irq);
}
}
if (thisboard->bustype == isa_bustype) {
printk("(base %#lx) ", iobase);
} else {
+#ifdef CONFIG_COMEDI_PCI
printk("(pci %s) ", pci_name(pci_dev));
+#endif
}
if (irq) {
printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
* allocated by _attach(). dev->private and dev->subdevices are
* deallocated automatically by the core.
*/
-static int
-dio200_detach(comedi_device *dev)
+static int dio200_detach(comedi_device * dev)
{
- dio200_layout *layout;
+ const dio200_layout *layout;
unsigned n;
printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
- DIO200_DRIVER_NAME);
+ DIO200_DRIVER_NAME);
if (dev->irq) {
comedi_free_irq(dev->irq, dev);
}
}
if (devpriv) {
+#ifdef CONFIG_COMEDI_PCI
if (devpriv->pci_dev) {
- if(dev->iobase)
- {
- pci_release_regions(devpriv->pci_dev);
- pci_disable_device(devpriv->pci_dev);
+ if (dev->iobase) {
+ comedi_pci_disable(devpriv->pci_dev);
}
pci_dev_put(devpriv->pci_dev);
- } else if (dev->iobase) {
- release_region(dev->iobase, DIO200_IO_SIZE);
+ } else
+#endif
+ {
+ if (dev->iobase) {
+ release_region(dev->iobase, DIO200_IO_SIZE);
+ }
}
}
if (dev->board_name) {
printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
+ dev->minor, dev->board_name);
}
return 0;
}
-