diff options
Diffstat (limited to 'drivers/staging/comedi/drivers')
121 files changed, 5664 insertions, 8082 deletions
diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index f8e1ebad304d..9f4c1411719d 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -90,8 +90,8 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base, } } - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: ns_high = div1_lub * div2_lub * i8253_osc_base; ns_low = div1_glb * div2_glb * i8253_osc_base; @@ -103,11 +103,11 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base, div2 = div2_glb; } break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: div1 = div1_lub; div2 = div2_lub; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: div1 = div1_glb; div2 = div2_glb; break; diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index a33a19622745..34d4d8b5f31e 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -79,49 +79,30 @@ I/O port base address can be found in the output of 'lspci -v'. #include "comedi_fc.h" #include "8255.h" -#define _8255_SIZE 4 - -#define _8255_DATA 0 -#define _8255_CR 3 - -#define CR_C_LO_IO 0x01 -#define CR_B_IO 0x02 -#define CR_B_MODE 0x04 -#define CR_C_HI_IO 0x08 -#define CR_A_IO 0x10 -#define CR_A_MODE(a) ((a)<<5) -#define CR_CW 0x80 - struct subdev_8255_private { - unsigned long iobase; - int (*io)(int, int, int, unsigned long); + unsigned long regbase; + int (*io)(struct comedi_device *, int, int, int, unsigned long); }; -static int subdev_8255_io(int dir, int port, int data, unsigned long iobase) +static int subdev_8255_io(struct comedi_device *dev, + int dir, int port, int data, unsigned long regbase) { if (dir) { - outb(data, iobase + port); + outb(data, dev->iobase + regbase + port); return 0; } - return inb(iobase + port); + return inb(dev->iobase + regbase + port); } -void subdev_8255_interrupt(struct comedi_device *dev, - struct comedi_subdevice *s) +static int subdev_8255_mmio(struct comedi_device *dev, + int dir, int port, int data, unsigned long regbase) { - struct subdev_8255_private *spriv = s->private; - unsigned long iobase = spriv->iobase; - unsigned short d; - - d = spriv->io(0, _8255_DATA, 0, iobase); - d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8); - - comedi_buf_put(s, d); - s->async->events |= COMEDI_CB_EOS; - - comedi_event(dev, s); + if (dir) { + writeb(data, dev->mmio + regbase + port); + return 0; + } + return readb(dev->mmio + regbase + port); } -EXPORT_SYMBOL_GPL(subdev_8255_interrupt); static int subdev_8255_insn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -129,25 +110,26 @@ static int subdev_8255_insn(struct comedi_device *dev, unsigned int *data) { struct subdev_8255_private *spriv = s->private; - unsigned long iobase = spriv->iobase; + unsigned long regbase = spriv->regbase; unsigned int mask; unsigned int v; mask = comedi_dio_update_state(s, data); if (mask) { if (mask & 0xff) - spriv->io(1, _8255_DATA, s->state & 0xff, iobase); + spriv->io(dev, 1, I8255_DATA_A_REG, + s->state & 0xff, regbase); if (mask & 0xff00) - spriv->io(1, _8255_DATA + 1, (s->state >> 8) & 0xff, - iobase); + spriv->io(dev, 1, I8255_DATA_B_REG, + (s->state >> 8) & 0xff, regbase); if (mask & 0xff0000) - spriv->io(1, _8255_DATA + 2, (s->state >> 16) & 0xff, - iobase); + spriv->io(dev, 1, I8255_DATA_C_REG, + (s->state >> 16) & 0xff, regbase); } - v = spriv->io(0, _8255_DATA, 0, iobase); - v |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8); - v |= (spriv->io(0, _8255_DATA + 2, 0, iobase) << 16); + v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, regbase); + v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, regbase) << 8); + v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, regbase) << 16); data[1] = v; @@ -158,21 +140,21 @@ static void subdev_8255_do_config(struct comedi_device *dev, struct comedi_subdevice *s) { struct subdev_8255_private *spriv = s->private; - unsigned long iobase = spriv->iobase; + unsigned long regbase = spriv->regbase; int config; - config = CR_CW; + config = I8255_CTRL_CW; /* 1 in io_bits indicates output, 1 in config indicates input */ if (!(s->io_bits & 0x0000ff)) - config |= CR_A_IO; + config |= I8255_CTRL_A_IO; if (!(s->io_bits & 0x00ff00)) - config |= CR_B_IO; + config |= I8255_CTRL_B_IO; if (!(s->io_bits & 0x0f0000)) - config |= CR_C_LO_IO; + config |= I8255_CTRL_C_LO_IO; if (!(s->io_bits & 0xf00000)) - config |= CR_C_HI_IO; + config |= I8255_CTRL_C_HI_IO; - spriv->io(1, _8255_CR, config, iobase); + spriv->io(dev, 1, I8255_CTRL_REG, config, regbase); } static int subdev_8255_insn_config(struct comedi_device *dev, @@ -202,67 +184,12 @@ static int subdev_8255_insn_config(struct comedi_device *dev, return insn->n; } -static int subdev_8255_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* step 4 */ - - if (err) - return 4; - - return 0; -} - -static int subdev_8255_cmd(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - /* FIXME */ - - return 0; -} - -static int subdev_8255_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - /* FIXME */ - - return 0; -} - -int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(int, int, int, unsigned long), - unsigned long iobase) +static int __subdev_8255_init(struct comedi_device *dev, + struct comedi_subdevice *s, + int (*io)(struct comedi_device *, + int, int, int, unsigned long), + unsigned long regbase, + bool is_mmio) { struct subdev_8255_private *spriv; @@ -270,8 +197,13 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, if (!spriv) return -ENOMEM; - spriv->iobase = iobase; - spriv->io = io ? io : subdev_8255_io; + if (io) + spriv->io = io; + else if (is_mmio) + spriv->io = subdev_8255_mmio; + else + spriv->io = subdev_8255_io; + spriv->regbase = regbase; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -285,27 +217,24 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -EXPORT_SYMBOL_GPL(subdev_8255_init); -int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(int, int, int, unsigned long), - unsigned long iobase) +int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, + int (*io)(struct comedi_device *, + int, int, int, unsigned long), + unsigned long regbase) { - int ret; - - ret = subdev_8255_init(dev, s, io, iobase); - if (ret) - return ret; - - s->len_chanlist = 1; - s->do_cmdtest = subdev_8255_cmdtest; - s->do_cmd = subdev_8255_cmd; - s->cancel = subdev_8255_cancel; - - return 0; + return __subdev_8255_init(dev, s, io, regbase, false); } -EXPORT_SYMBOL_GPL(subdev_8255_init_irq); +EXPORT_SYMBOL_GPL(subdev_8255_init); +int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s, + int (*io)(struct comedi_device *, + int, int, int, unsigned long), + unsigned long regbase) +{ + return __subdev_8255_init(dev, s, io, regbase, true); +} +EXPORT_SYMBOL_GPL(subdev_8255_mm_init); /* Start of the 8255 standalone device @@ -316,8 +245,8 @@ static int dev_8255_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; - int ret; unsigned long iobase; + int ret; int i; for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) { @@ -338,7 +267,14 @@ static int dev_8255_attach(struct comedi_device *dev, s = &dev->subdevices[i]; iobase = it->options[i]; - ret = __comedi_request_region(dev, iobase, _8255_SIZE); + /* + * __comedi_request_region() does not set dev->iobase. + * + * For 8255 devices that are manually attached using + * comedi_config, the 'iobase' is the actual I/O port + * base address of the chip. + */ + ret = __comedi_request_region(dev, iobase, I8255_SIZE); if (ret) { s->type = COMEDI_SUBD_UNUSED; } else { @@ -361,7 +297,7 @@ static void dev_8255_detach(struct comedi_device *dev) s = &dev->subdevices[i]; if (s->type != COMEDI_SUBD_UNUSED) { spriv = s->private; - release_region(spriv->iobase, _8255_SIZE); + release_region(spriv->regbase, I8255_SIZE); } } } diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index 795d232a6c02..5985c8e0330f 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -21,13 +21,28 @@ #include "../comedidev.h" -int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(int, int, int, unsigned long), - unsigned long iobase); -int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io)(int, int, int, unsigned long), - unsigned long iobase); -void subdev_8255_interrupt(struct comedi_device *dev, - struct comedi_subdevice *s); +#define I8255_SIZE 0x04 + +#define I8255_DATA_A_REG 0x00 +#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_A_MODE(x) ((x) << 5) +#define I8255_CTRL_CW (1 << 7) + +int subdev_8255_init(struct comedi_device *, struct comedi_subdevice *, + int (*io)(struct comedi_device *, + int, int, int, unsigned long), + unsigned long regbase); + +int subdev_8255_mm_init(struct comedi_device *, struct comedi_subdevice *, + int (*io)(struct comedi_device *, + int, int, int, unsigned long), + unsigned long regbase); #endif diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index f21e6567ac2f..8b9589828855 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -190,24 +190,12 @@ static int pci_8255_mite_init(struct pci_dev *pcidev) return 0; } -static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase) -{ - void __iomem *mmio_base = (void __iomem *)iobase; - - if (dir) { - writeb(data, mmio_base + port); - return 0; - } - return readb(mmio_base + port); -} - static int pci_8255_auto_attach(struct comedi_device *dev, unsigned long context) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct pci_8255_boardinfo *board = NULL; struct comedi_subdevice *s; - bool is_mmio; int ret; int i; @@ -228,9 +216,7 @@ static int pci_8255_auto_attach(struct comedi_device *dev, return ret; } - is_mmio = (pci_resource_flags(pcidev, board->dio_badr) & - IORESOURCE_MEM) != 0; - if (is_mmio) { + if ((pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM)) { dev->mmio = pci_ioremap_bar(pcidev, board->dio_badr); if (!dev->mmio) return -ENOMEM; @@ -248,16 +234,11 @@ static int pci_8255_auto_attach(struct comedi_device *dev, return ret; for (i = 0; i < board->n_8255; i++) { - unsigned long iobase; - s = &dev->subdevices[i]; - if (is_mmio) { - iobase = (unsigned long)(dev->mmio + (i * 4)); - ret = subdev_8255_init(dev, s, pci_8255_mmio, iobase); - } else { - iobase = dev->iobase + (i * 4); - ret = subdev_8255_init(dev, s, NULL, iobase); - } + if (dev->mmio) + ret = subdev_8255_mm_init(dev, s, NULL, i * I8255_SIZE); + else + ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); if (ret) return ret; } @@ -265,18 +246,11 @@ static int pci_8255_auto_attach(struct comedi_device *dev, return 0; } -static void pci_8255_detach(struct comedi_device *dev) -{ - if (dev->mmio) - iounmap(dev->mmio); - comedi_pci_disable(dev); -} - static struct comedi_driver pci_8255_driver = { .driver_name = "8255_pci", .module = THIS_MODULE, .auto_attach = pci_8255_auto_attach, - .detach = pci_8255_detach, + .detach = comedi_pci_detach, }; static int pci_8255_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 8873d4807a01..6bc9ef3b25b3 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_COMEDI_BOND) += comedi_bond.o obj-$(CONFIG_COMEDI_TEST) += comedi_test.o obj-$(CONFIG_COMEDI_PARPORT) += comedi_parport.o obj-$(CONFIG_COMEDI_SERIAL2002) += serial2002.o -obj-$(CONFIG_COMEDI_SKEL) += skel.o # Comedi ISA drivers obj-$(CONFIG_COMEDI_AMPLC_DIO200_ISA) += amplc_dio200.o @@ -50,6 +49,7 @@ obj-$(CONFIG_COMEDI_NI_AT_A2150) += ni_at_a2150.o obj-$(CONFIG_COMEDI_NI_AT_AO) += ni_at_ao.o obj-$(CONFIG_COMEDI_NI_ATMIO) += ni_atmio.o obj-$(CONFIG_COMEDI_NI_ATMIO16D) += ni_atmio16d.o +obj-$(CONFIG_COMEDI_NI_LABPC_ISA) += ni_labpc.o obj-$(CONFIG_COMEDI_PCMAD) += pcmad.o obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o @@ -125,6 +125,7 @@ obj-$(CONFIG_COMEDI_QUATECH_DAQP_CS) += quatech_daqp_cs.o # Comedi USB drivers obj-$(CONFIG_COMEDI_DT9812) += dt9812.o +obj-$(CONFIG_COMEDI_NI_USB6501) += ni_usb6501.o obj-$(CONFIG_COMEDI_USBDUX) += usbdux.o obj-$(CONFIG_COMEDI_USBDUXFAST) += usbduxfast.o obj-$(CONFIG_COMEDI_USBDUXSIGMA) += usbduxsigma.o @@ -134,11 +135,10 @@ obj-$(CONFIG_COMEDI_VMK80XX) += vmk80xx.o obj-$(CONFIG_COMEDI_MITE) += mite.o obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o obj-$(CONFIG_COMEDI_NI_TIOCMD) += ni_tiocmd.o -obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o +obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc_common.o obj-$(CONFIG_COMEDI_NI_LABPC_ISADMA) += ni_labpc_isadma.o obj-$(CONFIG_COMEDI_8255) += 8255.o obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200_common.o obj-$(CONFIG_COMEDI_AMPLC_PC236) += amplc_pc236_common.o obj-$(CONFIG_COMEDI_DAS08) += das08.o -obj-$(CONFIG_COMEDI_FC) += comedi_fc.o diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index de5843ab01ae..2e7fb218340f 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -44,7 +44,7 @@ static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; unsigned short w_Address = CR_CHAN(insn->chanspec); unsigned short w_Data; @@ -59,7 +59,7 @@ static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, static irqreturn_t v_ADDI_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; this_board->interrupt(irq, d); return IRQ_RETVAL(1); @@ -67,7 +67,7 @@ static irqreturn_t v_ADDI_Interrupt(int irq, void *d) static int i_ADDI_Reset(struct comedi_device *dev) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; this_board->reset(dev); return 0; @@ -77,7 +77,7 @@ static int addi_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv; struct comedi_subdevice *s; int ret, n_subdevices; @@ -268,13 +268,7 @@ static int addi_auto_attach(struct comedi_device *dev, static void i_ADDI_Detach(struct comedi_device *dev) { - struct addi_private *devpriv = dev->private; - - if (devpriv) { - if (dev->iobase) - i_ADDI_Reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - } - comedi_pci_disable(dev); + if (dev->iobase) + i_ADDI_Reset(dev); + comedi_pci_detach(dev); } diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index a7400a25f620..e2a3ffeee5cf 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -107,10 +107,9 @@ struct addi_private { unsigned char b_DmaDoubleBuffer; /* we can use double buffering */ unsigned int ui_DmaActualBuffer; /* which buffer is used now */ unsigned short *ul_DmaBufferVirtual[2]; /* pointers to DMA buffer */ - unsigned int ul_DmaBufferHw[2]; /* hw address of DMA buff */ + dma_addr_t ul_DmaBufferHw[2]; /* hw address of DMA buff */ unsigned int ui_DmaBufferSize[2]; /* size of dma buffer in bytes */ unsigned int ui_DmaBufferUsesize[2]; /* which size we may now used for transfer */ - unsigned int ui_DmaBufferPages[2]; /* number of pages in buffer */ unsigned char b_DigitalOutputRegister; /* Digital Output Register */ unsigned char b_OutputMemoryStatus; unsigned char b_TimerSelectMode; /* Contain data written at iobase + 0C */ diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c index aafc172f3a98..b731856c27da 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c @@ -179,7 +179,7 @@ static void addi_eeprom_read_di_info(struct comedi_device *dev, unsigned long iobase, unsigned short addr) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; char *type = this_board->pc_EepromChip; unsigned short tmp; @@ -200,7 +200,7 @@ static void addi_eeprom_read_do_info(struct comedi_device *dev, unsigned long iobase, unsigned short addr) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; char *type = this_board->pc_EepromChip; unsigned short tmp; @@ -218,7 +218,7 @@ static void addi_eeprom_read_timer_info(struct comedi_device *dev, { struct addi_private *devpriv = dev->private; #if 0 - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; char *type = this_board->pc_EepromChip; unsigned short offset = 0; unsigned short ntimers; @@ -259,7 +259,7 @@ static void addi_eeprom_read_ao_info(struct comedi_device *dev, unsigned long iobase, unsigned short addr) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; char *type = this_board->pc_EepromChip; unsigned short tmp; @@ -278,7 +278,7 @@ static void addi_eeprom_read_ai_info(struct comedi_device *dev, unsigned long iobase, unsigned short addr) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; char *type = this_board->pc_EepromChip; unsigned short offset; @@ -315,7 +315,7 @@ static void addi_eeprom_read_ai_info(struct comedi_device *dev, static void addi_eeprom_read_info(struct comedi_device *dev, unsigned long iobase) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; char *type = this_board->pc_EepromChip; unsigned short size; unsigned char nfuncs; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index cad33f1a04fe..53bb51bd77b5 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -477,6 +477,4 @@ static void apci035_interrupt(int irq, void *d) /* send signal to the sample */ send_sig(SIGIO, devpriv->tsk_Current, 0); } - - return; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 1e2fe66818e4..0ea081e1e119 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -172,17 +172,15 @@ static int apci1500_di_config(struct comedi_device *dev, if (data[0] == 1) { i_MaxChannel = 8; - } /* if (data[0] == 1) */ - else { + } else { if (data[0] == 2) { i_MaxChannel = 6; - } /* if(data[0]==2) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "The specified port event does not exist\n"); return -EINVAL; - } /* else if(data[0]==2) */ - } /* else if (data[0] == 1) */ + } + } switch (data[1]) { case 0: data[1] = APCI1500_AND; @@ -194,10 +192,10 @@ static int apci1500_di_config(struct comedi_device *dev, data[1] = APCI1500_OR_PRIORITY; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The specified interrupt logic does not exist\n"); return -EINVAL; - } /* switch(data[1]); */ + } i_Logic = data[1]; for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) { @@ -239,11 +237,11 @@ static int apci1500_di_config(struct comedi_device *dev, case 5: break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The option indicated in the event mask does not exist\n"); return -EINVAL; - } /* switch(i_EventMask) */ - } /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */ + } + } if (data[0] == 1) { /* Test the interrupt logic */ @@ -256,10 +254,10 @@ static int apci1500_di_config(struct comedi_device *dev, if (data[1] == APCI1500_OR_PRIORITY && i_PatternTransition != 0) { - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "Transition error on an OR PRIORITY logic\n"); return -EINVAL; - } /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */ + } /* Tests if more than one transition */ /* was declared for an AND logic */ @@ -271,14 +269,14 @@ static int apci1500_di_config(struct comedi_device *dev, ((i_PatternTransition >> i_Count) & 0x1); - } /* for (i_Count = 0; i_Count < 8; i_Count++) */ + } if (i_PatternTransitionCount > 1) { - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "Transition error on an AND logic\n"); return -EINVAL; - } /* if (i_PatternTransitionCount > 1) */ - } /* if (data[1]== APCI1500_AND) */ + } + } /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, @@ -347,13 +345,12 @@ static int apci1500_di_config(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "The choice for interrupt logic does not exist\n"); return -EINVAL; - } /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ - } /* if (data[0]== 1) */ + } + } /* Test if event setting for port 2 */ @@ -448,13 +445,12 @@ static int apci1500_di_config(struct comedi_device *dev, outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if (data[1] == APCI1500_OR) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "The choice for interrupt logic does not exist\n"); return -EINVAL; - } /* elseif (data[1] == APCI1500_OR) */ - } /* if(data[0]==2) */ + } + } return insn->n; } @@ -518,13 +514,12 @@ static int apci1500_di_write(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if(i_Event1Status==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Event 1 not initialised\n"); return -EINVAL; - } /* else if(i_Event1Status==1) */ - } /* if (data[1]==1) */ + } + } if (data[1] == 2) { if (i_Event2Status == 1) { @@ -555,19 +550,17 @@ static int apci1500_di_write(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 1; - } /* if(i_Event2Status==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Event 2 not initialised\n"); return -EINVAL; - } /* else if(i_Event2Status==1) */ - } /* if(data[1]==2) */ - } /* if (data[1] == 1 || data[0] == 2) */ - else { - dev_warn(dev->hw_dev, + } + } + } else { + dev_warn(dev->class_dev, "The port parameter is in error\n"); return -EINVAL; - } /* else if (data[1] == 1 || data[0] == 2) */ + } break; @@ -600,13 +593,12 @@ static int apci1500_di_write(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event1InterruptStatus = 0; - } /* if(i_Event1Status==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Event 1 not initialised\n"); return -EINVAL; - } /* else if(i_Event1Status==1) */ - } /* if (data[1]==1) */ + } + } if (data[1] == 2) { /* Test if event initialised */ if (i_Event2Status == 1) { @@ -630,26 +622,25 @@ static int apci1500_di_write(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 0; - } /* if(i_Event2Status==1) */ - else { - dev_warn(dev->hw_dev, + } else { + + dev_warn(dev->class_dev, "Event 2 not initialised\n"); return -EINVAL; - } /* else if(i_Event2Status==1) */ - } /* if(data[1]==2) */ + } + } - } /* if (data[1] == 1 || data[1] == 2) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "The port parameter is in error\n"); return -EINVAL; - } /* else if (data[1] == 1 || data[1] == 2) */ + } break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The option of START/STOP logic does not exist\n"); return -EINVAL; - } /* switch(data[0]) */ + } return insn->n; } @@ -835,17 +826,15 @@ static int apci1500_do_write(struct comedi_device *dev, unsigned int ui_Temp1; unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - if (!devpriv->b_OutputMemoryStatus) { + if (!devpriv->b_OutputMemoryStatus) ui_Temp = 0; - } /* if(!devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } /* if(data[1]==0) */ - else { + } else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -876,20 +865,18 @@ static int apci1500_do_write(struct comedi_device *dev, "chan spec wrong\n"); return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch(ui_NoOfChannels) */ + } outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Specified channel not supported\n"); return -EINVAL; - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==0) */ - else { + } + } + } else { if (data[3] == 1) { if (data[1] == 0) { data[0] = ~data[0] & 0x1; @@ -903,8 +890,7 @@ static int apci1500_do_write(struct comedi_device *dev, outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } /* if(data[1]==0) */ - else { + } else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -955,25 +941,23 @@ static int apci1500_do_write(struct comedi_device *dev, "chan spec wrong\n"); return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch(ui_NoOfChannels) */ + } outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Specified channel not supported\n"); return -EINVAL; - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==1); */ - else { - dev_warn(dev->hw_dev, + } + } + } else { + dev_warn(dev->class_dev, "Specified functionality does not exist\n"); return -EINVAL; - } /* if else data[3]==1) */ - } /* if else data[3]==0) */ + } + } ui_Temp = data[0]; return insn->n; } @@ -1002,17 +986,16 @@ static int apci1500_timer_config(struct comedi_device *dev, devpriv->tsk_Current = current; -/* Selection of the input clock */ + /* Selection of the input clock */ if (data[0] == 0 || data[0] == 1 || data[0] == 2) { outw(data[0], devpriv->i_IobaseAddon + APCI1500_CLK_SELECT); - } /* if(data[0]==0||data[0]==1||data[0]==2) */ - else { + } else { if (data[0] != 3) { - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The option for input clock selection does not exist\n"); return -EINVAL; - } /* if(data[0]!=3) */ - } /* elseif(data[0]==0||data[0]==1||data[0]==2) */ + } + } /* Select the counter/timer */ switch (data[1]) { case COUNTER1: @@ -1025,10 +1008,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This choice is not a timer nor a counter\n"); return -EINVAL; - } /* switch(data[2]) */ + } /* Selecting single or continuous mode */ switch (data[4]) { @@ -1039,10 +1022,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This option for single/continuous mode does not exist\n"); return -EINVAL; - } /* switch(data[4]) */ + } i_TimerCounterMode = data[2] | data[4] | 7; /* Test the reload value */ @@ -1133,18 +1116,16 @@ static int apci1500_timer_config(struct comedi_device *dev, outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Error in selection of interrupt enable or disable\n"); return -EINVAL; - } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ - } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ - else { - dev_warn(dev->hw_dev, + } + } else { + dev_warn(dev->class_dev, "Error in selection of reload value\n"); return -EINVAL; - } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ + } i_TimerCounterWatchdogInterrupt = data[7]; i_TimerCounter1Init = 1; break; @@ -1158,10 +1139,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This choice is not a timer nor a counter\n"); return -EINVAL; - } /* switch(data[2]) */ + } /* Selecting single or continuous mode */ switch (data[4]) { @@ -1172,10 +1153,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This option for single/continuous mode does not exist\n"); return -EINVAL; - } /* switch(data[4]) */ + } /* Selecting software or hardware trigger */ switch (data[5]) { @@ -1186,10 +1167,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[5] = APCI1500_HARDWARE_TRIGGER; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This choice for software or hardware trigger does not exist\n"); return -EINVAL; - } /* switch(data[5]) */ + } /* Selecting software or hardware gate */ switch (data[6]) { @@ -1200,10 +1181,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This choice for software or hardware gate does not exist\n"); return -EINVAL; - } /* switch(data[6]) */ + } i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7; @@ -1295,18 +1276,16 @@ static int apci1500_timer_config(struct comedi_device *dev, outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Error in selection of interrupt enable or disable\n"); return -EINVAL; - } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ - } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ - else { - dev_warn(dev->hw_dev, + } + } else { + dev_warn(dev->class_dev, "Error in selection of reload value\n"); return -EINVAL; - } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ + } i_TimerCounterWatchdogInterrupt = data[7]; i_TimerCounter2Init = 1; break; @@ -1320,10 +1299,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[2] = APCI1500_WATCHDOG; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This choice is not a watchdog nor a counter\n"); return -EINVAL; - } /* switch(data[2]) */ + } /* Selecting single or continuous mode */ switch (data[4]) { @@ -1334,10 +1313,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This option for single/continuous mode does not exist\n"); return -EINVAL; - } /* switch(data[4]) */ + } /* Selecting software or hardware gate */ switch (data[6]) { @@ -1348,10 +1327,10 @@ static int apci1500_timer_config(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "This choice for software or hardware gate does not exist\n"); return -EINVAL; - } /* switch(data[6]) */ + } /* Test if used for watchdog */ @@ -1360,10 +1339,9 @@ static int apci1500_timer_config(struct comedi_device *dev, /* - Enables retrigger */ /* - Pulses output */ i_TimerCounterMode = data[2] | data[4] | 0x54; - } /* if (data[2] == APCI1500_WATCHDOG) */ - else { + } else { i_TimerCounterMode = data[2] | data[4] | data[6] | 7; - } /* elseif (data[2] == APCI1500_WATCHDOG) */ + } /* Test the reload value */ if ((data[3] >= 0) && (data[3] <= 65535)) { @@ -1455,29 +1433,28 @@ static int apci1500_timer_config(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* elseif(data[2]==APCI1500_COUNTER) */ + } + + } else { - } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ - else { - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "Error in selection of interrupt enable or disable\n"); return -EINVAL; - } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ - } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ - else { - dev_warn(dev->hw_dev, + } + } else { + dev_warn(dev->class_dev, "Error in selection of reload value\n"); return -EINVAL; - } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ + } i_TimerCounterWatchdogInterrupt = data[7]; i_WatchdogCounter3Init = 1; break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The specified counter/timer option does not exist\n"); return -EINVAL; - } /* switch(data[1]) */ + } i_CounterLogic = data[2]; return insn->n; } @@ -1502,12 +1479,11 @@ static int apci1500_timer_write(struct comedi_device *dev, switch (data[1]) { case START: if (i_TimerCounter1Init == 1) { - if (i_TimerCounterWatchdogInterrupt == 1) { + if (i_TimerCounterWatchdogInterrupt == 1) i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ - } /* if(i_TimerCounterWatchdogInterrupt==1) */ - else { + else i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ - } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ + /* Starts timer/counter 1 */ i_TimerCounter1Enabled = 1; /* Selects the commands and status register */ @@ -1517,9 +1493,8 @@ static int apci1500_timer_write(struct comedi_device *dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_TimerCounter1Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Counter/Timer1 not configured\n"); return -EINVAL; } @@ -1545,12 +1520,11 @@ static int apci1500_timer_write(struct comedi_device *dev, /* Set Trigger and gate */ i_CommandAndStatusValue = 0x6; - } /* if( i_TimerCounter1Enabled==1) */ - else { + } else { /* Set Trigger */ i_CommandAndStatusValue = 0x2; - } /* elseif(i_TimerCounter1Enabled==1) */ + } /* Selects the commands and status register */ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, @@ -1559,31 +1533,29 @@ static int apci1500_timer_write(struct comedi_device *dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_TimerCounter1Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Counter/Timer1 not configured\n"); return -EINVAL; } break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; - } /* switch(data[1]) */ + } break; case COUNTER2: switch (data[1]) { case START: if (i_TimerCounter2Init == 1) { - if (i_TimerCounterWatchdogInterrupt == 1) { + if (i_TimerCounterWatchdogInterrupt == 1) i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ - } /* if(i_TimerCounterWatchdogInterrupt==1) */ - else { + else i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ - } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ + /* Starts timer/counter 2 */ i_TimerCounter2Enabled = 1; /* Selects the commands and status register */ @@ -1593,9 +1565,8 @@ static int apci1500_timer_write(struct comedi_device *dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_TimerCounter2Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Counter/Timer2 not configured\n"); return -EINVAL; } @@ -1620,12 +1591,11 @@ static int apci1500_timer_write(struct comedi_device *dev, /* Set Trigger and gate */ i_CommandAndStatusValue = 0x6; - } /* if( i_TimerCounter2Enabled==1) */ - else { + } else { /* Set Trigger */ i_CommandAndStatusValue = 0x2; - } /* elseif(i_TimerCounter2Enabled==1) */ + } /* Selects the commands and status register */ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, @@ -1634,30 +1604,28 @@ static int apci1500_timer_write(struct comedi_device *dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_TimerCounter2Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Counter/Timer2 not configured\n"); return -EINVAL; } break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; - } /* switch(data[1]) */ + } break; case COUNTER3: switch (data[1]) { case START: if (i_WatchdogCounter3Init == 1) { - if (i_TimerCounterWatchdogInterrupt == 1) { + if (i_TimerCounterWatchdogInterrupt == 1) i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ - } /* if(i_TimerCounterWatchdogInterrupt==1) */ - else { + else i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ - } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ + /* Starts Watchdog/counter 3 */ i_WatchdogCounter3Enabled = 1; /* Selects the commands and status register */ @@ -1668,9 +1636,8 @@ static int apci1500_timer_write(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_WatchdogCounter3init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Watchdog/Counter3 not configured\n"); return -EINVAL; } @@ -1698,12 +1665,11 @@ static int apci1500_timer_write(struct comedi_device *dev, /* Set Trigger and gate */ i_CommandAndStatusValue = 0x6; - } /* if( i_WatchdogCounter3Enabled==1) */ - else { + } else { /* Set Trigger */ i_CommandAndStatusValue = 0x2; - } /* elseif(i_WatchdogCounter3Enabled==1) */ + } /* Selects the commands and status register */ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, @@ -1712,9 +1678,8 @@ static int apci1500_timer_write(struct comedi_device *dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_WatchdogCounter3Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Counter3 not configured\n"); return -EINVAL; } @@ -1730,30 +1695,29 @@ static int apci1500_timer_write(struct comedi_device *dev, outb(0x6, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_WatchdogCounter3Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Watchdog 3 not configured\n"); return -EINVAL; } break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "Wrong choice of watchdog/counter3\n"); return -EINVAL; - } /* switch(data[2]) */ + } break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; - } /* switch(data[1]) */ + } break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The specified choice for counter/watchdog/timer does not exist\n"); return -EINVAL; - } /* switch(data[0]) */ + } return insn->n; } @@ -1778,12 +1742,11 @@ static int apci1500_timer_bits(struct comedi_device *dev, /* Set RCC and gate */ i_CommandAndStatusValue = 0xC; - } /* if( i_TimerCounter1Init==1) */ - else { + } else { /* Set RCC */ i_CommandAndStatusValue = 0x8; - } /* elseif(i_TimerCounter1Init==1) */ + } /* Selects the commands and status register */ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, @@ -1808,12 +1771,11 @@ static int apci1500_timer_bits(struct comedi_device *dev, data[0] = data[0] | inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_TimerCounter1Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Timer/Counter1 not configured\n"); return -EINVAL; - } /* elseif( i_TimerCounter1Init==1) */ + } break; case COUNTER2: /* Read counter/timer2 */ @@ -1822,12 +1784,11 @@ static int apci1500_timer_bits(struct comedi_device *dev, /* Set RCC and gate */ i_CommandAndStatusValue = 0xC; - } /* if( i_TimerCounter2Init==1) */ - else { + } else { /* Set RCC */ i_CommandAndStatusValue = 0x8; - } /* elseif(i_TimerCounter2Init==1) */ + } /* Selects the commands and status register */ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, @@ -1852,12 +1813,11 @@ static int apci1500_timer_bits(struct comedi_device *dev, data[0] = data[0] | inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_TimerCounter2Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Timer/Counter2 not configured\n"); return -EINVAL; - } /* elseif( i_TimerCounter2Init==1) */ + } break; case COUNTER3: /* Read counter/watchdog2 */ @@ -1866,12 +1826,11 @@ static int apci1500_timer_bits(struct comedi_device *dev, /* Set RCC and gate */ i_CommandAndStatusValue = 0xC; - } /* if( i_TimerCounter2Init==1) */ - else { + } else { /* Set RCC */ i_CommandAndStatusValue = 0x8; - } /* elseif(i_WatchdogCounter3Init==1) */ + } /* Selects the commands and status register */ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, @@ -1896,18 +1855,17 @@ static int apci1500_timer_bits(struct comedi_device *dev, data[0] = data[0] | inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if( i_WatchdogCounter3Init==1) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "WatchdogCounter3 not configured\n"); return -EINVAL; - } /* elseif( i_WatchdogCounter3Init==1) */ + } break; default: - dev_warn(dev->hw_dev, + dev_warn(dev->class_dev, "The choice of timer/counter/watchdog does not exist\n"); return -EINVAL; - } /* switch(data[0]) */ + } return insn->n; } @@ -1946,17 +1904,15 @@ static int apci1500_do_bits(struct comedi_device *dev, outl(0x0, devpriv->i_IobaseAmcc + 0x38); if (data[0] == 1) { i_Constant = 0xC0; - } /* if(data[0]==1) */ - else { + } else { if (data[0] == 0) { i_Constant = 0x00; - } /* if{data[0]==0) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "The parameter passed to driver is in error for enabling the voltage interrupt\n"); return -EINVAL; - } /* else if(data[0]==0) */ - } /* elseif(data[0]==1) */ + } + } /* Selects the mode specification register of port B */ outb(APCI1500_RW_PORT_B_SPECIFICATION, @@ -2062,6 +2018,8 @@ static void apci1500_interrupt(int irq, void *d) struct addi_private *devpriv = dev->private; unsigned int ui_InterruptStatus = 0; int i_RegValue = 0; + + /* Clear the interrupt mask */ i_InterruptMask = 0; /* Read the board interrupt status */ @@ -2071,10 +2029,7 @@ static void apci1500_interrupt(int irq, void *d) if ((ui_InterruptStatus & 0x800000) == 0x800000) { /* Disable all Interrupt */ /* Selects the master interrupt control register */ - /* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ /* Disables the main interrupt on the board */ - /* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /* Selects the command and status register of port A */ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2109,11 +2064,10 @@ static void apci1500_interrupt(int irq, void *d) i_InputChannel = 1 + (i_RegValue >> 1); - } /* if(i_Logic==APCI1500_OR_PRIORITY) */ - else { + } else { i_InputChannel = 0; - } /* elseif(i_Logic==APCI1500_OR_PRIORITY) */ - } /* if ((i_RegValue & 0x60) == 0x60) */ + } + } /* Selects the command and status register of port B */ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, @@ -2146,17 +2100,16 @@ static void apci1500_interrupt(int irq, void *d) if (i_RegValue & 0x80) { i_InterruptMask = i_InterruptMask | 0x40; - } /* if (i_RegValue & 0x80) */ + } if (i_RegValue & 0x40) { i_InterruptMask = i_InterruptMask | 0x80; - } /* if (i_RegValue & 0x40) */ - } /* if (i_RegValue) */ - else { + } + } else { i_InterruptMask = i_InterruptMask | 2; - } /* if (i_RegValue) */ - } /* if ((i_RegValue & 0x60) == 0x60) */ + } + } /* Selects the command and status register of timer 1 */ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, @@ -2174,7 +2127,7 @@ static void apci1500_interrupt(int irq, void *d) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 4; - } /* if ((i_RegValue & 0x60) == 0x60) */ + } /* Selects the command and status register of timer 2 */ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2191,7 +2144,7 @@ static void apci1500_interrupt(int irq, void *d) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 8; - } /* if ((i_RegValue & 0x60) == 0x60) */ + } /* Selects the command and status register of timer 3 */ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, @@ -2208,13 +2161,11 @@ static void apci1500_interrupt(int irq, void *d) outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - if (i_CounterLogic == APCI1500_COUNTER) { + if (i_CounterLogic == APCI1500_COUNTER) i_InterruptMask = i_InterruptMask | 0x10; - } /* if(i_CounterLogic==APCI1500_COUNTER) */ - else { + else i_InterruptMask = i_InterruptMask | 0x20; - } - } /* if ((i_RegValue & 0x60) == 0x60) */ + } send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ /* Enable all Interrupts */ @@ -2224,13 +2175,11 @@ static void apci1500_interrupt(int irq, void *d) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Authorizes the main interrupt on the board */ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */ - else { - dev_warn(dev->hw_dev, + } else { + dev_warn(dev->class_dev, "Interrupt from unknown source\n"); - } /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */ - return; + } } static int apci1500_reset(struct comedi_device *dev) @@ -2379,36 +2328,36 @@ static int apci1500_reset(struct comedi_device *dev) outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* reset all the digital outputs */ outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); -/* Disable the board interrupt */ + /* Disable the board interrupt */ /* Selects the master interrupt control register */ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/* Deactivates all interrupts */ + /* Deactivates all interrupts */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the command and status register of port A */ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/* Deactivates all interrupts */ + /* Deactivates all interrupts */ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the command and status register of port B */ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/* Deactivates all interrupts */ + /* Deactivates all interrupts */ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the command and status register of timer 1 */ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/* Deactivates all interrupts */ + /* Deactivates all interrupts */ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the command and status register of timer 2 */ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/* Deactivates all interrupts */ + /* Deactivates all interrupts */ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/* Selects the command and status register of timer 3*/ + /* Selects the command and status register of timer 3*/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/* Deactivates all interrupts */ + /* Deactivates all interrupts */ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index 8a613ae0acba..98de96953a29 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -1,28 +1,3 @@ -/* - * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - * - * ADDI-DATA GmbH - * Dieselstrasse 3 - * D-77833 Ottersweier - * Tel: +19(0)7223/9493-0 - * Fax: +49(0)7223/9493-92 - * http://www.addi-data.com - * info@addi-data.com - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - */ - -#define APCI1564_ADDRESS_RANGE 128 - /* Digital Input IRQ Function Selection */ #define APCI1564_DI_INT_OR (0 << 1) #define APCI1564_DI_INT_AND (1 << 1) @@ -32,10 +7,10 @@ #define APCI1564_DI_INT_DISABLE 0xfffffffb /* Digital Output Interrupt Enable Disable. */ -#define APCI1564_DIGITAL_OP_VCC_INTERRUPT_ENABLE 0x1 -#define APCI1564_DIGITAL_OP_VCC_INTERRUPT_DISABLE 0xfffffffe -#define APCI1564_DIGITAL_OP_CC_INTERRUPT_ENABLE 0x2 -#define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xfffffffd +#define APCI1564_DO_VCC_INT_ENABLE 0x1 +#define APCI1564_DO_VCC_INT_DISABLE 0xfffffffe +#define APCI1564_DO_CC_INT_ENABLE 0x2 +#define APCI1564_DO_CC_INT_DISABLE 0xfffffffd /* TIMER COUNTER WATCHDOG DEFINES */ #define ADDIDATA_TIMER 0 @@ -76,55 +51,21 @@ #define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64 /* - * dev>iobase Register Map + * dev->iobase Register Map */ -#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20)) -#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20)) -#define APCI1564_TCW_TIMEBASE_REG(x) (0x08 + ((x) * 0x20)) -#define APCI1564_TCW_CTRL_REG(x) (0x0c + ((x) * 0x20)) -#define APCI1564_TCW_STATUS_REG(x) (0x10 + ((x) * 0x20)) -#define APCI1564_TCW_IRQ_REG(x) (0x14 + ((x) * 0x20)) -#define APCI1564_TCW_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20)) -#define APCI1564_TCW_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20)) - -/* - * Configures The Digital Output Subdevice. - * - * data[1] 0 = Disable VCC Interrupt, 1 = Enable VCC Interrupt - * data[2] 0 = Disable CC Interrupt, 1 = Enable CC Interrupt - */ -static int apci1564_do_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1564_private *devpriv = dev->private; - unsigned int ul_Command = 0; - - if ((data[0] != 0) && (data[0] != 1)) { - dev_err(dev->class_dev, "Data should be 1 or 0\n"); - return -EINVAL; - } - - if (data[1] == 1) - ul_Command = ul_Command | 0x1; - else - ul_Command = ul_Command & 0xFFFFFFFE; - - if (data[2] == 1) - ul_Command = ul_Command | 0x2; - else - ul_Command = ul_Command & 0xFFFFFFFD; - - outl(ul_Command, devpriv->amcc_iobase + APCI1564_DO_INT_CTRL_REG); - devpriv->tsk_current = current; - return insn->n; -} +#define APCI1564_COUNTER_REG(x) (0x00 + ((x) * 0x20)) +#define APCI1564_COUNTER_RELOAD_REG(x) (0x04 + ((x) * 0x20)) +#define APCI1564_COUNTER_TIMEBASE_REG(x) (0x08 + ((x) * 0x20)) +#define APCI1564_COUNTER_CTRL_REG(x) (0x0c + ((x) * 0x20)) +#define APCI1564_COUNTER_STATUS_REG(x) (0x10 + ((x) * 0x20)) +#define APCI1564_COUNTER_IRQ_REG(x) (0x14 + ((x) * 0x20)) +#define APCI1564_COUNTER_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20)) +#define APCI1564_COUNTER_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20)) /* - * Configures The Timer, Counter or Watchdog + * Configures The Timer or Counter * - * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[0] Configure as: 0 = Timer, 1 = Counter * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt * data[2] Time Unit * data[3] Reload Value @@ -141,14 +82,7 @@ static int apci1564_timer_config(struct comedi_device *dev, unsigned int ul_Command1 = 0; devpriv->tsk_current = current; - if (data[0] == ADDIDATA_WATCHDOG) { - devpriv->timer_select_mode = ADDIDATA_WATCHDOG; - - /* Disable the watchdog */ - outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG); - /* Loading the Reload value */ - outl(data[3], devpriv->amcc_iobase + APCI1564_WDOG_RELOAD_REG); - } else if (data[0] == ADDIDATA_TIMER) { + if (data[0] == ADDIDATA_TIMER) { /* First Stop The Timer */ ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; @@ -162,14 +96,14 @@ static int apci1564_timer_config(struct comedi_device *dev, outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); outl(0x0, devpriv->amcc_iobase + APCI1564_DO_IRQ_REG); outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_IRQ_REG); - outl(0x0, - dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)); - outl(0x0, - dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)); - outl(0x0, - dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)); - outl(0x0, - dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)); + outl(0x0, dev->iobase + + APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER1)); + outl(0x0, dev->iobase + + APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER2)); + outl(0x0, dev->iobase + + APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER3)); + outl(0x0, dev->iobase + + APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER4)); } else { /* disable Timer interrupt */ outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); @@ -190,13 +124,16 @@ static int apci1564_timer_config(struct comedi_device *dev, devpriv->mode_select_register = data[5]; /* First Stop The Counter */ - ul_Command1 = inl(dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + ul_Command1 = inl(dev->iobase + + APCI1564_COUNTER_CTRL_REG(data[5] - 1)); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; /* Stop The Timer */ - outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + + APCI1564_COUNTER_CTRL_REG(data[5] - 1)); /* Set the reload value */ - outl(data[3], dev->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1)); + outl(data[3], dev->iobase + + APCI1564_COUNTER_RELOAD_REG(data[5] - 1)); /* Set the mode : */ /* - Disable the hardware */ @@ -209,26 +146,28 @@ static int apci1564_timer_config(struct comedi_device *dev, ul_Command1 = (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | (unsigned int) ((unsigned int) data[4] << 16UL); - outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + + APCI1564_COUNTER_CTRL_REG(data[5] - 1)); /* Enable or Disable Interrupt */ ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); - outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + + APCI1564_COUNTER_CTRL_REG(data[5] - 1)); /* Set the Up/Down selection */ ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18); - outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + + APCI1564_COUNTER_CTRL_REG(data[5] - 1)); } else { dev_err(dev->class_dev, "Invalid subdevice.\n"); } - return insn->n; } /* - * Start / Stop The Selected Timer, Counter or Watchdog + * Start / Stop The Selected Timer or Counter * - * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[0] Configure as: 0 = Timer, 1 = Counter * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter) */ static int apci1564_timer_write(struct comedi_device *dev, @@ -239,23 +178,6 @@ static int apci1564_timer_write(struct comedi_device *dev, struct apci1564_private *devpriv = dev->private; unsigned int ul_Command1 = 0; - if (devpriv->timer_select_mode == ADDIDATA_WATCHDOG) { - switch (data[1]) { - case 0: /* stop the watchdog */ - /* disable the watchdog */ - outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG); - break; - case 1: /* start the watchdog */ - outl(0x0001, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG); - break; - case 2: /* Software trigger */ - outl(0x0201, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG); - break; - default: - dev_err(dev->class_dev, "Specified functionality does not exist.\n"); - return -EINVAL; - } - } if (devpriv->timer_select_mode == ADDIDATA_TIMER) { if (data[1] == 1) { ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); @@ -270,11 +192,10 @@ static int apci1564_timer_write(struct comedi_device *dev, ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); } - } - if (devpriv->timer_select_mode == ADDIDATA_COUNTER) { + } else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) { ul_Command1 = inl(dev->iobase + - APCI1564_TCW_CTRL_REG(devpriv->mode_select_register - 1)); + APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1)); if (data[1] == 1) { /* Start the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; @@ -287,13 +208,15 @@ static int apci1564_timer_write(struct comedi_device *dev, ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; } outl(ul_Command1, dev->iobase + - APCI1564_TCW_CTRL_REG(devpriv->mode_select_register - 1)); + APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1)); + } else { + dev_err(dev->class_dev, "Invalid subdevice.\n"); } return insn->n; } /* - * Read The Selected Timer, Counter or Watchdog + * Read The Selected Timer or Counter */ static int apci1564_timer_read(struct comedi_device *dev, struct comedi_subdevice *s, @@ -303,11 +226,7 @@ static int apci1564_timer_read(struct comedi_device *dev, struct apci1564_private *devpriv = dev->private; unsigned int ul_Command1 = 0; - if (devpriv->timer_select_mode == ADDIDATA_WATCHDOG) { - /* Stores the status of the Watchdog */ - data[0] = inl(devpriv->amcc_iobase + APCI1564_WDOG_STATUS_REG) & 0x1; - data[1] = inl(devpriv->amcc_iobase + APCI1564_WDOG_REG); - } else if (devpriv->timer_select_mode == ADDIDATA_TIMER) { + if (devpriv->timer_select_mode == ADDIDATA_TIMER) { /* Stores the status of the Timer */ data[0] = inl(devpriv->amcc_iobase + APCI1564_TIMER_STATUS_REG) & 0x1; @@ -317,10 +236,10 @@ static int apci1564_timer_read(struct comedi_device *dev, /* Read the Counter Actual Value. */ data[0] = inl(dev->iobase + - APCI1564_TCW_REG(devpriv->mode_select_register - 1)); + APCI1564_COUNTER_REG(devpriv->mode_select_register - 1)); ul_Command1 = inl(dev->iobase + - APCI1564_TCW_STATUS_REG(devpriv->mode_select_register - 1)); + APCI1564_COUNTER_STATUS_REG(devpriv->mode_select_register - 1)); /* Get the software trigger status */ data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); @@ -333,10 +252,8 @@ static int apci1564_timer_read(struct comedi_device *dev, /* Get the overflow status */ data[4] = (unsigned char) ((ul_Command1 >> 0) & 1); - } else if ((devpriv->timer_select_mode != ADDIDATA_TIMER) - && (devpriv->timer_select_mode != ADDIDATA_WATCHDOG) - && (devpriv->timer_select_mode != ADDIDATA_COUNTER)) { - dev_err(dev->class_dev, "Invalid Subdevice!\n"); + } else { + dev_err(dev->class_dev, "Invalid subdevice.\n"); } return insn->n; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index 77cee876a374..2950815b65f4 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -241,26 +241,19 @@ static const struct comedi_lrange range_apci3120_ao = { /* FUNCTION DEFINITIONS */ - -/* -+----------------------------------------------------------------------------+ -| ANALOG INPUT SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ - static int apci3120_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; unsigned int i; if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE)) return -1; - /* Check for Conversion time to be added ?? */ + /* Check for Conversion time to be added */ devpriv->ui_EocEosConversionTime = data[2]; if (data[0] == APCI3120_EOS_MODE) { @@ -282,7 +275,6 @@ static int apci3120_ai_insn_config(struct comedi_device *dev, else devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Copy channel list and Range List to devpriv */ - devpriv->ui_AiNbrofChannels = data[3]; for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) devpriv->ui_AiChannelList[i] = data[4 + i]; @@ -311,7 +303,7 @@ static int apci3120_setup_chan_list(struct comedi_device *dev, char check) { struct addi_private *devpriv = dev->private; - unsigned int i; /* , differencial=0, bipolar=0; */ + unsigned int i; unsigned int gain; unsigned short us_TmpValue; @@ -326,7 +318,7 @@ static int apci3120_setup_chan_list(struct comedi_device *dev, if (check) return 1; - /* Code to set the PA and PR...Here it set PA to 0.. */ + /* Code to set the PA and PR...Here it set PA to 0 */ devpriv->us_OutputRegister = devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR; devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8; @@ -334,16 +326,16 @@ static int apci3120_setup_chan_list(struct comedi_device *dev, for (i = 0; i < n_chan; i++) { /* store range list to card */ - us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */ + us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number */ if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */ else - us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */ + us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar */ gain = CR_RANGE(chanlist[i]); /* get gain number */ us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */ - us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */ + us_TmpValue |= i << 8; /* To select the RAM LOCATION */ outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); } return 1; /* we can serve this with scan logic */ @@ -359,7 +351,7 @@ static int apci3120_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; unsigned short us_ConvertTiming, us_TmpValue, i; unsigned char b_Tmp; @@ -370,24 +362,21 @@ static int apci3120_ai_insn_read(struct comedi_device *dev, else us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */ - /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */ - /* Clear software registers */ devpriv->b_TimerSelectMode = 0; devpriv->b_ModeSelectRegister = 0; devpriv->us_OutputRegister = 0; -/* devpriv->b_DigitalOutputRegister=0; */ if (insn->unused[0] == 222) { /* second insn read */ for (i = 0; i < insn->n; i++) data[i] = devpriv->ui_AiReadData[i]; } else { devpriv->tsk_Current = current; /* Save the current process task structure */ -/* - * Testing if board have the new Quartz and calculate the time value - * to set in the timer - */ + /* + * Testing if board have the new Quartz and calculate the time value + * to set in the timer + */ us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); @@ -406,9 +395,9 @@ static int apci3120_ai_insn_read(struct comedi_device *dev, case APCI3120_EOC_MODE: -/* - * Testing the interrupt flag and set the EOC bit Clears the FIFO - */ + /* + * Testing the interrupt flag and set the EOC bit Clears the FIFO + */ inw(devpriv->iobase + APCI3120_RESET_FIFO); /* Initialize the sequence array */ @@ -556,7 +545,6 @@ static int apci3120_ai_insn_read(struct comedi_device *dev, inw(devpriv->iobase + APCI3120_RD_STATUS); /* Sets gate 0 */ - devpriv->us_OutputRegister = devpriv-> us_OutputRegister | APCI3120_ENABLE_TIMER0; @@ -583,7 +571,7 @@ static int apci3120_ai_insn_read(struct comedi_device *dev, data[i] = (unsigned int) us_TmpValue; } - devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */ + devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults */ } break; @@ -591,7 +579,7 @@ static int apci3120_ai_insn_read(struct comedi_device *dev, dev_err(dev->class_dev, "inputs wrong\n"); } - devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */ + devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable */ } return insn->n; @@ -623,10 +611,10 @@ static int apci3120_reset(struct comedi_device *dev) devpriv->us_OutputRegister = 0; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); -/* - * Code to set the all anolog o/p channel to 0v 8191 is decimal - * value for zero(0 v)volt in bipolar mode(default) - */ + /* + * Code to set the all anolog o/p channel to 0v 8191 is decimal + * value for zero(0 v)volt in bipolar mode(default) + */ outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */ outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */ outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */ @@ -637,9 +625,6 @@ static int apci3120_reset(struct comedi_device *dev) outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */ outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */ - /* Reset digital output to L0W */ - -/* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */ udelay(10); inw(dev->iobase + 0); /* make a dummy read */ @@ -689,12 +674,6 @@ static int apci3120_cancel(struct comedi_device *dev, /* Disable BUS Master PCI */ outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), - * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */ - - /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), - * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */ - /* Disable ext trigger */ apci3120_exttrig_disable(dev); @@ -802,7 +781,7 @@ static int apci3120_cyclic_ai(int mode, struct comedi_device *dev, struct comedi_subdevice *s) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned char b_Tmp; @@ -811,53 +790,29 @@ static int apci3120_cyclic_ai(int mode, 0, ui_TimerValue0, ui_ConvertTiming; unsigned short us_TmpValue; - /*******************/ /* Resets the FIFO */ - /*******************/ inb(dev->iobase + APCI3120_RESET_FIFO); - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* inw(dev->iobase+APCI3120_RD_STATUS); */ - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - devpriv->ai_running = 1; /* clear software registers */ devpriv->b_TimerSelectMode = 0; devpriv->us_OutputRegister = 0; devpriv->b_ModeSelectRegister = 0; - /* devpriv->b_DigitalOutputRegister=0; */ - - /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */ - /****************************/ /* Clear Timer Write TC int */ - /****************************/ outl(APCI3120_CLEAR_WRITE_TC_INT, devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR); - /************************************/ - /* Clears the timer status register */ - /************************************/ - - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */ - /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */ - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - - /**************************/ /* Disables All Timer */ /* Sets PR and PA to 0 */ - /**************************/ devpriv->us_OutputRegister = devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER0 & APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - /*******************/ /* Resets the FIFO */ - /*******************/ /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ inb(devpriv->iobase + APCI3120_RESET_FIFO); /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ @@ -866,44 +821,21 @@ static int apci3120_cyclic_ai(int mode, s->async->cur_chan = 0; devpriv->ui_DmaActualBuffer = 0; - /* value for timer2 minus -2 has to be done .....dunno y?? */ + /* value for timer2 minus -2 has to be done */ ui_TimerValue2 = cmd->stop_arg - 2; ui_ConvertTiming = cmd->convert_arg; if (mode == 2) ui_DelayTiming = cmd->scan_begin_arg; - /**********************************/ /* Initializes the sequence array */ - /**********************************/ if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, cmd->chanlist, 0)) return -EINVAL; us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); -/*** EL241003 : add this section in comment because floats must not be used - if((us_TmpValue & 0x00B0)==0x00B0) - { - f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2); - ui_TimerValue0=(unsigned int)f_ConvertValue; - if (mode==2) - { - f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2); - ui_TimerValue1 = (unsigned int) f_DelayValue; - } - } - else - { - f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1); - ui_TimerValue0=(unsigned int)f_ConvertValue; - if (mode == 2) - { - f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1); - ui_TimerValue1 = (unsigned int) f_DelayValue; - } - } -***********************************************************************************************/ -/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/ + + /* EL241003 Begin: add this section to replace floats calculation by integer calculations */ /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */ if ((us_TmpValue & 0x00B0) == 0x00B0 || !strcmp(this_board->pc_DriverName, "apci3001")) { @@ -926,7 +858,7 @@ static int apci3120_cyclic_ai(int mode, ui_TimerValue1 = ui_TimerValue1 / 1000000; } } -/*** EL241003 End ******************************************************************************/ + /* EL241003 End */ if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) apci3120_exttrig_enable(dev); /* activate EXT trigger */ @@ -985,15 +917,8 @@ static int apci3120_cyclic_ai(int mode, break; } - /* ##########common for all modes################# */ - - /***********************/ - /* Clears the SCAN bit */ - /***********************/ - + /* common for all modes */ /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */ - devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & APCI3120_DISABLE_SCAN; /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ @@ -1015,10 +940,10 @@ static int apci3120_cyclic_ai(int mode, dev->iobase + APCI3120_WRITE_MODE_SELECT); if (cmd->stop_src == TRIG_COUNT) { -/* - * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to - * disable it (Set Bit D14 to 0) - */ + /* + * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to + * disable it (Set Bit D14 to 0) + */ devpriv->us_OutputRegister = devpriv-> us_OutputRegister & APCI3120_DISABLE_TIMER2; @@ -1084,14 +1009,9 @@ static int apci3120_cyclic_ai(int mode, /* If DMA Enabled */ unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short); - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* inw(dev->iobase+0); reset EOC bit */ - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ devpriv->b_InterruptMode = APCI3120_DMA_MODE; - /************************************/ /* Disables the EOC, EOS interrupt */ - /************************************/ devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT; @@ -1114,7 +1034,7 @@ static int apci3120_cyclic_ai(int mode, dmalen0; } - if (cmd->flags & TRIG_WAKE_EOS) { + if (cmd->flags & CMDF_WAKE_EOS) { /* don't we want wake up every scan? */ if (dmalen0 > scan_bytes) { dmalen0 = scan_bytes; @@ -1139,17 +1059,15 @@ static int apci3120_cyclic_ai(int mode, /* Initialize DMA */ -/* - * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS - * register 1 - */ + /* + * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS + * register 1 + */ ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS); /* changed since 16 bit interface for add on */ - /*********************/ /* ENABLE BUS MASTER */ - /*********************/ outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->i_IobaseAddon + 2); @@ -1158,112 +1076,88 @@ static int apci3120_cyclic_ai(int mode, outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); -/* - * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux - * driver - */ + /* + * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux + * driver + */ outw(0x1000, devpriv->i_IobaseAddon + 2); /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ /* 2 No change */ /* A2P FIFO MANAGEMENT */ /* A2P fifo reset & transfer control enable */ - - /***********************/ - /* A2P FIFO MANAGEMENT */ - /***********************/ outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR); -/* - * 3 - * beginning address of dma buf The 32 bit address of dma buffer - * is converted into two 16 bit addresses Can done by using _attach - * and put into into an array array used may be for differnet pages - */ + /* + * 3 + * beginning address of dma buf The 32 bit address of dma buffer + * is converted into two 16 bit addresses Can done by using _attach + * and put into into an array array used may be for differnet pages + */ /* DMA Start Address Low */ outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF), devpriv->i_IobaseAddon + 2); - /*************************/ /* DMA Start Address High */ - /*************************/ outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); outw((devpriv->ul_DmaBufferHw[0] / 65536), devpriv->i_IobaseAddon + 2); -/* - * 4 - * amount of bytes to be transferred set transfer count used ADDON - * MWTC register commented testing - * outl(devpriv->ui_DmaBufferUsesize[0], - * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC); - */ + /* + * 4 + * amount of bytes to be transferred set transfer count used ADDON + * MWTC register commented testing + */ - /**************************/ /* Nbr of acquisition LOW */ - /**************************/ outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF), devpriv->i_IobaseAddon + 2); - /***************************/ /* Nbr of acquisition HIGH */ - /***************************/ outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); outw((devpriv->ui_DmaBufferUsesize[0] / 65536), devpriv->i_IobaseAddon + 2); -/* - * 5 - * To configure A2P FIFO testing outl( - * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); - */ + /* + * 5 + * To configure A2P FIFO testing outl( + * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); + */ - /******************/ /* A2P FIFO RESET */ - /******************/ -/* - * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux - * driver - */ + /* + * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux + * driver + */ outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ -/* - * 6 - * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE | - * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 - */ - - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* outw(3,devpriv->i_IobaseAddon + 4); */ - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - -/* - * 7 - * initialise end of dma interrupt AINT_WRITE_COMPL = - * ENABLE_WRITE_TC_INT(ADDI) - */ - /***************************************************/ + /* + * 6 + * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE | + * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 + */ + + /* + * 7 + * initialise end of dma interrupt AINT_WRITE_COMPL = + * ENABLE_WRITE_TC_INT(ADDI) + */ /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */ - /***************************************************/ outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | APCI3120_ENABLE_WRITE_TC_INT), devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /******************************************/ /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */ - /******************************************/ outw(3, devpriv->i_IobaseAddon + 4); /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - /******************/ /* A2P FIFO RESET */ - /******************/ /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ outl(0x04000000UL, devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR); @@ -1323,8 +1217,8 @@ static int apci3120_ai_cmd(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_FOLLOW) return apci3120_cyclic_ai(1, dev, s); - else /* TRIG_TIMER */ - return apci3120_cyclic_ai(2, dev, s); + /* TRIG_TIMER */ + return apci3120_cyclic_ai(2, dev, s); } /* @@ -1416,11 +1310,11 @@ static void apci3120_interrupt_dma(int irq, void *d) outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); outw(high_word, devpriv->i_IobaseAddon + 2); -/* - * To configure A2P FIFO - * ENABLE A2P FIFO WRITE AND ENABLE AMWEN - * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 - */ + /* + * To configure A2P FIFO + * ENABLE A2P FIFO WRITE AND ENABLE AMWEN + * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 + */ outw(3, devpriv->i_IobaseAddon + 4); /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | @@ -1433,7 +1327,7 @@ static void apci3120_interrupt_dma(int irq, void *d) devpriv->ul_DmaBufferVirtual[devpriv-> ui_DmaActualBuffer], samplesinbuf); - if (!(cmd->flags & TRIG_WAKE_EOS)) { + if (!(cmd->flags & CMDF_WAKE_EOS)) { s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); } @@ -1450,10 +1344,10 @@ static void apci3120_interrupt_dma(int irq, void *d) if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */ devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer; } else { -/* - * restart DMA if is not used double buffering - * ADDED REINITIALISE THE DMA - */ + /* + * restart DMA if is not used double buffering + * ADDED REINITIALISE THE DMA + */ ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); @@ -1462,11 +1356,11 @@ static void apci3120_interrupt_dma(int irq, void *d) outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->i_IobaseAddon + 2); outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */ -/* - * A2P FIFO MANAGEMENT - * A2P fifo reset & transfer control enable - */ + outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); + /* + * A2P FIFO MANAGEMENT + * A2P fifo reset & transfer control enable + */ outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); @@ -1488,11 +1382,11 @@ static void apci3120_interrupt_dma(int irq, void *d) outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); outw(high_word, devpriv->i_IobaseAddon + 2); -/* - * To configure A2P FIFO - * ENABLE A2P FIFO WRITE AND ENABLE AMWEN - * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 - */ + /* + * To configure A2P FIFO + * ENABLE A2P FIFO WRITE AND ENABLE AMWEN + * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 + */ outw(3, devpriv->i_IobaseAddon + 4); /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | @@ -1570,7 +1464,6 @@ static void apci3120_interrupt(int irq, void *d) if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* Read the AI Value */ - devpriv->ui_AiReadData[0] = (unsigned int) inw(devpriv->iobase + 0); devpriv->b_EocEosInterrupt = APCI3120_DISABLE; @@ -1670,7 +1563,6 @@ static void apci3120_interrupt(int irq, void *d) default: /* disable Timer Interrupt */ - devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & @@ -1688,17 +1580,12 @@ static void apci3120_interrupt(int irq, void *d) if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) { if (devpriv->ai_running) { - /****************************/ /* Clear Timer Write TC int */ - /****************************/ - outl(APCI3120_CLEAR_WRITE_TC_INT, devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR); - /************************************/ /* Clears the timer status register */ - /************************************/ inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); /* do some data transfer */ apci3120_interrupt_dma(irq, d); @@ -1711,8 +1598,6 @@ static void apci3120_interrupt(int irq, void *d) } } - - return; } /* @@ -1728,7 +1613,7 @@ static int apci3120_config_insn_timer(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; unsigned int ui_Timervalue2; unsigned short us_TmpValue; @@ -1741,13 +1626,12 @@ static int apci3120_config_insn_timer(struct comedi_device *dev, ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */ - /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */ us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); -/* - * EL250804: Testing if board APCI3120 have the new Quartz or if it - * is an APCI3001 and calculate the time value to set in the timer - */ + /* + * EL250804: Testing if board APCI3120 have the new Quartz or if it + * is an APCI3001 and calculate the time value to set in the timer + */ if ((us_TmpValue & 0x00B0) == 0x00B0 || !strcmp(this_board->pc_DriverName, "apci3001")) { /* Calculate the time value to set in the timer */ @@ -1775,11 +1659,6 @@ static int apci3120_config_insn_timer(struct comedi_device *dev, outb(devpriv->b_ModeSelectRegister, devpriv->iobase + APCI3120_WRITE_MODE_SELECT); if (data[0] == APCI3120_TIMER) { /* initialize timer */ - /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | - * APCI3120_ENABLE_TIMER_INT; */ - - /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */ - /* Set the Timer 2 in mode 2(Timer) */ devpriv->b_TimerSelectMode = (devpriv-> @@ -1787,13 +1666,13 @@ static int apci3120_config_insn_timer(struct comedi_device *dev, outb(devpriv->b_TimerSelectMode, devpriv->iobase + APCI3120_TIMER_CRT1); -/* - * Configure the timer 2 for writing the LOW unsigned short of timer - * is Delay value You must make a b_tmp variable with - * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 - * you can set the digital output and configure the timer 2,and if - * you don't make this, digital output are erase (Set to 0) - */ + /* + * Configure the timer 2 for writing the LOW unsigned short of timer + * is Delay value You must make a b_tmp variable with + * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 + * you can set the digital output and configure the timer 2,and if + * you don't make this, digital output are erase (Set to 0) + */ /* Writing LOW unsigned short */ b_Tmp = ((devpriv-> @@ -1816,20 +1695,19 @@ static int apci3120_config_insn_timer(struct comedi_device *dev, } else { /* Initialize Watch dog */ /* Set the Timer 2 in mode 5(Watchdog) */ - devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5; outb(devpriv->b_TimerSelectMode, devpriv->iobase + APCI3120_TIMER_CRT1); -/* - * Configure the timer 2 for writing the LOW unsigned short of timer - * is Delay value You must make a b_tmp variable with - * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 - * you can set the digital output and configure the timer 2,and if - * you don't make this, digital output are erase (Set to 0) - */ + /* + * Configure the timer 2 for writing the LOW unsigned short of timer + * is Delay value You must make a b_tmp variable with + * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 + * you can set the digital output and configure the timer 2,and if + * you don't make this, digital output are erase (Set to 0) + */ /* Writing LOW unsigned short */ b_Tmp = ((devpriv-> @@ -1873,7 +1751,7 @@ static int apci3120_write_insn_timer(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; struct addi_private *devpriv = dev->private; unsigned int ui_Timervalue2 = 0; unsigned short us_TmpValue; @@ -1898,8 +1776,6 @@ static int apci3120_write_insn_timer(struct comedi_device *dev, ui_Timervalue2 = 0; } - /* this_board->timer_write(dev,data[0],ui_Timervalue2); */ - switch (data[0]) { case APCI3120_START: @@ -1937,7 +1813,7 @@ static int apci3120_write_insn_timer(struct comedi_device *dev, devpriv->iobase + APCI3120_WRITE_MODE_SELECT); if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */ - /* For Timer mode is Gate2 must be activated **timer started */ + /* For Timer mode is Gate2 must be activated timer started */ devpriv->us_OutputRegister = devpriv-> us_OutputRegister | APCI3120_ENABLE_TIMER2; @@ -1979,9 +1855,6 @@ static int apci3120_write_insn_timer(struct comedi_device *dev, /* Reset FC_TIMER BIT */ inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); - /* Disable timer */ - /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */ - break; case 2: /* write new value to Timer */ @@ -1990,14 +1863,13 @@ static int apci3120_write_insn_timer(struct comedi_device *dev, "timer2 not configured in TIMER MODE\n"); return -EINVAL; } - /* ui_Timervalue2=data[1]; // passed as argument */ us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); -/* - * EL250804: Testing if board APCI3120 have the new Quartz or if it - * is an APCI3001 and calculate the time value to set in the timer - */ + /* + * EL250804: Testing if board APCI3120 have the new Quartz or if it + * is an APCI3001 and calculate the time value to set in the timer + */ if ((us_TmpValue & 0x00B0) == 0x00B0 || !strcmp(this_board->pc_DriverName, "apci3001")) { /* Calculate the time value to set in the timer */ @@ -2053,8 +1925,6 @@ static int apci3120_read_insn_timer(struct comedi_device *dev, && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { dev_err(dev->class_dev, "timer2 not configured\n"); } - - /* this_board->timer_read(dev,data); */ if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* Read the LOW unsigned short of Timer 2 register */ @@ -2137,7 +2007,6 @@ static int apci3120_ao_insn_write(struct comedi_device *dev, ui_Range = CR_RANGE(insn->chanspec); ui_Channel = CR_CHAN(insn->chanspec); - /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */ if (ui_Range) { /* if 1 then unipolar */ if (data[0] != 0) @@ -2163,17 +2032,17 @@ static int apci3120_ao_insn_write(struct comedi_device *dev, } while (us_TmpValue != 0x0001); if (ui_Channel <= 3) -/* - * for channel 0-3 out at the register 1 (wrDac1-8) data[i] - * typecasted to ushort since word write is to be done - */ + /* + * for channel 0-3 out at the register 1 (wrDac1-8) data[i] + * typecasted to ushort since word write is to be done + */ outw((unsigned short) data[0], devpriv->iobase + APCI3120_ANALOG_OUTPUT_1); else -/* - * for channel 4-7 out at the register 2 (wrDac5-8) data[i] - * typecasted to ushort since word write is to be done - */ + /* + * for channel 4-7 out at the register 2 (wrDac5-8) data[i] + * typecasted to ushort since word write is to be done + */ outw((unsigned short) data[0], devpriv->iobase + APCI3120_ANALOG_OUTPUT_2); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index e82c3fcd048b..339519a3d6b5 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -168,7 +168,7 @@ static int apci3501_read_insn_timer(struct comedi_device *dev, else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)) { - printk("\nIn ReadTimerCounterWatchdog :: Invalid Subdevice \n"); + dev_err(dev->class_dev, "Invalid subdevice.\n"); } return insn->n; } diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 1b2e7c040c9f..840cb289507a 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -190,9 +190,6 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); @@ -204,10 +201,9 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: ignored */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } @@ -347,9 +343,7 @@ static void apci1032_detach(struct comedi_device *dev) { if (dev->iobase) apci1032_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver apci1032_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index e9c5291c77cd..55d00fd94c91 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -102,7 +102,7 @@ static int apci1516_do_insn_bits(struct comedi_device *dev, static int apci1516_reset(struct comedi_device *dev) { - const struct apci1516_boardinfo *this_board = comedi_board(dev); + const struct apci1516_boardinfo *this_board = dev->board_ptr; struct apci1516_private *devpriv = dev->private; if (!this_board->has_wdog) @@ -190,7 +190,7 @@ static void apci1516_detach(struct comedi_device *dev) { if (dev->iobase) apci1516_reset(dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver apci1516_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 543cb074213a..688b015a834e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -1,3 +1,26 @@ +/* + * addi_apci_1564.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + #include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -42,10 +65,10 @@ static int apci1564_reset(struct comedi_device *dev) outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_RELOAD_REG); /* Reset the counter registers */ - outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); - outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); - outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); - outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); + outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER1)); + outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER2)); + outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER3)); + outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER4)); return 0; } @@ -94,17 +117,20 @@ static irqreturn_t apci1564_interrupt(int irq, void *d) } for (chan = 0; chan < 4; chan++) { - status = inl(dev->iobase + APCI1564_TCW_IRQ_REG(chan)); + status = inl(dev->iobase + APCI1564_COUNTER_IRQ_REG(chan)); if (status & 0x01) { /* Disable Counter Interrupt */ - ctrl = inl(dev->iobase + APCI1564_TCW_CTRL_REG(chan)); - outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(chan)); + ctrl = inl(dev->iobase + + APCI1564_COUNTER_CTRL_REG(chan)); + outl(0x0, dev->iobase + + APCI1564_COUNTER_CTRL_REG(chan)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_current, 0); /* Enable Counter Interrupt */ - outl(ctrl, dev->iobase + APCI1564_TCW_CTRL_REG(chan)); + outl(ctrl, dev->iobase + + APCI1564_COUNTER_CTRL_REG(chan)); } } @@ -282,9 +308,6 @@ static int apci1564_cos_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); @@ -296,10 +319,9 @@ static int apci1564_cos_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: ignored */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } @@ -374,53 +396,52 @@ static int apci1564_auto_attach(struct comedi_device *dev, /* Allocate and Initialise DI Subdevice Structures */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = apci1564_di_insn_bits; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci1564_di_insn_bits; /* Allocate and Initialise DO Subdevice Structures */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = apci1564_do_config; - s->insn_bits = apci1564_do_insn_bits; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci1564_do_insn_bits; /* Change-Of-State (COS) interrupt subdevice */ s = &dev->subdevices[2]; if (dev->irq) { dev->read_subdev = s; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->maxdata = 1; - s->range_table = &range_digital; - s->len_chanlist = 1; - s->insn_config = apci1564_cos_insn_config; - s->insn_bits = apci1564_cos_insn_bits; - s->do_cmdtest = apci1564_cos_cmdtest; - s->do_cmd = apci1564_cos_cmd; - s->cancel = apci1564_cos_cancel; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->len_chanlist = 1; + s->insn_config = apci1564_cos_insn_config; + s->insn_bits = apci1564_cos_insn_bits; + s->do_cmdtest = apci1564_cos_cmdtest; + s->do_cmd = apci1564_cos_cmd; + s->cancel = apci1564_cos_cancel; } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } /* Allocate and Initialise Timer Subdevice Structures */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; - s->range_table = &range_digital; - s->insn_write = apci1564_timer_write; - s->insn_read = apci1564_timer_read; - s->insn_config = apci1564_timer_config; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_write = apci1564_timer_write; + s->insn_read = apci1564_timer_read; + s->insn_config = apci1564_timer_config; /* Initialize the watchdog subdevice */ s = &dev->subdevices[4]; @@ -430,12 +451,12 @@ static int apci1564_auto_attach(struct comedi_device *dev, /* Initialize the diagnostic status subdevice */ s = &dev->subdevices[5]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 2; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = apci1564_diag_insn_bits; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 2; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci1564_diag_insn_bits; return 0; } @@ -444,9 +465,7 @@ static void apci1564_detach(struct comedi_device *dev) { if (dev->iobase) apci1564_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver apci1564_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index 28df4b50b87a..4162e2dc2860 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -159,7 +159,7 @@ static struct comedi_driver apci16xx_driver = { .driver_name = "addi_apci_16xx", .module = THIS_MODULE, .auto_attach = apci16xx_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int apci16xx_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index be0a8a7bd3b2..aea3da325359 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -86,30 +86,6 @@ static void apci2032_int_stop(struct comedi_device *dev, outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); } -static bool apci2032_int_start(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned char enabled_isns) -{ - struct apci2032_int_private *subpriv = s->private; - struct comedi_cmd *cmd = &s->async->cmd; - bool do_event; - - subpriv->enabled_isns = enabled_isns; - subpriv->stop_count = cmd->stop_arg; - if (cmd->stop_src == TRIG_COUNT && subpriv->stop_count == 0) { - /* An empty acquisition! */ - s->async->events |= COMEDI_CB_EOA; - subpriv->active = false; - do_event = true; - } else { - subpriv->active = true; - outl(enabled_isns, dev->iobase + APCI2032_INT_CTRL_REG); - do_event = false; - } - - return do_event; -} - static int apci2032_int_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -141,16 +117,17 @@ static int apci2032_int_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; - /* step 4: ignored */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } @@ -163,18 +140,19 @@ static int apci2032_int_cmd(struct comedi_device *dev, unsigned char enabled_isns; unsigned int n; unsigned long flags; - bool do_event; enabled_isns = 0; for (n = 0; n < cmd->chanlist_len; n++) enabled_isns |= 1 << CR_CHAN(cmd->chanlist[n]); spin_lock_irqsave(&subpriv->spinlock, flags); - do_event = apci2032_int_start(dev, s, enabled_isns); - spin_unlock_irqrestore(&subpriv->spinlock, flags); - if (do_event) - comedi_event(dev, s); + subpriv->enabled_isns = enabled_isns; + subpriv->stop_count = cmd->stop_arg; + subpriv->active = true; + outl(enabled_isns, dev->iobase + APCI2032_INT_CTRL_REG); + + spin_unlock_irqrestore(&subpriv->spinlock, flags); return 0; } @@ -339,11 +317,9 @@ static void apci2032_detach(struct comedi_device *dev) { if (dev->iobase) apci2032_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); + comedi_pci_detach(dev); if (dev->read_subdev) kfree(dev->read_subdev->private); - comedi_pci_disable(dev); } static struct comedi_driver apci2032_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index e1a916546d18..51ab1f937bae 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -118,7 +118,7 @@ static void apci2200_detach(struct comedi_device *dev) { if (dev->iobase) apci2200_reset(dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver apci2200_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 0b77f1012d47..ba71e24a56fd 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -44,7 +44,7 @@ static const struct addi_board apci3120_boardtypes[] = { static irqreturn_t v_ADDI_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - const struct addi_board *this_board = comedi_board(dev); + const struct addi_board *this_board = dev->board_ptr; this_board->interrupt(irq, d); return IRQ_RETVAL(1); @@ -57,7 +57,7 @@ static int apci3120_auto_attach(struct comedi_device *dev, const struct addi_board *this_board = NULL; struct addi_private *devpriv; struct comedi_subdevice *s; - int ret, pages, i; + int ret, order, i; if (context < ARRAY_SIZE(apci3120_boardtypes)) this_board = &apci3120_boardtypes[context]; @@ -88,28 +88,23 @@ static int apci3120_auto_attach(struct comedi_device *dev, dev->irq = pcidev->irq; } - devpriv->us_UseDma = 1; - /* Allocate DMA buffers */ - devpriv->b_DmaDoubleBuffer = 0; for (i = 0; i < 2; i++) { - for (pages = 4; pages >= 0; pages--) { + for (order = 2; order >= 0; order--) { devpriv->ul_DmaBufferVirtual[i] = - (void *) __get_free_pages(GFP_KERNEL, pages); + dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order, + &devpriv->ul_DmaBufferHw[i], + GFP_KERNEL); if (devpriv->ul_DmaBufferVirtual[i]) break; } - if (devpriv->ul_DmaBufferVirtual[i]) { - devpriv->ui_DmaBufferPages[i] = pages; - devpriv->ui_DmaBufferSize[i] = PAGE_SIZE * pages; - devpriv->ul_DmaBufferHw[i] = - virt_to_bus((void *)devpriv-> - ul_DmaBufferVirtual[i]); - } + if (!devpriv->ul_DmaBufferVirtual[i]) + break; + devpriv->ui_DmaBufferSize[i] = PAGE_SIZE << order; } - if (!devpriv->ul_DmaBufferVirtual[0]) - devpriv->us_UseDma = 0; + if (devpriv->ul_DmaBufferVirtual[0]) + devpriv->us_UseDma = 1; if (devpriv->ul_DmaBufferVirtual[1]) devpriv->b_DmaDoubleBuffer = 1; @@ -195,23 +190,22 @@ static void apci3120_detach(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; + if (dev->iobase) + apci3120_reset(dev); + comedi_pci_detach(dev); if (devpriv) { - if (dev->iobase) - apci3120_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv->ul_DmaBufferVirtual[0]) { - free_pages((unsigned long)devpriv-> - ul_DmaBufferVirtual[0], - devpriv->ui_DmaBufferPages[0]); - } - if (devpriv->ul_DmaBufferVirtual[1]) { - free_pages((unsigned long)devpriv-> - ul_DmaBufferVirtual[1], - devpriv->ui_DmaBufferPages[1]); + unsigned int i; + + for (i = 0; i < 2; i++) { + if (devpriv->ul_DmaBufferVirtual[i]) { + dma_free_coherent(dev->hw_dev, + devpriv->ui_DmaBufferSize[i], + devpriv-> + ul_DmaBufferVirtual[i], + devpriv->ul_DmaBufferHw[i]); + } } } - comedi_pci_disable(dev); } static struct comedi_driver apci3120_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index d9594f48d00f..010efa3fed6c 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -104,9 +104,9 @@ static int apci3501_ao_insn_write(struct comedi_device *dev, { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val = 0; - int i; + unsigned int cfg = APCI3501_AO_DATA_CHAN(chan); int ret; + int i; /* * All analog output channels have the same output range. @@ -117,14 +117,14 @@ static int apci3501_ao_insn_write(struct comedi_device *dev, if (range) { outl(0, dev->iobase + APCI3501_AO_CTRL_STATUS_REG); } else { - val |= APCI3501_AO_DATA_BIPOLAR; + cfg |= APCI3501_AO_DATA_BIPOLAR; outl(APCI3501_AO_CTRL_BIPOLAR, dev->iobase + APCI3501_AO_CTRL_STATUS_REG); } - val |= APCI3501_AO_DATA_CHAN(chan); - for (i = 0; i < insn->n; i++) { + unsigned int val = data[i]; + if (range == 1) { if (data[i] > 0x1fff) { dev_err(dev->class_dev, @@ -137,8 +137,10 @@ static int apci3501_ao_insn_write(struct comedi_device *dev, if (ret) return ret; - outl(val | APCI3501_AO_DATA_VAL(data[i]), + outl(cfg | APCI3501_AO_DATA_VAL(val), dev->iobase + APCI3501_AO_DATA_REG); + + s->readback[chan] = val; } return insn->n; @@ -360,6 +362,11 @@ static int apci3501_auto_attach(struct comedi_device *dev, s->maxdata = 0x3fff; s->range_table = &apci3501_ao_range; s->insn_write = apci3501_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -410,9 +417,7 @@ static void apci3501_detach(struct comedi_device *dev) { if (dev->iobase) apci3501_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver apci3501_driver = { diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index 0f0c7fa5daa3..a296bd5b2c0c 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -472,7 +472,7 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev, static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev, unsigned int *ns, unsigned int flags) { - const struct apci3xxx_boardinfo *board = comedi_board(dev); + const struct apci3xxx_boardinfo *board = dev->board_ptr; struct apci3xxx_private *devpriv = dev->private; unsigned int base; unsigned int timer; @@ -496,15 +496,15 @@ static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev, break; } - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: timer = (*ns + base / 2) / base; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: timer = *ns / base; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: timer = (*ns + base - 1) / base; break; } @@ -523,7 +523,7 @@ static int apci3xxx_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct apci3xxx_boardinfo *board = comedi_board(dev); + const struct apci3xxx_boardinfo *board = dev->board_ptr; int err = 0; unsigned int arg; @@ -628,16 +628,20 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, int i; for (i = 0; i < insn->n; i++) { + unsigned int val = data[i]; + /* Set the range selection */ writel(range, dev->mmio + 96); /* Write the analog value to the selected channel */ - writel((data[i] << 8) | chan, dev->mmio + 100); + writel((val << 8) | chan, dev->mmio + 100); /* Wait the end of transfer */ ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0); if (ret) return ret; + + s->readback[chan] = val; } return insn->n; @@ -850,6 +854,11 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table = &apci3xxx_ao_range; s->insn_write = apci3xxx_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; subdev++; } @@ -901,17 +910,9 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, static void apci3xxx_detach(struct comedi_device *dev) { - struct apci3xxx_private *devpriv = dev->private; - - if (devpriv) { - if (dev->iobase) - apci3xxx_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->mmio) - iounmap(dev->mmio); - } - comedi_pci_disable(dev); + if (dev->iobase) + apci3xxx_reset(dev); + comedi_pci_detach(dev); } static struct comedi_driver apci3xxx_driver = { diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 921f6942dfce..0ad46fe492c9 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -46,8 +46,6 @@ #define PCI6208_DIO_DI_MASK (0xf0) #define PCI6208_DIO_DI_SHIFT (4) -#define PCI6208_MAX_AO_CHANNELS 16 - enum pci6208_boardid { BOARD_PCI6208, BOARD_PCI6216, @@ -69,10 +67,6 @@ static const struct pci6208_board pci6208_boards[] = { }, }; -struct pci6208_private { - unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS]; -}; - static int pci6208_ao_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -91,9 +85,8 @@ static int pci6208_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct pci6208_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val = devpriv->ao_readback[chan]; + unsigned int val = s->readback[chan]; int ret; int i; @@ -108,23 +101,9 @@ static int pci6208_ao_insn_write(struct comedi_device *dev, /* the hardware expects two's complement values */ outw(comedi_offset_munge(s, val), dev->iobase + PCI6208_AO_CONTROL(chan)); - } - devpriv->ao_readback[chan] = val; - - return insn->n; -} -static int pci6208_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct pci6208_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + s->readback[chan] = val; + } return insn->n; } @@ -162,7 +141,6 @@ static int pci6208_auto_attach(struct comedi_device *dev, { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct pci6208_board *boardinfo = NULL; - struct pci6208_private *devpriv; struct comedi_subdevice *s; unsigned int val; int ret; @@ -174,10 +152,6 @@ static int pci6208_auto_attach(struct comedi_device *dev, dev->board_ptr = boardinfo; dev->board_name = boardinfo->name; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_pci_enable(dev); if (ret) return ret; @@ -195,7 +169,11 @@ static int pci6208_auto_attach(struct comedi_device *dev, s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = pci6208_ao_insn_write; - s->insn_read = pci6208_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[1]; /* digital input subdevice */ @@ -230,7 +208,7 @@ static struct comedi_driver adl_pci6208_driver = { .driver_name = "adl_pci6208", .module = THIS_MODULE, .auto_attach = pci6208_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int adl_pci6208_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index 5e3cc77a8a0c..fb8e5f582496 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -246,7 +246,7 @@ static struct comedi_driver adl_pci7x3x_driver = { .driver_name = "adl_pci7x3x", .module = THIS_MODULE, .auto_attach = adl_pci7x3x_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int adl_pci7x3x_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index 300df55a2802..72bccb447a74 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -135,7 +135,7 @@ static struct comedi_driver adl_pci8164_driver = { .driver_name = "adl_pci8164", .module = THIS_MODULE, .auto_attach = adl_pci8164_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int adl_pci8164_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index 51edfebb952a..d18d8f21af23 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -139,8 +139,6 @@ struct pci9111_private_data { unsigned int chunk_counter; unsigned int chunk_num_samples; - int ao_readback; - unsigned int div1; unsigned int div2; @@ -643,29 +641,15 @@ static int pci9111_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct pci9111_private_data *dev_private = dev->private; - unsigned int val = 0; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; int i; for (i = 0; i < insn->n; i++) { val = data[i]; outw(val, dev->iobase + PCI9111_AO_REG); } - dev_private->ao_readback = val; - - return insn->n; -} - -static int pci9111_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct pci9111_private_data *dev_private = dev->private; - int i; - - for (i = 0; i < insn->n; i++) - data[i] = dev_private->ao_readback; + s->readback[chan] = val; return insn->n; } @@ -768,7 +752,11 @@ static int pci9111_auto_attach(struct comedi_device *dev, s->len_chanlist = 1; s->range_table = &range_bipolar10; s->insn_write = pci9111_ao_insn_write; - s->insn_read = pci9111_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; @@ -793,9 +781,7 @@ static void pci9111_detach(struct comedi_device *dev) { if (dev->iobase) pci9111_reset(dev); - if (dev->irq != 0) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver adl_pci9111_driver = { diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index f30b84e1987b..e18fd9569a2b 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -36,8 +36,8 @@ * b) DMA transfers must have the length aligned to two samples (32 bit), * so there is some problems if cmd->chanlist_len is odd. This driver tries * bypass this with adding one sample to the end of the every scan and discard - * it on output but this cann't be used if cmd->scan_begin_src=TRIG_FOLLOW - * and is used flag TRIG_WAKE_EOS, then driver switch to interrupt driven mode + * it on output but this can't be used if cmd->scan_begin_src=TRIG_FOLLOW + * and is used flag CMDF_WAKE_EOS, then driver switch to interrupt driven mode * with interrupt after every sample. * c) If isn't used DMA then you can use only mode where * cmd->scan_begin_src=TRIG_FOLLOW. @@ -49,19 +49,13 @@ * card will be used. * [2] - 0= standard 8 DIFF/16 SE channels configuration * n = external multiplexer connected, 1 <= n <= 256 - * [3] - 0=autoselect DMA or EOC interrupts operation - * 1 = disable DMA mode - * 3 = disable DMA and INT, only insn interface will work + * [3] - ignored * [4] - sample&hold signal - card can generate signal for external S&H board * 0 = use SSHO(pin 45) signal is generated in onboard hardware S&H logic * 0 != use ADCHN7(pin 23) signal is generated from driver, number say how * long delay is requested in ns and sign polarity of the hold * (in this case external multiplexor can serve only 128 channels) - * [5] - 0=stop measure on all hardware errors - * 2 | = ignore ADOR - A/D Overrun status - * 8|=ignore Bover - A/D Burst Mode Overrun status - * 256|=ignore nFull - A/D FIFO Full status - * + * [5] - ignored */ /* @@ -91,111 +85,68 @@ #include "8253.h" #include "comedi_fc.h" -/* paranoid checks are broken */ -#undef PCI9118_PARANOIDCHECK /* - * if defined, then is used code which control - * correct channel number on every 12 bit sample - */ - #define IORANGE_9118 64 /* I hope */ #define PCI9118_CHANLEN 255 /* * len of chanlist, some source say 256, * but reality looks like 255 :-( */ -#define PCI9118_CNT0 0x00 /* R/W: 8254 counter 0 */ -#define PCI9118_CNT1 0x04 /* R/W: 8254 counter 0 */ -#define PCI9118_CNT2 0x08 /* R/W: 8254 counter 0 */ -#define PCI9118_CNTCTRL 0x0c /* W: 8254 counter control */ -#define PCI9118_AD_DATA 0x10 /* R: A/D data */ -#define PCI9118_DA1 0x10 /* W: D/A registers */ -#define PCI9118_DA2 0x14 -#define PCI9118_ADSTAT 0x18 /* R: A/D status register */ -#define PCI9118_ADCNTRL 0x18 /* W: A/D control register */ -#define PCI9118_DI 0x1c /* R: digi input register */ -#define PCI9118_DO 0x1c /* W: digi output register */ -#define PCI9118_SOFTTRG 0x20 /* W: soft trigger for A/D */ -#define PCI9118_GAIN 0x24 /* W: A/D gain/channel register */ -#define PCI9118_BURST 0x28 /* W: A/D burst number register */ -#define PCI9118_SCANMOD 0x2c /* W: A/D auto scan mode */ -#define PCI9118_ADFUNC 0x30 /* W: A/D function register */ -#define PCI9118_DELFIFO 0x34 /* W: A/D data FIFO reset */ -#define PCI9118_INTSRC 0x38 /* R: interrupt reason register */ -#define PCI9118_INTCTRL 0x38 /* W: interrupt control register */ - -/* bits from A/D control register (PCI9118_ADCNTRL) */ -#define AdControl_UniP 0x80 /* 1=bipolar, 0=unipolar */ -#define AdControl_Diff 0x40 /* 1=differential, 0= single end inputs */ -#define AdControl_SoftG 0x20 /* 1=8254 counter works, 0=counter stops */ -#define AdControl_ExtG 0x10 /* - * 1=8254 countrol controlled by TGIN(pin 46), - * 0=controlled by SoftG - */ -#define AdControl_ExtM 0x08 /* - * 1=external hardware trigger (pin 44), - * 0=internal trigger - */ -#define AdControl_TmrTr 0x04 /* - * 1=8254 is iternal trigger source, - * 0=software trigger is source - * (register PCI9118_SOFTTRG) - */ -#define AdControl_Int 0x02 /* 1=enable INT, 0=disable */ -#define AdControl_Dma 0x01 /* 1=enable DMA, 0=disable */ - -/* bits from A/D function register (PCI9118_ADFUNC) */ -#define AdFunction_PDTrg 0x80 /* - * 1=positive, - * 0=negative digital trigger - * (only positive is correct) - */ -#define AdFunction_PETrg 0x40 /* - * 1=positive, - * 0=negative external trigger - * (only positive is correct) - */ -#define AdFunction_BSSH 0x20 /* 1=with sample&hold, 0=without */ -#define AdFunction_BM 0x10 /* 1=burst mode, 0=normal mode */ -#define AdFunction_BS 0x08 /* - * 1=burst mode start, - * 0=burst mode stop - */ -#define AdFunction_PM 0x04 /* - * 1=post trigger mode, - * 0=not post trigger - */ -#define AdFunction_AM 0x02 /* - * 1=about trigger mode, - * 0=not about trigger - */ -#define AdFunction_Start 0x01 /* 1=trigger start, 0=trigger stop */ - -/* bits from A/D status register (PCI9118_ADSTAT) */ -#define AdStatus_nFull 0x100 /* 0=FIFO full (fatal), 1=not full */ -#define AdStatus_nHfull 0x080 /* 0=FIFO half full, 1=FIFO not half full */ -#define AdStatus_nEpty 0x040 /* 0=FIFO empty, 1=FIFO not empty */ -#define AdStatus_Acmp 0x020 /* */ -#define AdStatus_DTH 0x010 /* 1=external digital trigger */ -#define AdStatus_Bover 0x008 /* 1=burst mode overrun (fatal) */ -#define AdStatus_ADOS 0x004 /* 1=A/D over speed (warning) */ -#define AdStatus_ADOR 0x002 /* 1=A/D overrun (fatal) */ -#define AdStatus_ADrdy 0x001 /* 1=A/D already ready, 0=not ready */ - -/* bits for interrupt reason and control (PCI9118_INTSRC, PCI9118_INTCTRL) */ -/* 1=interrupt occur, enable source, 0=interrupt not occur, disable source */ -#define Int_Timer 0x08 /* timer interrupt */ -#define Int_About 0x04 /* about trigger complete */ -#define Int_Hfull 0x02 /* A/D FIFO hlaf full */ -#define Int_DTrg 0x01 /* external digital trigger */ +/* + * PCI BAR2 Register map (dev->iobase) + */ +#define PCI9118_TIMER_REG(x) (0x00 + ((x) * 4)) +#define PCI9118_TIMER_CTRL_REG 0x0c +#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_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_DIO_REG 0x1c +#define PCI9118_SOFTTRG_REG 0x20 +#define PCI9118_AI_CHANLIST_REG 0x24 +#define PCI9118_AI_CHANLIST_RANGE(x) (((x) & 0x3) << 8) +#define PCI9118_AI_CHANLIST_CHAN(x) ((x) << 0) +#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_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 START_AI_EXT 0x01 /* start measure on external trigger */ #define STOP_AI_EXT 0x02 /* stop measure on external trigger */ -#define START_AI_INT 0x04 /* start measure on internal trigger */ #define STOP_AI_INT 0x08 /* stop measure on internal trigger */ -#define EXTTRG_AI 0 /* ext trg is used by AI */ +#define PCI9118_HALF_FIFO_SZ (1024 / 2) -static const struct comedi_lrange range_pci9118dg_hr = { +static const struct comedi_lrange pci9118_ai_range = { 8, { BIP_RANGE(5), BIP_RANGE(2.5), @@ -208,7 +159,7 @@ static const struct comedi_lrange range_pci9118dg_hr = { } }; -static const struct comedi_lrange range_pci9118hg = { +static const struct comedi_lrange pci9118hg_ai_range = { 8, { BIP_RANGE(5), BIP_RANGE(0.5), @@ -226,102 +177,49 @@ static const struct comedi_lrange range_pci9118hg = { * of BIP/UNI ranges */ -struct boardtype { - const char *name; /* board name */ - int device_id; /* PCI device ID of card */ - int iorange_amcc; /* iorange for own S5933 region */ - int iorange_9118; /* pass thru card region size */ - int n_aichan; /* num of A/D chans */ - int n_aichand; /* num of A/D chans in diff mode */ - int mux_aichan; /* - * num of A/D chans with - * external multiplexor - */ - int n_aichanlist; /* len of chanlist */ - int n_aochan; /* num of D/A chans */ - int ai_maxdata; /* resolution of A/D */ - int ao_maxdata; /* resolution of D/A */ - const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ - unsigned int ai_ns_min; /* max sample speed of card v ns */ - unsigned int ai_pacer_min; /* - * minimal pacer value - * (c1*c2 or c1 in burst) - */ - int half_fifo_size; /* size of FIFO/2 */ +enum pci9118_boardid { + BOARD_PCI9118DG, + BOARD_PCI9118HG, + BOARD_PCI9118HR, +}; +struct pci9118_boardinfo { + const char *name; + unsigned int ai_is_16bit:1; + unsigned int is_hg:1; }; -static const struct boardtype boardtypes[] = { - { +static const struct pci9118_boardinfo pci9118_boards[] = { + [BOARD_PCI9118DG] = { .name = "pci9118dg", - .device_id = 0x80d9, - .iorange_amcc = AMCC_OP_REG_SIZE, - .iorange_9118 = IORANGE_9118, - .n_aichan = 16, - .n_aichand = 8, - .mux_aichan = 256, - .n_aichanlist = PCI9118_CHANLEN, - .n_aochan = 2, - .ai_maxdata = 0x0fff, - .ao_maxdata = 0x0fff, - .rangelist_ai = &range_pci9118dg_hr, - .rangelist_ao = &range_bipolar10, - .ai_ns_min = 3000, - .ai_pacer_min = 12, - .half_fifo_size = 512, - }, { + }, + [BOARD_PCI9118HG] = { .name = "pci9118hg", - .device_id = 0x80d9, - .iorange_amcc = AMCC_OP_REG_SIZE, - .iorange_9118 = IORANGE_9118, - .n_aichan = 16, - .n_aichand = 8, - .mux_aichan = 256, - .n_aichanlist = PCI9118_CHANLEN, - .n_aochan = 2, - .ai_maxdata = 0x0fff, - .ao_maxdata = 0x0fff, - .rangelist_ai = &range_pci9118hg, - .rangelist_ao = &range_bipolar10, - .ai_ns_min = 3000, - .ai_pacer_min = 12, - .half_fifo_size = 512, - }, { + .is_hg = 1, + }, + [BOARD_PCI9118HR] = { .name = "pci9118hr", - .device_id = 0x80d9, - .iorange_amcc = AMCC_OP_REG_SIZE, - .iorange_9118 = IORANGE_9118, - .n_aichan = 16, - .n_aichand = 8, - .mux_aichan = 256, - .n_aichanlist = PCI9118_CHANLEN, - .n_aochan = 2, - .ai_maxdata = 0xffff, - .ao_maxdata = 0x0fff, - .rangelist_ai = &range_pci9118dg_hr, - .rangelist_ao = &range_bipolar10, - .ai_ns_min = 10000, - .ai_pacer_min = 40, - .half_fifo_size = 512, + .ai_is_16bit = 1, }, }; +struct pci9118_dmabuf { + unsigned short *virt; /* virtual address of buffer */ + dma_addr_t hw; /* hardware (bus) address of buffer */ + unsigned int size; /* size of dma buffer in bytes */ + unsigned int use_size; /* which size we may now use for transfer */ +}; + struct pci9118_private { unsigned long iobase_a; /* base+size for AMCC chip */ - unsigned int master; /* master capable */ - unsigned int usemux; /* we want to use external multiplexor! */ -#ifdef PCI9118_PARANOIDCHECK - unsigned short chanlist[PCI9118_CHANLEN + 1]; /* - * list of - * scanned channel - */ - unsigned char chanlistlen; /* number of scanlist */ -#endif - unsigned char AdControlReg; /* A/D control register */ - unsigned char IntControlReg; /* Interrupt control register */ - unsigned char AdFunctionReg; /* A/D function register */ - char ai_neverending; /* we do unlimited AI */ + unsigned int master:1; + unsigned int dma_doublebuf:1; + unsigned int ai_neverending:1; + unsigned int usedma:1; + unsigned int usemux:1; + unsigned char ai_ctrl; + unsigned char int_ctrl; + unsigned char ai_cfg; unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ unsigned int ai_act_scan; /* how many scans we finished */ unsigned int ai_n_realscanlen; /* @@ -346,29 +244,8 @@ struct pci9118_private { * divisors for start of measure * on external start */ - unsigned short ao_data[2]; /* data output buffer */ - char dma_doublebuf; /* use double buffering */ unsigned int dma_actbuf; /* which buffer is used now */ - unsigned short *dmabuf_virt[2]; /* - * pointers to begin of - * DMA buffer - */ - unsigned long dmabuf_hw[2]; /* hw address of DMA buff */ - unsigned int dmabuf_size[2]; /* - * size of dma buffer in bytes - */ - unsigned int dmabuf_use_size[2]; /* - * which size we may now use - * for transfer - */ - unsigned int dmabuf_used_size[2]; /* which size was truly used */ - unsigned int dmabuf_panic_size[2]; - int dmabuf_pages[2]; /* number of pages in buffer */ - unsigned char exttrg_users; /* - * bit field of external trigger - * users(0-AI, 1-AO, 2-DI, 3-DO) - */ - unsigned char usedma; /* =1 use DMA transfer and not INT */ + struct pci9118_dmabuf dmabuf[2]; int softsshdelay; /* * >0 use software S&H, * numer is requested delay in ns @@ -381,15 +258,74 @@ struct pci9118_private { * polarity of S&H signal * in hold state */ - unsigned int ai_maskerr; /* which warning was printed */ - unsigned int ai_maskharderr; /* on which error bits stops */ + unsigned int ai_ns_min; }; +static void pci9118_amcc_setup_dma(struct comedi_device *dev, unsigned int buf) +{ + struct pci9118_private *devpriv = dev->private; + struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[buf]; + + /* set the master write address and transfer count */ + outl(dmabuf->hw, devpriv->iobase_a + AMCC_OP_REG_MWAR); + outl(dmabuf->use_size, devpriv->iobase_a + AMCC_OP_REG_MWTC); +} + +static void pci9118_amcc_dma_ena(struct comedi_device *dev, bool enable) +{ + struct pci9118_private *devpriv = dev->private; + unsigned int mcsr; + + mcsr = inl(devpriv->iobase_a + AMCC_OP_REG_MCSR); + if (enable) + mcsr |= RESET_A2P_FLAGS | A2P_HI_PRIORITY | EN_A2P_TRANSFERS; + else + mcsr &= ~EN_A2P_TRANSFERS; + outl(mcsr, devpriv->iobase_a + AMCC_OP_REG_MCSR); +} + +static void pci9118_amcc_int_ena(struct comedi_device *dev, bool enable) +{ + struct pci9118_private *devpriv = dev->private; + unsigned int intcsr; + + /* enable/disable interrupt for AMCC Incoming Mailbox 4 (32-bit) */ + intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); + if (enable) + intcsr |= 0x1f00; + else + intcsr &= ~0x1f00; + outl(intcsr, devpriv->iobase_a + AMCC_OP_REG_INTCSR); +} + +static void pci9118_timer_write(struct comedi_device *dev, + unsigned int timer, unsigned int val) +{ + outl(val & 0xff, dev->iobase + PCI9118_TIMER_REG(timer)); + outl((val >> 8) & 0xff, dev->iobase + PCI9118_TIMER_REG(timer)); +} + +static void pci9118_timer_set_mode(struct comedi_device *dev, + unsigned int timer, unsigned int mode) +{ + unsigned int val; + + val = timer << 6; /* select timer */ + val |= 0x30; /* load low then high byte */ + val |= mode; /* set timer mode and BCD|binary */ + outl(val, dev->iobase + PCI9118_TIMER_CTRL_REG); +} + +static void pci9118_ai_reset_fifo(struct comedi_device *dev) +{ + /* writing any value resets the A/D FIFO */ + 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) { - const struct boardtype *this_board = comedi_board(dev); struct pci9118_private *devpriv = dev->private; unsigned int i, differencial = 0, bipolar = 0; @@ -423,7 +359,7 @@ static int check_channel_list(struct comedi_device *dev, return 0; } if (!devpriv->usemux && differencial && - (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) { + (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; @@ -433,234 +369,82 @@ static int check_channel_list(struct comedi_device *dev, return 1; } -static int setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, int n_chan, - unsigned int *chanlist, int rot, int frontadd, - int backadd, int usedma) +static void pci9118_set_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + int n_chan, unsigned int *chanlist, + int frontadd, int backadd) { struct pci9118_private *devpriv = dev->private; - unsigned int i, differencial = 0, bipolar = 0; - unsigned int scanquad, gain, ssh = 0x00; - - if (usedma == 1) { - rot = 8; - usedma = 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 */ - - /* All is ok, so we can setup channel/range list */ - - if (!bipolar) { - devpriv->AdControlReg |= AdControl_UniP; - /* set unibipolar */ - } else { - devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff); - /* enable bipolar */ - } - - if (differencial) { - devpriv->AdControlReg |= AdControl_Diff; - /* enable diff inputs */ - } else { - devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff); - /* set single ended inputs */ - } - - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - /* setup mode */ + unsigned int chan0 = CR_CHAN(chanlist[0]); + unsigned int range0 = CR_RANGE(chanlist[0]); + unsigned int aref0 = CR_AREF(chanlist[0]); + unsigned int ssh = 0x00; + unsigned int val; + int i; - outl(2, dev->iobase + PCI9118_SCANMOD); - /* gods know why this sequence! */ - outl(0, dev->iobase + PCI9118_SCANMOD); - outl(1, dev->iobase + PCI9118_SCANMOD); - -#ifdef PCI9118_PARANOIDCHECK - devpriv->chanlistlen = n_chan; - for (i = 0; i < (PCI9118_CHANLEN + 1); i++) - devpriv->chanlist[i] = 0x55aa; -#endif - - if (frontadd) { /* insert channels for S&H */ + /* + * Configure analog input based on the first chanlist entry. + * All entries are either unipolar or bipolar and single-ended + * or differential. + */ + devpriv->ai_ctrl = 0; + if (comedi_range_is_unipolar(s, range0)) + devpriv->ai_ctrl |= PCI9118_AI_CTRL_UNIP; + if (aref0 == AREF_DIFF) + devpriv->ai_ctrl |= PCI9118_AI_CTRL_DIFF; + outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG); + + /* gods know why this sequence! */ + outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + + /* insert channels for S&H */ + if (frontadd) { + val = PCI9118_AI_CHANLIST_CHAN(chan0) | + PCI9118_AI_CHANLIST_RANGE(range0); ssh = devpriv->softsshsample; for (i = 0; i < frontadd; i++) { - /* store range list to card */ - scanquad = CR_CHAN(chanlist[0]); - /* get channel number; */ - gain = CR_RANGE(chanlist[0]); - /* get gain number */ - scanquad |= ((gain & 0x03) << 8); - outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); + outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG); ssh = devpriv->softsshhold; } } - for (i = 0; i < n_chan; i++) { /* store range list to card */ - scanquad = CR_CHAN(chanlist[i]); /* get channel number */ -#ifdef PCI9118_PARANOIDCHECK - devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot; -#endif - gain = CR_RANGE(chanlist[i]); /* get gain number */ - scanquad |= ((gain & 0x03) << 8); - outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); - } + /* store chanlist */ + for (i = 0; i < n_chan; i++) { + unsigned int chan = CR_CHAN(chanlist[i]); + unsigned int range = CR_RANGE(chanlist[i]); - if (backadd) { /* insert channels for fit onto 32bit DMA */ - for (i = 0; i < backadd; i++) { /* store range list to card */ - scanquad = CR_CHAN(chanlist[0]); - /* get channel number */ - gain = CR_RANGE(chanlist[0]); /* get gain number */ - scanquad |= ((gain & 0x03) << 8); - outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); - } + val = PCI9118_AI_CHANLIST_CHAN(chan) | + PCI9118_AI_CHANLIST_RANGE(range); + outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG); } -#ifdef PCI9118_PARANOIDCHECK - devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; - /* for 32bit operations */ -#endif - outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */ - /* udelay(100); important delay, or first sample will be crippled */ - - return 1; /* we can serve this with scan logic */ -} - -static int pci9118_ai_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned long context) -{ - unsigned int status; - - status = inl(dev->iobase + PCI9118_ADSTAT); - if (status & AdStatus_ADrdy) - return 0; - return -EBUSY; -} - -static int pci9118_insn_read_ai(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pci9118_private *devpriv = dev->private; - int ret; - int n; - - devpriv->AdControlReg = AdControl_Int & 0xff; - devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - /* - * positive triggers, no S&H, - * no burst, burst stop, - * no post trigger, - * no about trigger, - * trigger stop - */ - if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0)) - return -EINVAL; - - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - - for (n = 0; n < insn->n; n++) { - outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */ - udelay(2); - - ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0); - if (ret) { - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - return ret; - } - - if (s->maxdata == 0xffff) { - data[n] = - (inl(dev->iobase + - PCI9118_AD_DATA) & 0xffff) ^ 0x8000; - } else { - data[n] = - (inw(dev->iobase + PCI9118_AD_DATA) >> 4) & 0xfff; - } - } - - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - return n; - -} - -static int pci9118_insn_write_ao(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pci9118_private *devpriv = dev->private; - int n, chanreg, ch; - - ch = CR_CHAN(insn->chanspec); - if (ch) - chanreg = PCI9118_DA2; - else - chanreg = PCI9118_DA1; - - - for (n = 0; n < insn->n; n++) { - outl(data[n], dev->iobase + chanreg); - devpriv->ao_data[ch] = data[n]; + /* insert channels to fit onto 32bit DMA */ + if (backadd) { + val = PCI9118_AI_CHANLIST_CHAN(chan0) | + PCI9118_AI_CHANLIST_RANGE(range0); + for (i = 0; i < backadd; i++) + outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG); } - - return n; -} - -static int pci9118_insn_read_ao(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pci9118_private *devpriv = dev->private; - int n, chan; - - chan = CR_CHAN(insn->chanspec); - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_data[chan]; - - return n; -} - -static int pci9118_insn_bits_di(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[1] = inl(dev->iobase + PCI9118_DI) & 0xf; - - return insn->n; -} - -static int pci9118_insn_bits_do(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (comedi_dio_update_state(s, data)) - outl(s->state & 0x0f, dev->iobase + PCI9118_DO); - - data[1] = s->state; - - return insn->n; + /* close scan queue */ + outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + /* udelay(100); important delay, or first sample will be crippled */ } -static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev) +static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev, + unsigned int next_buf) { struct pci9118_private *devpriv = dev->private; - - devpriv->AdFunctionReg = - AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - outl(0x30, dev->iobase + PCI9118_CNTCTRL); - outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 1) & 0xff, - dev->iobase + PCI9118_CNT0); - outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 9) & 0xff, - dev->iobase + PCI9118_CNT0); - devpriv->AdFunctionReg |= AdFunction_Start; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); + struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[next_buf]; + + devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG | + PCI9118_AI_CFG_AM; + outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); + pci9118_timer_set_mode(dev, 0, I8254_MODE0); + pci9118_timer_write(dev, 0, dmabuf->hw >> 1); + devpriv->ai_cfg |= PCI9118_AI_CFG_START; + outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); } static unsigned int defragment_dma_buffer(struct comedi_device *dev, @@ -689,9 +473,9 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev, } static int move_block_from_dma(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned short *dma_buffer, - unsigned int num_samples) + struct comedi_subdevice *s, + unsigned short *dma_buffer, + unsigned int num_samples) { struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -710,100 +494,59 @@ static int move_block_from_dma(struct comedi_device *dev, return 0; } -static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source) +static void pci9118_exttrg_enable(struct comedi_device *dev, bool enable) { struct pci9118_private *devpriv = dev->private; - if (source > 3) - return -1; /* incorrect source */ - devpriv->exttrg_users |= (1 << source); - devpriv->IntControlReg |= Int_DTrg; - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* allow INT in AMCC */ - return 0; -} - -static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source) -{ - struct pci9118_private *devpriv = dev->private; + if (enable) + devpriv->int_ctrl |= PCI9118_INT_CTRL_DTRG; + else + devpriv->int_ctrl &= ~PCI9118_INT_CTRL_DTRG; + outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG); - if (source > 3) - return -1; /* incorrect source */ - devpriv->exttrg_users &= ~(1 << source); - if (!devpriv->exttrg_users) { /* shutdown ext trg intterrupts */ - devpriv->IntControlReg &= ~Int_DTrg; - if (!devpriv->IntControlReg) /* all IRQ disabled */ - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) & - (~0x00001f00), - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* disable int in AMCC */ - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - } - return 0; + if (devpriv->int_ctrl) + pci9118_amcc_int_ena(dev, true); + else + pci9118_amcc_int_ena(dev, false); } -static void pci9118_calc_divisors(char mode, struct comedi_device *dev, +static void pci9118_calc_divisors(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *tim1, unsigned int *tim2, unsigned int flags, int chans, unsigned int *div1, unsigned int *div2, unsigned int chnsshfront) { - const struct boardtype *this_board = comedi_board(dev); struct comedi_cmd *cmd = &s->async->cmd; - switch (mode) { - case 1: - case 4: - if (*tim2 < this_board->ai_ns_min) - *tim2 = this_board->ai_ns_min; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, - div1, div2, - tim2, flags & TRIG_ROUND_NEAREST); - break; - case 2: - if (*tim2 < this_board->ai_ns_min) - *tim2 = this_board->ai_ns_min; - *div1 = *tim2 / I8254_OSC_BASE_4MHZ; - /* convert timer (burst) */ - if (*div1 < this_board->ai_pacer_min) - *div1 = this_board->ai_pacer_min; - *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */ - *div2 = *div2 / *div1; /* major timer is c1*c2 */ - if (*div2 < chans) - *div2 = chans; - - *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */ - - if (cmd->convert_src == TRIG_NOW && !chnsshfront) { - /* use BSSH signal */ - if (*div2 < (chans + 2)) - *div2 = chans + 2; - } + *div1 = *tim2 / I8254_OSC_BASE_4MHZ; /* convert timer (burst) */ + *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */ + *div2 = *div2 / *div1; /* major timer is c1*c2 */ + if (*div2 < chans) + *div2 = chans; - *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ; - break; + *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */ + + if (cmd->convert_src == TRIG_NOW && !chnsshfront) { + /* use BSSH signal */ + if (*div2 < (chans + 2)) + *div2 = chans + 2; } + + *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ; } static void pci9118_start_pacer(struct comedi_device *dev, int mode) { struct pci9118_private *devpriv = dev->private; - unsigned int divisor1 = devpriv->ai_divisor1; - unsigned int divisor2 = devpriv->ai_divisor2; - outl(0x74, dev->iobase + PCI9118_CNTCTRL); - outl(0xb4, dev->iobase + PCI9118_CNTCTRL); -/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */ + pci9118_timer_set_mode(dev, 1, I8254_MODE2); + pci9118_timer_set_mode(dev, 2, I8254_MODE2); udelay(1); if ((mode == 1) || (mode == 2) || (mode == 4)) { - outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2); - outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2); - outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1); - outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1); + pci9118_timer_write(dev, 2, devpriv->ai_divisor2); + pci9118_timer_write(dev, 1, devpriv->ai_divisor1); } } @@ -813,29 +556,24 @@ static int pci9118_ai_cancel(struct comedi_device *dev, struct pci9118_private *devpriv = dev->private; if (devpriv->usedma) - outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & - (~EN_A2P_TRANSFERS), - devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */ - pci9118_exttrg_del(dev, EXTTRG_AI); + pci9118_amcc_dma_ena(dev, false); + pci9118_exttrg_enable(dev, false); pci9118_start_pacer(dev, 0); /* stop 8254 counters */ - devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - /* - * positive triggers, no S&H, no burst, - * burst stop, no post trigger, - * no about trigger, trigger stop - */ - devpriv->AdControlReg = 0x00; - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - /* - * bipolar, S.E., use 8254, stop 8354, - * internal trigger, soft trigger, - * disable INT and DMA - */ - outl(0, dev->iobase + PCI9118_BURST); - outl(1, dev->iobase + PCI9118_SCANMOD); - outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */ - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ + /* set default config (disable burst and triggers) */ + devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG; + outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); + /* reset acqusition control */ + devpriv->ai_ctrl = 0; + outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG); + outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG); + /* reset scan queue */ + outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + pci9118_ai_reset_fifo(dev); + + devpriv->int_ctrl = 0; + outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG); + pci9118_amcc_int_ena(dev, false); devpriv->ai_do = 0; devpriv->usedma = 0; @@ -847,44 +585,6 @@ static int pci9118_ai_cancel(struct comedi_device *dev, devpriv->ai_neverending = 0; devpriv->dma_actbuf = 0; - if (!devpriv->IntControlReg) - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* allow INT in AMCC */ - - return 0; -} - -static char pci9118_decode_error_status(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned char m) -{ - struct pci9118_private *devpriv = dev->private; - - if (m & 0x100) { - dev_err(dev->class_dev, - "A/D FIFO Full status (Fatal Error!)\n"); - devpriv->ai_maskerr &= ~0x100L; - } - if (m & 0x008) { - dev_err(dev->class_dev, - "A/D Burst Mode Overrun Status (Fatal Error!)\n"); - devpriv->ai_maskerr &= ~0x008L; - } - if (m & 0x004) { - dev_err(dev->class_dev, "A/D Over Speed Status (Warning!)\n"); - devpriv->ai_maskerr &= ~0x004L; - } - if (m & 0x002) { - dev_err(dev->class_dev, "A/D Overrun Status (Fatal Error!)\n"); - devpriv->ai_maskerr &= ~0x002L; - } - if (m & devpriv->ai_maskharderr) { - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); - return 1; - } - return 0; } @@ -909,35 +609,14 @@ static void pci9118_ai_munge(struct comedi_device *dev, } static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned short int_adstat, - unsigned int int_amcc, - unsigned short int_daq) + struct comedi_subdevice *s) { struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned short sampl; - if (int_adstat & devpriv->ai_maskerr) - if (pci9118_decode_error_status(dev, s, int_adstat)) - return; - - sampl = inw(dev->iobase + PCI9118_AD_DATA); + sampl = inl(dev->iobase + PCI9118_AI_FIFO_REG); -#ifdef PCI9118_PARANOIDCHECK - if (s->maxdata != 0xffff) { - if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) { - /* data dropout! */ - dev_info(dev->class_dev, - "A/D SAMPL - data dropout: received channel %d, expected %d!\n", - sampl & 0x000f, - devpriv->chanlist[s->async->cur_chan]); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); - return; - } - } -#endif cfc_write_to_buffer(s, sampl); s->async->cur_chan++; if (s->async->cur_chan >= cmd->scan_end_arg) { @@ -950,63 +629,33 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, s->async->events |= COMEDI_CB_EOA; } } - - cfc_handle_events(dev, s); } static void interrupt_pci9118_ai_dma(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned short int_adstat, - unsigned int int_amcc, - unsigned short int_daq) + struct comedi_subdevice *s) { struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[devpriv->dma_actbuf]; unsigned int next_dma_buf, samplesinbuf, sampls, m; - if (int_amcc & MASTER_ABORT_INT) { - dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n"); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); - return; - } - - if (int_amcc & TARGET_ABORT_INT) { - dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n"); - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); - return; - } - if (int_adstat & devpriv->ai_maskerr) - /* if (int_adstat & 0x106) */ - if (pci9118_decode_error_status(dev, s, int_adstat)) - return; - - samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1; - /* number of received real samples */ + samplesinbuf = dmabuf->use_size >> 1; /* number of received samples */ if (devpriv->dma_doublebuf) { /* * switch DMA buffers if is used * double buffering */ next_dma_buf = 1 - devpriv->dma_actbuf; - outl(devpriv->dmabuf_hw[next_dma_buf], - devpriv->iobase_a + AMCC_OP_REG_MWAR); - outl(devpriv->dmabuf_use_size[next_dma_buf], - devpriv->iobase_a + AMCC_OP_REG_MWTC); - devpriv->dmabuf_used_size[next_dma_buf] = - devpriv->dmabuf_use_size[next_dma_buf]; + pci9118_amcc_setup_dma(dev, next_dma_buf); if (devpriv->ai_do == 4) - interrupt_pci9118_ai_mode4_switch(dev); + interrupt_pci9118_ai_mode4_switch(dev, next_dma_buf); } if (samplesinbuf) { /* how many samples is to end of buffer */ m = s->async->prealloc_bufsz >> 1; sampls = m; - move_block_from_dma(dev, s, - devpriv->dmabuf_virt[devpriv->dma_actbuf], - samplesinbuf); + move_block_from_dma(dev, s, dmabuf->virt, samplesinbuf); m = m - sampls; /* m=how many samples was transferred */ } @@ -1016,18 +665,15 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, s->async->events |= COMEDI_CB_EOA; } - if (devpriv->dma_doublebuf) { /* switch dma buffers */ + if (devpriv->dma_doublebuf) { + /* switch dma buffers */ devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; - } else { /* restart DMA if is not used double buffering */ - outl(devpriv->dmabuf_hw[0], - devpriv->iobase_a + AMCC_OP_REG_MWAR); - outl(devpriv->dmabuf_use_size[0], - devpriv->iobase_a + AMCC_OP_REG_MWTC); + } else { + /* restart DMA if is not used double buffering */ + pci9118_amcc_setup_dma(dev, 0); if (devpriv->ai_do == 4) - interrupt_pci9118_ai_mode4_switch(dev); + interrupt_pci9118_ai_mode4_switch(dev, 0); } - - cfc_handle_events(dev, s); } static irqreturn_t pci9118_interrupt(int irq, void *d) @@ -1042,7 +688,7 @@ static irqreturn_t pci9118_interrupt(int irq, void *d) if (!dev->attached) return IRQ_NONE; - intsrc = inl(dev->iobase + PCI9118_INTSRC) & 0xf; + intsrc = inl(dev->iobase + PCI9118_INT_CTRL_REG) & 0xf; intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); if (!intsrc && !(intcsr & ANY_S593X_INT)) @@ -1050,28 +696,63 @@ static irqreturn_t pci9118_interrupt(int irq, void *d) outl(intcsr | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); - adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; + if (intcsr & MASTER_ABORT_INT) { + dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n"); + s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + goto interrupt_exit; + } + + if (intcsr & TARGET_ABORT_INT) { + dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n"); + s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + goto interrupt_exit; + } + + adstat = inl(dev->iobase + PCI9118_AI_STATUS_REG); + if ((adstat & PCI9118_AI_STATUS_NFULL) == 0) { + dev_err(dev->class_dev, + "A/D FIFO Full status (Fatal Error!)\n"); + s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; + goto interrupt_exit; + } + if (adstat & PCI9118_AI_STATUS_BOVER) { + dev_err(dev->class_dev, + "A/D Burst Mode Overrun Status (Fatal Error!)\n"); + s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; + goto interrupt_exit; + } + if (adstat & PCI9118_AI_STATUS_ADOS) { + dev_err(dev->class_dev, "A/D Over Speed Status (Warning!)\n"); + s->async->events |= COMEDI_CB_ERROR; + goto interrupt_exit; + } + if (adstat & PCI9118_AI_STATUS_ADOR) { + dev_err(dev->class_dev, "A/D Overrun Status (Fatal Error!)\n"); + s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; + goto interrupt_exit; + } if (!devpriv->ai_do) return IRQ_HANDLED; if (devpriv->ai12_startstop) { - if ((adstat & AdStatus_DTH) && (intsrc & Int_DTrg)) { + if ((adstat & PCI9118_AI_STATUS_DTH) && + (intsrc & PCI9118_INT_CTRL_DTRG)) { /* start/stop of measure */ if (devpriv->ai12_startstop & START_AI_EXT) { /* deactivate EXT trigger */ devpriv->ai12_startstop &= ~START_AI_EXT; if (!(devpriv->ai12_startstop & STOP_AI_EXT)) - pci9118_exttrg_del(dev, EXTTRG_AI); + pci9118_exttrg_enable(dev, false); /* start pacer */ pci9118_start_pacer(dev, devpriv->ai_do); - outl(devpriv->AdControlReg, - dev->iobase + PCI9118_ADCNTRL); + outl(devpriv->ai_ctrl, + dev->iobase + PCI9118_AI_CTRL_REG); } else if (devpriv->ai12_startstop & STOP_AI_EXT) { /* deactivate EXT trigger */ devpriv->ai12_startstop &= ~STOP_AI_EXT; - pci9118_exttrg_del(dev, EXTTRG_AI); + pci9118_exttrg_enable(dev, false); /* on next interrupt measure will stop */ devpriv->ai_neverending = 0; @@ -1080,198 +761,41 @@ static irqreturn_t pci9118_interrupt(int irq, void *d) } if (devpriv->usedma) - interrupt_pci9118_ai_dma(dev, s, adstat, intcsr, intsrc); + interrupt_pci9118_ai_dma(dev, s); else - interrupt_pci9118_ai_onesample(dev, s, adstat, intcsr, intsrc); + interrupt_pci9118_ai_onesample(dev, s); +interrupt_exit: + cfc_handle_events(dev, s); return IRQ_HANDLED; } -static int pci9118_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int trig_num) +static void pci9118_ai_cmd_start(struct comedi_device *dev) { struct pci9118_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - - if (trig_num != cmd->start_arg) - return -EINVAL; - - devpriv->ai12_startstop &= ~START_AI_INT; - s->async->inttrig = NULL; - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); + outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG); + outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); if (devpriv->ai_do != 3) { pci9118_start_pacer(dev, devpriv->ai_do); - devpriv->AdControlReg |= AdControl_SoftG; + devpriv->ai_ctrl |= PCI9118_AI_CTRL_SOFTG; } - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - - return 1; + outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG); } -static int pci9118_ai_cmdtest(struct comedi_device *dev, +static int pci9118_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) + unsigned int trig_num) { - const struct boardtype *this_board = comedi_board(dev); - struct pci9118_private *devpriv = dev->private; - int err = 0; - unsigned int flags; - unsigned int arg; - unsigned int divisor1 = 0, divisor2 = 0; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, - TRIG_NOW | TRIG_EXT | TRIG_INT); - - flags = TRIG_FOLLOW; - if (devpriv->master) - flags |= TRIG_TIMER | TRIG_EXT; - err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); - - flags = TRIG_TIMER | TRIG_EXT; - if (devpriv->master) - flags |= TRIG_NOW; - err |= cfc_check_trigger_src(&cmd->convert_src, flags); - - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, - TRIG_COUNT | TRIG_NONE | TRIG_EXT); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->start_src); - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - 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; - - if ((cmd->scan_begin_src == TRIG_FOLLOW) && - (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) - err |= -EINVAL; - - if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) - err |= -EINVAL; - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - switch (cmd->start_src) { - case TRIG_NOW: - case TRIG_EXT: - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - break; - case TRIG_INT: - /* start_arg is the internal trigger (any value) */ - break; - } - - if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT)) - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - - if ((cmd->scan_begin_src == TRIG_TIMER) && - (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) { - cmd->scan_begin_src = TRIG_FOLLOW; - cmd->convert_arg = cmd->scan_begin_arg; - cmd->scan_begin_arg = 0; - } - - if (cmd->scan_begin_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - this_board->ai_ns_min); - - if (cmd->scan_begin_src == TRIG_EXT) - if (cmd->scan_begin_arg) { - cmd->scan_begin_arg = 0; - err |= -EINVAL; - err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, - 65535); - } - - if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - this_board->ai_ns_min); - - if (cmd->convert_src == TRIG_EXT) - err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - - if (cmd->stop_src == TRIG_COUNT) - err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); - else /* TRIG_NONE */ - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - - err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - - err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg, - cmd->chanlist_len); - - if ((cmd->scan_end_arg % cmd->chanlist_len)) { - cmd->scan_end_arg = - cmd->chanlist_len * (cmd->scan_end_arg / cmd->chanlist_len); - err |= -EINVAL; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - arg = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, - &divisor1, &divisor2, - &arg, cmd->flags); - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); - } - - if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) { - arg = cmd->convert_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, - &divisor1, &divisor2, - &arg, cmd->flags); - err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); - - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->convert_src == TRIG_NOW) { - if (cmd->convert_arg == 0) { - arg = this_board->ai_ns_min * - (cmd->scan_end_arg + 2); - } else { - arg = cmd->convert_arg * cmd->chanlist_len; - } - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - arg); - } - } + struct comedi_cmd *cmd = &s->async->cmd; - if (err) - return 4; + if (trig_num != cmd->start_arg) + return -EINVAL; - if (cmd->chanlist) - if (!check_channel_list(dev, s, cmd->chanlist_len, - cmd->chanlist, 0, 0)) - return 5; /* incorrect channels list */ + s->async->inttrig = NULL; + pci9118_ai_cmd_start(dev); - return 0; + return 1; } static int Compute_and_setup_dma(struct comedi_device *dev, @@ -1279,10 +803,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev, { 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; - dmalen0 = devpriv->dmabuf_size[0]; - dmalen1 = devpriv->dmabuf_size[1]; + 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 */ @@ -1294,12 +820,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev, } /* we want wake up every scan? */ - if (devpriv->ai_flags & TRIG_WAKE_EOS) { + if (devpriv->ai_flags & CMDF_WAKE_EOS) { if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) { /* uff, too short DMA buffer, disable EOS support! */ - devpriv->ai_flags &= (~TRIG_WAKE_EOS); + devpriv->ai_flags &= (~CMDF_WAKE_EOS); dev_info(dev->class_dev, - "WAR: DMA0 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n", + "WAR: DMA0 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n", dmalen0, devpriv->ai_n_realscanlen << 1); } else { /* short first DMA buffer to one scan */ @@ -1312,12 +838,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev, } } } - if (devpriv->ai_flags & TRIG_WAKE_EOS) { + if (devpriv->ai_flags & CMDF_WAKE_EOS) { if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) { /* uff, too short DMA buffer, disable EOS support! */ - devpriv->ai_flags &= (~TRIG_WAKE_EOS); + devpriv->ai_flags &= (~CMDF_WAKE_EOS); dev_info(dev->class_dev, - "WAR: DMA1 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n", + "WAR: DMA1 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n", dmalen1, devpriv->ai_n_realscanlen << 1); } else { /* short second DMA buffer to one scan */ @@ -1331,8 +857,8 @@ static int Compute_and_setup_dma(struct comedi_device *dev, } } - /* transfer without TRIG_WAKE_EOS */ - if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) { + /* transfer without CMDF_WAKE_EOS */ + if (!(devpriv->ai_flags & CMDF_WAKE_EOS)) { /* if it's possible then align DMA buffers to length of scan */ i = dmalen0; dmalen0 = @@ -1378,37 +904,16 @@ static int Compute_and_setup_dma(struct comedi_device *dev, /* these DMA buffer size will be used */ devpriv->dma_actbuf = 0; - devpriv->dmabuf_use_size[0] = dmalen0; - devpriv->dmabuf_use_size[1] = dmalen1; - -#if 0 - if (cmd->scan_end_arg < this_board->half_fifo_size) { - devpriv->dmabuf_panic_size[0] = - (this_board->half_fifo_size / cmd->scan_end_arg + - 1) * cmd->scan_end_arg * sizeof(short); - devpriv->dmabuf_panic_size[1] = - (this_board->half_fifo_size / cmd->scan_end_arg + - 1) * cmd->scan_end_arg * sizeof(short); - } else { - devpriv->dmabuf_panic_size[0] = - (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[0]; - devpriv->dmabuf_panic_size[1] = - (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[1]; - } -#endif + dmabuf0->use_size = dmalen0; + dmabuf1->use_size = dmalen1; - outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS), - devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */ - outl(devpriv->dmabuf_hw[0], devpriv->iobase_a + AMCC_OP_REG_MWAR); - outl(devpriv->dmabuf_use_size[0], devpriv->iobase_a + AMCC_OP_REG_MWTC); + pci9118_amcc_dma_ena(dev, false); + pci9118_amcc_setup_dma(dev, 0); /* init DMA transfer */ outl(0x00000000 | AINT_WRITE_COMPL, devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR); */ - - outl(inl(devpriv->iobase_a + - AMCC_OP_REG_MCSR) | RESET_A2P_FLAGS | A2P_HI_PRIORITY | - EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_MCSR); + pci9118_amcc_dma_ena(dev, true); outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* allow bus mastering */ @@ -1416,135 +921,16 @@ static int Compute_and_setup_dma(struct comedi_device *dev, return 0; } -static int pci9118_ai_docmd_sampl(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pci9118_private *devpriv = dev->private; - - switch (devpriv->ai_do) { - case 1: - devpriv->AdControlReg |= AdControl_TmrTr; - break; - case 2: - dev_err(dev->class_dev, "%s mode 2 bug!\n", __func__); - return -EIO; - case 3: - devpriv->AdControlReg |= AdControl_ExtM; - break; - case 4: - dev_err(dev->class_dev, "%s mode 4 bug!\n", __func__); - return -EIO; - default: - dev_err(dev->class_dev, "%s mode number bug!\n", __func__); - return -EIO; - } - - if (devpriv->ai12_startstop) - pci9118_exttrg_add(dev, EXTTRG_AI); - /* activate EXT trigger */ - - if ((devpriv->ai_do == 1) || (devpriv->ai_do == 2)) - devpriv->IntControlReg |= Int_Timer; - - devpriv->AdControlReg |= AdControl_Int; - - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* allow INT in AMCC */ - - if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) { - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - if (devpriv->ai_do != 3) { - pci9118_start_pacer(dev, devpriv->ai_do); - devpriv->AdControlReg |= AdControl_SoftG; - } - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - } - - return 0; -} - -static int pci9118_ai_docmd_dma(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pci9118_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - - Compute_and_setup_dma(dev, s); - - switch (devpriv->ai_do) { - case 1: - devpriv->AdControlReg |= - ((AdControl_TmrTr | AdControl_Dma) & 0xff); - break; - case 2: - devpriv->AdControlReg |= - ((AdControl_TmrTr | AdControl_Dma) & 0xff); - devpriv->AdFunctionReg = - AdFunction_PDTrg | AdFunction_PETrg | AdFunction_BM | - AdFunction_BS; - if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay) - devpriv->AdFunctionReg |= AdFunction_BSSH; - outl(devpriv->ai_n_realscanlen, dev->iobase + PCI9118_BURST); - break; - case 3: - devpriv->AdControlReg |= - ((AdControl_ExtM | AdControl_Dma) & 0xff); - devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - break; - case 4: - devpriv->AdControlReg |= - ((AdControl_TmrTr | AdControl_Dma) & 0xff); - devpriv->AdFunctionReg = - AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - outl(0x30, dev->iobase + PCI9118_CNTCTRL); - outl((devpriv->dmabuf_hw[0] >> 1) & 0xff, - dev->iobase + PCI9118_CNT0); - outl((devpriv->dmabuf_hw[0] >> 9) & 0xff, - dev->iobase + PCI9118_CNT0); - devpriv->AdFunctionReg |= AdFunction_Start; - break; - default: - dev_err(dev->class_dev, "%s mode number bug!\n", __func__); - return -EIO; - } - - if (devpriv->ai12_startstop) { - pci9118_exttrg_add(dev, EXTTRG_AI); - /* activate EXT trigger */ - } - - outl(0x02000000 | AINT_WRITE_COMPL, - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - - if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) { - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - if (devpriv->ai_do != 3) { - pci9118_start_pacer(dev, devpriv->ai_do); - devpriv->AdControlReg |= AdControl_SoftG; - } - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - } - - return 0; -} - static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct boardtype *this_board = comedi_board(dev); struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int addchans = 0; - int ret = 0; devpriv->ai12_startstop = 0; devpriv->ai_flags = cmd->flags; devpriv->ai_add_front = 0; devpriv->ai_add_back = 0; - devpriv->ai_maskerr = 0x10e; /* prepare for start/stop conditions */ if (cmd->start_src == TRIG_EXT) @@ -1553,10 +939,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_neverending = 1; devpriv->ai12_startstop |= STOP_AI_EXT; } - if (cmd->start_src == TRIG_INT) { - devpriv->ai12_startstop |= START_AI_INT; - s->async->inttrig = pci9118_ai_inttrig; - } if (cmd->stop_src == TRIG_NONE) devpriv->ai_neverending = 1; if (cmd->stop_src == TRIG_COUNT) @@ -1570,7 +952,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_add_back = 0; if (devpriv->master) { devpriv->usedma = 1; - if ((cmd->flags & TRIG_WAKE_EOS) && + if ((cmd->flags & CMDF_WAKE_EOS) && (cmd->scan_end_arg == 1)) { if (cmd->convert_src == TRIG_NOW) devpriv->ai_add_back = 1; @@ -1582,7 +964,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) */ } } - if ((cmd->flags & TRIG_WAKE_EOS) && + if ((cmd->flags & CMDF_WAKE_EOS) && (cmd->scan_end_arg & 1) && (cmd->scan_end_arg > 1)) { if (cmd->scan_begin_src == TRIG_FOLLOW) { @@ -1612,8 +994,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_add_front++; devpriv->ai_add_back = 0; } - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; + if (cmd->convert_arg < devpriv->ai_ns_min) + cmd->convert_arg = devpriv->ai_ns_min; addchans = devpriv->softsshdelay / cmd->convert_arg; if (devpriv->softsshdelay % cmd->convert_arg) addchans++; @@ -1642,171 +1024,432 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) cmd->chanlist, devpriv->ai_add_front, devpriv->ai_add_back)) return -EINVAL; - if (!setup_channel_list(dev, s, cmd->chanlist_len, - cmd->chanlist, 0, devpriv->ai_add_front, - devpriv->ai_add_back, devpriv->usedma)) - return -EINVAL; - /* compute timers settings */ /* - * simplest way, fr=4Mhz/(tim1*tim2), - * channel manipulation without timers effect + * Configure analog input and load the chanlist. + * The acqusition control bits are enabled later. */ - if (((cmd->scan_begin_src == TRIG_FOLLOW) || - (cmd->scan_begin_src == TRIG_EXT) || - (cmd->scan_begin_src == TRIG_INT)) && - (cmd->convert_src == TRIG_TIMER)) { - /* both timer is used for one time */ + pci9118_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist, + devpriv->ai_add_front, devpriv->ai_add_back); + + /* Determine acqusition mode and calculate timing */ + devpriv->ai_do = 0; + if (cmd->scan_begin_src != TRIG_TIMER && + cmd->convert_src == TRIG_TIMER) { + /* cascaded timers 1 and 2 are used for convert timing */ if (cmd->scan_begin_src == TRIG_EXT) devpriv->ai_do = 4; else devpriv->ai_do = 1; - pci9118_calc_divisors(devpriv->ai_do, dev, s, - &cmd->scan_begin_arg, &cmd->convert_arg, - devpriv->ai_flags, - devpriv->ai_n_realscanlen, - &devpriv->ai_divisor1, - &devpriv->ai_divisor2, - devpriv->ai_add_front); + + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, + &devpriv->ai_divisor1, + &devpriv->ai_divisor2, + &cmd->convert_arg, + devpriv->ai_flags & + CMDF_ROUND_NEAREST); + + devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR; + + if (!devpriv->usedma) { + devpriv->ai_ctrl |= PCI9118_AI_CTRL_INT; + devpriv->int_ctrl |= PCI9118_INT_CTRL_TIMER; + } + + if (cmd->scan_begin_src == TRIG_EXT) { + struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[0]; + + devpriv->ai_cfg |= PCI9118_AI_CFG_AM; + outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); + pci9118_timer_set_mode(dev, 0, I8254_MODE0); + pci9118_timer_write(dev, 0, dmabuf->hw >> 1); + devpriv->ai_cfg |= PCI9118_AI_CFG_START; + } } - if ((cmd->scan_begin_src == TRIG_TIMER) && - ((cmd->convert_src == TRIG_TIMER) || - (cmd->convert_src == TRIG_NOW))) { - /* double timed action */ + if (cmd->scan_begin_src == TRIG_TIMER && + cmd->convert_src != TRIG_EXT) { if (!devpriv->usedma) { dev_err(dev->class_dev, "cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!\n"); return -EIO; } + /* double timed action */ devpriv->ai_do = 2; - pci9118_calc_divisors(devpriv->ai_do, dev, s, + + pci9118_calc_divisors(dev, s, &cmd->scan_begin_arg, &cmd->convert_arg, devpriv->ai_flags, devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, &devpriv->ai_divisor2, devpriv->ai_add_front); + + devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR; + devpriv->ai_cfg |= PCI9118_AI_CFG_BM | PCI9118_AI_CFG_BS; + if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay) + devpriv->ai_cfg |= PCI9118_AI_CFG_BSSH; + outl(devpriv->ai_n_realscanlen, + dev->iobase + PCI9118_AI_BURST_NUM_REG); } - if ((cmd->scan_begin_src == TRIG_FOLLOW) - && (cmd->convert_src == TRIG_EXT)) { + if (cmd->scan_begin_src == TRIG_FOLLOW && + cmd->convert_src == TRIG_EXT) { + /* external trigger conversion */ devpriv->ai_do = 3; + + devpriv->ai_ctrl |= PCI9118_AI_CTRL_EXTM; + } + + if (devpriv->ai_do == 0) { + dev_err(dev->class_dev, + "Unable to determine acqusition mode! BUG in (*do_cmdtest)?\n"); + return -EINVAL; } + if (devpriv->usedma) + devpriv->ai_ctrl |= PCI9118_AI_CTRL_DMA; + pci9118_start_pacer(dev, -1); /* stop pacer */ - devpriv->AdControlReg = 0; /* - * bipolar, S.E., use 8254, stop 8354, - * internal trigger, soft trigger, - * disable DMA - */ - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - /* - * positive triggers, no S&H, no burst, - * burst stop, no post trigger, - * no about trigger, trigger stop - */ - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); + /* set default config (disable burst and triggers) */ + devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG; + outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); udelay(1); - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - inl(dev->iobase + PCI9118_ADSTAT); /* - * flush A/D and INT - * status register - */ - inl(dev->iobase + PCI9118_INTSRC); + pci9118_ai_reset_fifo(dev); + + /* clear A/D and INT status registers */ + inl(dev->iobase + PCI9118_AI_STATUS_REG); + inl(dev->iobase + PCI9118_INT_CTRL_REG); devpriv->ai_act_scan = 0; devpriv->ai_act_dmapos = 0; s->async->cur_chan = 0; - if (devpriv->usedma) - ret = pci9118_ai_docmd_dma(dev, s); - else - ret = pci9118_ai_docmd_sampl(dev, s); + if (devpriv->usedma) { + Compute_and_setup_dma(dev, s); + + outl(0x02000000 | AINT_WRITE_COMPL, + devpriv->iobase_a + AMCC_OP_REG_INTCSR); + } else { + pci9118_amcc_int_ena(dev, true); + } - return ret; + /* start async command now or wait for internal trigger */ + if (cmd->start_src == TRIG_NOW) + pci9118_ai_cmd_start(dev); + else if (cmd->start_src == TRIG_INT) + s->async->inttrig = pci9118_ai_inttrig; + + /* enable external trigger for command start/stop */ + if (cmd->start_src == TRIG_EXT || cmd->stop_src == TRIG_EXT) + pci9118_exttrg_enable(dev, true); + + return 0; } -static int pci9118_reset(struct comedi_device *dev) +static int pci9118_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { struct pci9118_private *devpriv = dev->private; + int err = 0; + unsigned int flags; + unsigned int arg; + unsigned int divisor1 = 0, divisor2 = 0; - devpriv->IntControlReg = 0; - devpriv->exttrg_users = 0; - inl(dev->iobase + PCI9118_INTCTRL); - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - /* disable interrupts source */ - outl(0x30, dev->iobase + PCI9118_CNTCTRL); -/* outl(0xb4, dev->iobase + PCI9118_CNTCTRL); */ - pci9118_start_pacer(dev, 0); /* stop 8254 counters */ - devpriv->AdControlReg = 0; - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - /* - * bipolar, S.E., use 8254, - * stop 8354, internal trigger, - * soft trigger, - * disable INT and DMA - */ - outl(0, dev->iobase + PCI9118_BURST); - outl(1, dev->iobase + PCI9118_SCANMOD); - outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */ - devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - /* - * positive triggers, no S&H, - * no burst, burst stop, - * no post trigger, - * no about trigger, - * trigger stop - */ + /* Step 1 : check if triggers are trivially valid */ - devpriv->ao_data[0] = 2047; - devpriv->ao_data[1] = 2047; - outl(devpriv->ao_data[0], dev->iobase + PCI9118_DA1); - /* reset A/D outs to 0V */ - outl(devpriv->ao_data[1], dev->iobase + PCI9118_DA2); - outl(0, dev->iobase + PCI9118_DO); /* reset digi outs to L */ - udelay(10); - inl(dev->iobase + PCI9118_AD_DATA); - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - outl(0, dev->iobase + PCI9118_INTSRC); /* remove INT requests */ - inl(dev->iobase + PCI9118_ADSTAT); /* flush A/D status register */ - inl(dev->iobase + PCI9118_INTSRC); /* flush INT requests */ - devpriv->AdControlReg = 0; - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - /* - * bipolar, S.E., use 8254, - * stop 8354, internal trigger, - * soft trigger, - * disable INT and DMA - */ + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_EXT | TRIG_INT); + + flags = TRIG_FOLLOW; + if (devpriv->master) + flags |= TRIG_TIMER | TRIG_EXT; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); + + flags = TRIG_TIMER | TRIG_EXT; + if (devpriv->master) + flags |= TRIG_NOW; + err |= cfc_check_trigger_src(&cmd->convert_src, flags); + + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, + TRIG_COUNT | TRIG_NONE | TRIG_EXT); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + 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; - devpriv->exttrg_users = 0; + if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) && + (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) + err |= -EINVAL; + + if ((cmd->scan_begin_src == TRIG_FOLLOW) && + (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) + err |= -EINVAL; + + if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) + err |= -EINVAL; + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_EXT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_INT: + /* start_arg is the internal trigger (any value) */ + break; + } + + if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT)) + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + + if ((cmd->scan_begin_src == TRIG_TIMER) && + (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) { + cmd->scan_begin_src = TRIG_FOLLOW; + cmd->convert_arg = cmd->scan_begin_arg; + cmd->scan_begin_arg = 0; + } + + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + devpriv->ai_ns_min); + + if (cmd->scan_begin_src == TRIG_EXT) + if (cmd->scan_begin_arg) { + cmd->scan_begin_arg = 0; + err |= -EINVAL; + err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, + 65535); + } + + if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + devpriv->ai_ns_min); + + if (cmd->convert_src == TRIG_EXT) + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + + err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg, + cmd->chanlist_len); + + if ((cmd->scan_end_arg % cmd->chanlist_len)) { + cmd->scan_end_arg = + cmd->chanlist_len * (cmd->scan_end_arg / cmd->chanlist_len); + err |= -EINVAL; + } + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, + &divisor1, &divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); + } + + if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) { + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ, + &divisor1, &divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER && + cmd->convert_src == TRIG_NOW) { + if (cmd->convert_arg == 0) { + arg = devpriv->ai_ns_min * + (cmd->scan_end_arg + 2); + } else { + arg = cmd->convert_arg * cmd->chanlist_len; + } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); + } + } + + if (err) + return 4; + + if (cmd->chanlist) + if (!check_channel_list(dev, s, cmd->chanlist_len, + cmd->chanlist, 0, 0)) + return 5; /* incorrect channels list */ return 0; } -/* - * FIXME - this is pretty ineffective because all the supported board types - * have the same device ID! - */ -static const struct boardtype *pci9118_find_boardinfo(struct pci_dev *pcidev) +static int pci9118_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned int i; + unsigned int status; - for (i = 0; i < ARRAY_SIZE(boardtypes); i++) - if (pcidev->device == boardtypes[i].device_id) - return &boardtypes[i]; - return NULL; + status = inl(dev->iobase + PCI9118_AI_STATUS_REG); + if (status & PCI9118_AI_STATUS_ADRDY) + return 0; + return -EBUSY; +} + +static void pci9118_ai_start_conv(struct comedi_device *dev) +{ + /* writing any value triggers an A/D conversion */ + outl(0, dev->iobase + PCI9118_SOFTTRG_REG); +} + +static int pci9118_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pci9118_private *devpriv = dev->private; + unsigned int val; + int ret; + int i; + + /* + * Configure analog input based on the chanspec. + * Acqusition is software controlled without interrupts. + */ + pci9118_set_chanlist(dev, s, 1, &insn->chanspec, 0, 0); + + /* set default config (disable burst and triggers) */ + devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG; + outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); + + pci9118_ai_reset_fifo(dev); + + for (i = 0; i < insn->n; i++) { + pci9118_ai_start_conv(dev); + + ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0); + if (ret) + return ret; + + val = inl(dev->iobase + PCI9118_AI_FIFO_REG); + if (s->maxdata == 0xffff) + data[i] = (val & 0xffff) ^ 0x8000; + else + data[i] = (val >> 4) & 0xfff; + } + + return insn->n; +} + +static int pci9118_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + outl(val, dev->iobase + PCI9118_AO_REG(chan)); + } + s->readback[chan] = val; + + return insn->n; +} + +static int pci9118_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + /* + * The digital inputs and outputs share the read register. + * bits [7:4] are the digital outputs + * bits [3:0] are the digital inputs + */ + data[1] = inl(dev->iobase + PCI9118_DIO_REG) & 0xf; + + return insn->n; +} + +static int pci9118_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + /* + * The digital outputs are set with the same register that + * the digital inputs and outputs are read from. But the + * outputs are set with bits [3:0] so we can simply write + * the s->state to set them. + */ + if (comedi_dio_update_state(s, data)) + outl(s->state, dev->iobase + PCI9118_DIO_REG); + + data[1] = s->state; + + return insn->n; +} + +static void pci9118_reset(struct comedi_device *dev) +{ + /* reset analog input subsystem */ + outl(0, dev->iobase + PCI9118_INT_CTRL_REG); + outl(0, dev->iobase + PCI9118_AI_CTRL_REG); + outl(0, dev->iobase + PCI9118_AI_CFG_REG); + pci9118_ai_reset_fifo(dev); + + /* clear any pending interrupts and status */ + inl(dev->iobase + PCI9118_INT_CTRL_REG); + inl(dev->iobase + PCI9118_AI_STATUS_REG); + + /* reset and stop counters */ + pci9118_timer_set_mode(dev, 0, I8254_MODE0); + pci9118_start_pacer(dev, 0); + + /* reset DMA and scan queue */ + outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG); + outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG); + + /* reset analog outputs to 0V */ + outl(2047, dev->iobase + PCI9118_AO_REG(0)); + outl(2047, dev->iobase + PCI9118_AO_REG(1)); } static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct boardtype *this_board = comedi_board(dev); struct pci_dev *pcidev = NULL; int bus = it->options[0]; int slot = it->options[1]; @@ -1814,7 +1457,7 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, for_each_pci_dev(pcidev) { if (pcidev->vendor != PCI_VENDOR_ID_AMCC) continue; - if (pcidev->device != this_board->device_id) + if (pcidev->device != 0x80d9) continue; if (bus || slot) { /* requested particular bus/slot */ @@ -1830,56 +1473,85 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, return NULL; } -static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, - int master, int ext_mux, int softsshdelay, - int hw_err_mask) +static void pci9118_alloc_dma(struct comedi_device *dev) +{ + struct pci9118_private *devpriv = dev->private; + struct pci9118_dmabuf *dmabuf; + int order; + int i; + + for (i = 0; i < 2; i++) { + dmabuf = &devpriv->dmabuf[i]; + for (order = 2; order >= 0; order--) { + dmabuf->virt = + dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order, + &dmabuf->hw, GFP_KERNEL); + if (dmabuf->virt) + break; + } + if (!dmabuf->virt) + break; + dmabuf->size = PAGE_SIZE << order; + + if (i == 0) + devpriv->master = 1; + if (i == 1) + devpriv->dma_doublebuf = 1; + } +} + +static void pci9118_free_dma(struct comedi_device *dev) { - const struct boardtype *this_board = comedi_board(dev); struct pci9118_private *devpriv = dev->private; + struct pci9118_dmabuf *dmabuf; + int i; + + if (!devpriv) + return; + + for (i = 0; i < 2; i++) { + dmabuf = &devpriv->dmabuf[i]; + if (dmabuf->virt) { + dma_free_coherent(dev->hw_dev, dmabuf->size, + dmabuf->virt, dmabuf->hw); + } + } +} + +static int pci9118_common_attach(struct comedi_device *dev, + int ext_mux, int softsshdelay) +{ + const struct pci9118_boardinfo *board = dev->board_ptr; struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct pci9118_private *devpriv; struct comedi_subdevice *s; - int ret, pages, i; + int ret; + int i; u16 u16w; - dev->board_name = this_board->name; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + ret = comedi_pci_enable(dev); if (ret) return ret; - if (master) - pci_set_master(pcidev); + pci_set_master(pcidev); devpriv->iobase_a = pci_resource_start(pcidev, 0); dev->iobase = pci_resource_start(pcidev, 2); pci9118_reset(dev); - if (master) { /* alloc DMA buffers */ - devpriv->dma_doublebuf = 0; - for (i = 0; i < 2; i++) { - for (pages = 4; pages >= 0; pages--) { - devpriv->dmabuf_virt[i] = - (unsigned short *) - __get_free_pages(GFP_KERNEL, pages); - if (devpriv->dmabuf_virt[i]) - break; - } - if (devpriv->dmabuf_virt[i]) { - devpriv->dmabuf_pages[i] = pages; - devpriv->dmabuf_size[i] = PAGE_SIZE * pages; - devpriv->dmabuf_hw[i] = - virt_to_bus((void *) - devpriv->dmabuf_virt[i]); - } - } - if (!devpriv->dmabuf_virt[0]) { - dev_warn(dev->class_dev, - "Can't allocate DMA buffer, DMA disabled!\n"); - master = 0; + if (pcidev->irq) { + ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) { + dev->irq = pcidev->irq; + + pci9118_alloc_dma(dev); } - if (devpriv->dmabuf_virt[1]) - devpriv->dma_doublebuf = 1; } - devpriv->master = master; if (ext_mux > 0) { if (ext_mux > 256) @@ -1887,7 +1559,7 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, if (softsshdelay > 0) if (ext_mux > 128) ext_mux = 128; - devpriv->usemux = ext_mux; + devpriv->usemux = 1; } else { devpriv->usemux = 0; } @@ -1907,70 +1579,81 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, pci_write_config_word(pcidev, PCI_COMMAND, u16w | 64); /* Enable parity check for parity error */ - if (!disable_irq && pcidev->irq) { - ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED, - dev->board_name, dev); - if (ret == 0) - dev->irq = pcidev->irq; - } - ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; - if (devpriv->usemux) - s->n_chan = devpriv->usemux; - else - s->n_chan = this_board->n_aichan; - - s->maxdata = this_board->ai_maxdata; - s->range_table = this_board->rangelist_ai; - s->insn_read = pci9118_insn_read_ai; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = (devpriv->usemux) ? ext_mux : 16; + s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff; + s->range_table = board->is_hg ? &pci9118hg_ai_range + : &pci9118_ai_range; + s->insn_read = pci9118_ai_insn_read; if (dev->irq) { dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = this_board->n_aichanlist; - s->do_cmdtest = pci9118_ai_cmdtest; - s->do_cmd = pci9118_ai_cmd; - s->cancel = pci9118_ai_cancel; - s->munge = pci9118_ai_munge; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = PCI9118_CHANLEN; + s->do_cmdtest = pci9118_ai_cmdtest; + s->do_cmd = pci9118_ai_cmd; + s->cancel = pci9118_ai_cancel; + s->munge = pci9118_ai_munge; + } + + if (s->maxdata == 0xffff) { + /* + * 16-bit samples are from an ADS7805 A/D converter. + * Minimum sampling rate is 10us. + */ + devpriv->ai_ns_min = 10000; + } else { + /* + * 12-bit samples are from an ADS7800 A/D converter. + * Minimum sampling rate is 3us. + */ + devpriv->ai_ns_min = 3000; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_aochan; - s->maxdata = this_board->ao_maxdata; - s->len_chanlist = this_board->n_aochan; - s->range_table = this_board->rangelist_ao; - s->insn_write = pci9118_insn_write_ao; - s->insn_read = pci9118_insn_read_ao; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_bipolar10; + s->insn_write = pci9118_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; - s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 1; - s->len_chanlist = 4; - s->range_table = &range_digital; - s->insn_bits = pci9118_insn_bits_di; + /* the analog outputs were reset to 0V, make the readback match */ + for (i = 0; i < s->n_chan; i++) + s->readback[i] = 2047; + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci9118_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 1; - s->len_chanlist = 4; - s->range_table = &range_digital; - s->insn_bits = pci9118_insn_bits_do; - - devpriv->ai_maskharderr = 0x10a; - /* default measure crash condition */ - if (hw_err_mask) /* disable some requested */ - devpriv->ai_maskharderr &= ~hw_err_mask; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci9118_do_insn_bits; + + /* get the current state of the digital outputs */ + s->state = inl(dev->iobase + PCI9118_DIO_REG) >> 4; return 0; } @@ -1978,74 +1661,50 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, static int pci9118_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct pci9118_private *devpriv; struct pci_dev *pcidev; - int ext_mux, disable_irq, master, softsshdelay, hw_err_mask; + int ext_mux, softsshdelay; ext_mux = it->options[2]; - master = ((it->options[3] & 1) == 0); - disable_irq = ((it->options[3] & 2) != 0); softsshdelay = it->options[4]; - hw_err_mask = it->options[5]; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; pcidev = pci9118_find_pci(dev, it); if (!pcidev) return -EIO; comedi_set_hw_dev(dev, &pcidev->dev); - return pci9118_common_attach(dev, disable_irq, master, ext_mux, - softsshdelay, hw_err_mask); + return pci9118_common_attach(dev, ext_mux, softsshdelay); } static int pci9118_auto_attach(struct comedi_device *dev, - unsigned long context_unused) + unsigned long context) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct pci9118_private *devpriv; + const struct pci9118_boardinfo *board = NULL; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; + if (context < ARRAY_SIZE(pci9118_boards)) + board = &pci9118_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - dev->board_ptr = pci9118_find_boardinfo(pcidev); - if (dev->board_ptr == NULL) { - dev_err(dev->class_dev, - "adl_pci9118: cannot determine board type for pci %s\n", - pci_name(pcidev)); - return -EINVAL; - } /* * Need to 'get' the PCI device to match the 'put' in pci9118_detach(). * (The 'put' also matches the implicit 'get' by pci9118_find_pci().) */ pci_dev_get(pcidev); - /* Don't disable irq, use bus master, no external mux, - * no sample-hold delay, no error mask. */ - return pci9118_common_attach(dev, 0, 1, 0, 0, 0); + /* no external mux, no sample-hold delay */ + return pci9118_common_attach(dev, 0, 0); } static void pci9118_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct pci9118_private *devpriv = dev->private; - if (devpriv) { - if (dev->iobase) - pci9118_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv->dmabuf_virt[0]) - free_pages((unsigned long)devpriv->dmabuf_virt[0], - devpriv->dmabuf_pages[0]); - if (devpriv->dmabuf_virt[1]) - free_pages((unsigned long)devpriv->dmabuf_virt[1], - devpriv->dmabuf_pages[1]); - } - comedi_pci_disable(dev); + if (dev->iobase) + pci9118_reset(dev); + comedi_pci_detach(dev); + pci9118_free_dma(dev); if (pcidev) pci_dev_put(pcidev); } @@ -2056,9 +1715,9 @@ static struct comedi_driver adl_pci9118_driver = { .attach = pci9118_attach, .auto_attach = pci9118_auto_attach, .detach = pci9118_detach, - .num_names = ARRAY_SIZE(boardtypes), - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), + .num_names = ARRAY_SIZE(pci9118_boards), + .board_name = &pci9118_boards[0].name, + .offset = sizeof(struct pci9118_boardinfo), }; static int adl_pci9118_pci_probe(struct pci_dev *dev, @@ -2068,8 +1727,11 @@ static int adl_pci9118_pci_probe(struct pci_dev *dev, id->driver_data); } +/* FIXME: All the supported board types have the same device ID! */ static const struct pci_device_id adl_pci9118_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) }, + { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118DG }, +/* { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118HG }, */ +/* { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118HR }, */ { 0 } }; MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table); diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index e19ab958791b..5539bd294862 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -327,7 +327,7 @@ static int pci171x_ai_dropout(struct comedi_device *dev, unsigned int chan, unsigned int val) { - const struct boardtype *board = comedi_board(dev); + const struct boardtype *board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; if (board->cardtype != TYPE_PCI1713) { @@ -413,7 +413,7 @@ static void setup_channel_list(struct comedi_device *dev, unsigned int *chanlist, unsigned int n_chan, unsigned int seglen) { - const struct boardtype *this_board = comedi_board(dev); + const struct boardtype *this_board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; unsigned int i, range, chanprog; @@ -715,7 +715,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, static int pci171x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct boardtype *this_board = comedi_board(dev); + const struct boardtype *this_board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; switch (this_board->cardtype) { @@ -828,7 +828,7 @@ static int move_block_from_fifo(struct comedi_device *dev, static void pci1710_handle_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct boardtype *this_board = comedi_board(dev); + const struct boardtype *this_board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int m, samplesinbuf; @@ -907,7 +907,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) return IRQ_HANDLED; } - if (cmd->flags & TRIG_WAKE_EOS) + if (cmd->flags & CMDF_WAKE_EOS) pci1710_handle_every_sample(dev, s); else pci1710_handle_fifo(dev, s); @@ -932,7 +932,7 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->cur_chan = 0; devpriv->CntrlReg &= Control_CNT0; - if ((cmd->flags & TRIG_WAKE_EOS) == 0) + if ((cmd->flags & CMDF_WAKE_EOS) == 0) devpriv->CntrlReg |= Control_ONEFH; devpriv->divisor1 = devpriv->next_divisor1; @@ -968,7 +968,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct boardtype *this_board = comedi_board(dev); + const struct boardtype *this_board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -1045,7 +1045,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, */ static int pci171x_reset(struct comedi_device *dev) { - const struct boardtype *this_board = comedi_board(dev); + const struct boardtype *this_board = dev->board_ptr; struct pci1710_private *devpriv = dev->private; outw(0x30, dev->iobase + PCI171x_CNTCTRL); @@ -1102,7 +1102,7 @@ static int pci1720_reset(struct comedi_device *dev) */ static int pci1710_reset(struct comedi_device *dev) { - const struct boardtype *this_board = comedi_board(dev); + const struct boardtype *this_board = dev->board_ptr; switch (this_board->cardtype) { case TYPE_PCI1720: @@ -1250,9 +1250,7 @@ static void pci1710_detach(struct comedi_device *dev) { if (dev->iobase) pci1710_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver adv_pci1710_driver = { diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 1881df459dae..1610e2b406f3 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -286,7 +286,7 @@ static void pci1723_detach(struct comedi_device *dev) { if (dev->iobase) pci1723_reset(dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver adv_pci1723_driver = { diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c index bc3c34916768..2697758b1ed9 100644 --- a/drivers/staging/comedi/drivers/adv_pci1724.c +++ b/drivers/staging/comedi/drivers/adv_pci1724.c @@ -372,7 +372,7 @@ static struct comedi_driver adv_pci1724_driver = { .driver_name = "adv_pci1724", .module = THIS_MODULE, .auto_attach = adv_pci1724_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int adv_pci1724_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index b8c7d9145a54..f2e2d7e163bf 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -66,7 +66,6 @@ enum hw_io_access { * subdevice) */ #define SIZE_8254 4 /* 8254 IO space length */ -#define SIZE_8255 4 /* 8255 IO space length */ #define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */ @@ -394,7 +393,6 @@ static const struct dio_boardtype boardtypes[] = { }; struct pci_dio_private { - char valid; /* card is usable */ char GlobalIrqEnabled; /* 1= any IRQ source is enabled */ /* PCI-1760 specific data */ unsigned char IDICntEnable; /* counter's counting enable status */ @@ -819,7 +817,7 @@ static int pci1760_reset(struct comedi_device *dev) */ static int pci_dio_reset(struct comedi_device *dev) { - const struct dio_boardtype *this_board = comedi_board(dev); + const struct dio_boardtype *this_board = dev->board_ptr; switch (this_board->cardtype) { case TYPE_PCI1730: @@ -977,7 +975,7 @@ static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s, const struct diosubd_data *d) { - const struct dio_boardtype *this_board = comedi_board(dev); + const struct dio_boardtype *this_board = dev->board_ptr; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags; @@ -1007,7 +1005,7 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, const struct diosubd_data *d) { - const struct dio_boardtype *this_board = comedi_board(dev); + const struct dio_boardtype *this_board = dev->board_ptr; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; @@ -1132,9 +1130,8 @@ static int pci_dio_auto_attach(struct comedi_device *dev, for (j = 0; j < this_board->sdio[i].regs; j++) { s = &dev->subdevices[subdev]; ret = subdev_8255_init(dev, s, NULL, - dev->iobase + this_board->sdio[i].addr + - SIZE_8255 * j); + j * I8255_SIZE); if (ret) return ret; subdev++; @@ -1157,8 +1154,6 @@ static int pci_dio_auto_attach(struct comedi_device *dev, if (this_board->cardtype == TYPE_PCI1760) pci1760_attach(dev); - devpriv->valid = 1; - pci_dio_reset(dev); return 0; @@ -1166,13 +1161,9 @@ static int pci_dio_auto_attach(struct comedi_device *dev, static void pci_dio_detach(struct comedi_device *dev) { - struct pci_dio_private *devpriv = dev->private; - - if (devpriv) { - if (devpriv->valid) - pci_dio_reset(dev); - } - comedi_pci_disable(dev); + if (dev->iobase) + pci_dio_reset(dev); + comedi_pci_detach(dev); } static struct comedi_driver adv_pci_dio_driver = { diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index 324746b14931..538277a691b2 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -97,10 +97,6 @@ static const struct aio12_8_boardtype board_types[] = { }, }; -struct aio12_8_private { - unsigned int ao_readback[4]; -}; - static int aio_aio12_8_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -149,28 +145,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, return insn->n; } -static int aio_aio12_8_ao_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct aio12_8_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int val = devpriv->ao_readback[chan]; - int i; - - for (i = 0; i < insn->n; i++) - data[i] = val; - return insn->n; -} - -static int aio_aio12_8_ao_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int aio_aio12_8_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct aio12_8_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned long port = dev->iobase + AIO12_8_DAC_REG(chan); - unsigned int val = 0; + unsigned int val = s->readback[chan]; int i; /* enable DACs */ @@ -178,10 +159,9 @@ static int aio_aio12_8_ao_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - outw(val, port); + outw(val, dev->iobase + AIO12_8_DAC_REG(chan)); } - - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; return insn->n; } @@ -198,8 +178,7 @@ static const struct comedi_lrange range_aio_aio12_8 = { static int aio_aio12_8_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct aio12_8_boardtype *board = comedi_board(dev); - struct aio12_8_private *devpriv; + const struct aio12_8_boardtype *board = dev->board_ptr; struct comedi_subdevice *s; int ret; @@ -207,10 +186,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; @@ -236,16 +211,19 @@ static int aio_aio12_8_attach(struct comedi_device *dev, s->n_chan = 4; s->maxdata = 0x0fff; s->range_table = &range_aio_aio12_8; - s->insn_read = aio_aio12_8_ao_read; - s->insn_write = aio_aio12_8_ao_write; + s->insn_write = aio_aio12_8_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } s = &dev->subdevices[2]; /* 8255 Digital i/o subdevice */ - ret = subdev_8255_init(dev, s, NULL, - dev->iobase + AIO12_8_8255_BASE_REG); + ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 17d2e20663cb..4fe118380218 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -202,100 +202,69 @@ */ static const struct dio200_board dio200_isa_boards[] = { { - .name = "pc212e", - .bustype = isa_bustype, - .mainsize = DIO200_IO_SIZE, - .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 = true, - .has_clk_gat_sce = true, + .name = "pc212e", + .n_subdevs = 6, + .sdtype = { + sd_8255, sd_8254, sd_8254, sd_8254, sd_8254, sd_intr }, - }, - { - .name = "pc214e", - .bustype = isa_bustype, - .mainsize = DIO200_IO_SIZE, - .layout = { - .n_subdevs = 4, - .sdtype = {sd_8255, sd_8255, sd_8254, sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x01}, + .sdinfo = { 0x00, 0x08, 0x0c, 0x10, 0x14, 0x3f }, + .has_int_sce = true, + .has_clk_gat_sce = true, + }, { + .name = "pc214e", + .n_subdevs = 4, + .sdtype = { + sd_8255, sd_8255, sd_8254, sd_intr }, - }, - { - .name = "pc215e", - .bustype = isa_bustype, - .mainsize = DIO200_IO_SIZE, - .layout = { - .n_subdevs = 5, - .sdtype = {sd_8255, sd_8255, sd_8254, sd_8254, sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F}, - .has_int_sce = true, - .has_clk_gat_sce = true, + .sdinfo = { 0x00, 0x08, 0x10, 0x01 }, + }, { + .name = "pc215e", + .n_subdevs = 5, + .sdtype = { + sd_8255, sd_8255, sd_8254, sd_8254, sd_intr }, - }, - { - .name = "pc218e", - .bustype = isa_bustype, - .mainsize = DIO200_IO_SIZE, - .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 = true, - .has_clk_gat_sce = true, + .sdinfo = { 0x00, 0x08, 0x10, 0x14, 0x3f }, + .has_int_sce = true, + .has_clk_gat_sce = true, + }, { + .name = "pc218e", + .n_subdevs = 7, + .sdtype = { + sd_8254, sd_8254, sd_8255, sd_8254, sd_8254, sd_intr }, - }, - { - .name = "pc272e", - .bustype = isa_bustype, - .mainsize = DIO200_IO_SIZE, - .layout = { - .n_subdevs = 4, - .sdtype = {sd_8255, sd_8255, sd_8255, sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x3F}, - .has_int_sce = true, + .sdinfo = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x3f }, + .has_int_sce = true, + .has_clk_gat_sce = true, + }, { + .name = "pc272e", + .n_subdevs = 4, + .sdtype = { + sd_8255, sd_8255, sd_8255, sd_intr }, + .sdinfo = { 0x00, 0x08, 0x10, 0x3f }, + .has_int_sce = true, }, }; static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct dio200_board *thisboard = comedi_board(dev); - struct dio200_private *devpriv; - unsigned int irq; int ret; - irq = it->options[1]; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - ret = comedi_request_region(dev, it->options[0], thisboard->mainsize); + ret = comedi_request_region(dev, it->options[0], 0x20); if (ret) return ret; - return amplc_dio200_common_attach(dev, irq, 0); -} - -static void dio200_detach(struct comedi_device *dev) -{ - amplc_dio200_common_detach(dev); - comedi_legacy_detach(dev); + return amplc_dio200_common_attach(dev, it->options[1], 0); } static struct comedi_driver amplc_dio200_driver = { - .driver_name = "amplc_dio200", - .module = THIS_MODULE, - .attach = dio200_attach, - .detach = dio200_detach, - .board_name = &dio200_isa_boards[0].name, - .offset = sizeof(struct dio200_board), - .num_names = ARRAY_SIZE(dio200_isa_boards), + .driver_name = "amplc_dio200", + .module = THIS_MODULE, + .attach = dio200_attach, + .detach = comedi_legacy_detach, + .board_name = &dio200_isa_boards[0].name, + .offset = sizeof(struct dio200_board), + .num_names = ARRAY_SIZE(dio200_isa_boards), }; module_comedi_driver(amplc_dio200_driver); diff --git a/drivers/staging/comedi/drivers/amplc_dio200.h b/drivers/staging/comedi/drivers/amplc_dio200.h index e0afe2cee2d6..d6d6a265c461 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.h +++ b/drivers/staging/comedi/drivers/amplc_dio200.h @@ -23,10 +23,6 @@ #ifndef AMPLC_DIO200_H_INCLUDED #define AMPLC_DIO200_H_INCLUDED -/* 200 series register area sizes */ -#define DIO200_IO_SIZE 0x20 -#define DIO200_PCIE_IO_SIZE 0x4000 - /* * Subdevice types. */ @@ -35,42 +31,20 @@ enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254, sd_timer }; #define DIO200_MAX_SUBDEVS 8 #define DIO200_MAX_ISNS 6 -/* - * Board descriptions. - */ - -struct dio200_layout { +struct dio200_board { + const char *name; + unsigned char mainbar; 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 */ bool has_int_sce:1; /* has interrupt enable/status reg */ bool has_clk_gat_sce:1; /* has clock/gate selection registers */ - bool has_enhancements:1; /* has enhanced features */ -}; - -enum dio200_bustype { isa_bustype, pci_bustype }; - -struct dio200_board { - const char *name; - struct dio200_layout layout; - enum dio200_bustype bustype; - unsigned char mainbar; - unsigned char mainshift; - unsigned int mainsize; -}; - -/* - * Comedi device private data. - */ -struct dio200_private { - int intr_sd; + bool is_pcie:1; /* has enhanced features */ }; int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq, unsigned long req_irq_flags); -void amplc_dio200_common_detach(struct comedi_device *dev); - /* Used by initialization of PCIe boards. */ void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val); diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index f0d709e0dafc..2c1bfb09601d 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -27,15 +27,7 @@ #include "amplc_dio200.h" #include "comedi_fc.h" #include "8253.h" - -/* 8255 control register bits */ -#define CR_C_LO_IO 0x01 -#define CR_B_IO 0x02 -#define CR_B_MODE 0x04 -#define CR_C_HI_IO 0x08 -#define CR_A_IO 0x10 -#define CR_A_MODE(a) ((a)<<5) -#define CR_CW 0x80 +#include "8255.h" /* only for register defines */ /* 200 series registers */ #define DIO200_IO_SIZE 0x20 @@ -132,42 +124,26 @@ struct dio200_subdev_intr { bool active:1; }; -static inline const struct dio200_layout * -dio200_board_layout(const struct dio200_board *board) -{ - return &board->layout; -} - -static inline const struct dio200_layout * -dio200_dev_layout(struct comedi_device *dev) -{ - return dio200_board_layout(comedi_board(dev)); -} - -/* - * Read 8-bit register. - */ static unsigned char dio200_read8(struct comedi_device *dev, unsigned int offset) { - const struct dio200_board *thisboard = comedi_board(dev); + const struct dio200_board *board = dev->board_ptr; - offset <<= thisboard->mainshift; + if (board->is_pcie) + offset <<= 3; if (dev->mmio) return readb(dev->mmio + offset); return inb(dev->iobase + offset); } -/* - * Write 8-bit register. - */ -static void dio200_write8(struct comedi_device *dev, unsigned int offset, - unsigned char val) +static void dio200_write8(struct comedi_device *dev, + unsigned int offset, unsigned char val) { - const struct dio200_board *thisboard = comedi_board(dev); + const struct dio200_board *board = dev->board_ptr; - offset <<= thisboard->mainshift; + if (board->is_pcie) + offset <<= 3; if (dev->mmio) writeb(val, dev->mmio + offset); @@ -175,30 +151,26 @@ static void dio200_write8(struct comedi_device *dev, unsigned int offset, outb(val, dev->iobase + offset); } -/* - * Read 32-bit register. - */ static unsigned int dio200_read32(struct comedi_device *dev, unsigned int offset) { - const struct dio200_board *thisboard = comedi_board(dev); + const struct dio200_board *board = dev->board_ptr; - offset <<= thisboard->mainshift; + if (board->is_pcie) + offset <<= 3; if (dev->mmio) return readl(dev->mmio + offset); return inl(dev->iobase + offset); } -/* - * Write 32-bit register. - */ -static void dio200_write32(struct comedi_device *dev, unsigned int offset, - unsigned int val) +static void dio200_write32(struct comedi_device *dev, + unsigned int offset, unsigned int val) { - const struct dio200_board *thisboard = comedi_board(dev); + const struct dio200_board *board = dev->board_ptr; - offset <<= thisboard->mainshift; + if (board->is_pcie) + offset <<= 3; if (dev->mmio) writel(val, dev->mmio + offset); @@ -206,18 +178,15 @@ static void dio200_write32(struct comedi_device *dev, unsigned int offset, outl(val, dev->iobase + offset); } -/* - * 'insn_bits' function for an 'INTERRUPT' subdevice. - */ -static int -dio200_subdev_intr_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dio200_subdev_intr_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_intr *subpriv = s->private; - if (layout->has_int_sce) { + if (board->has_int_sce) { /* Just read the interrupt status register. */ data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns; } else { @@ -228,54 +197,38 @@ dio200_subdev_intr_insn_bits(struct comedi_device *dev, return insn->n; } -/* - * Called to stop acquisition for an 'INTERRUPT' subdevice. - */ static void dio200_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_intr *subpriv = s->private; subpriv->active = false; subpriv->enabled_isns = 0; - if (layout->has_int_sce) + if (board->has_int_sce) dio200_write8(dev, subpriv->ofs, 0); } -/* - * Called to start acquisition for an 'INTERRUPT' subdevice. - */ -static int dio200_start_intr(struct comedi_device *dev, - struct comedi_subdevice *s) +static void dio200_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned int n; - unsigned isn_bits; - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_intr *subpriv = s->private; struct comedi_cmd *cmd = &s->async->cmd; - int retval = 0; + unsigned int n; + unsigned isn_bits; - if (cmd->stop_src == TRIG_COUNT && subpriv->stopcount == 0) { - /* An empty acquisition! */ - s->async->events |= COMEDI_CB_EOA; - subpriv->active = false; - retval = 1; - } else { - /* Determine interrupt sources to enable. */ - isn_bits = 0; - if (cmd->chanlist) { - for (n = 0; n < cmd->chanlist_len; n++) - isn_bits |= (1U << CR_CHAN(cmd->chanlist[n])); - } - isn_bits &= subpriv->valid_isns; - /* Enable interrupt sources. */ - subpriv->enabled_isns = isn_bits; - if (layout->has_int_sce) - dio200_write8(dev, subpriv->ofs, isn_bits); + /* Determine interrupt sources to enable. */ + isn_bits = 0; + if (cmd->chanlist) { + for (n = 0; n < cmd->chanlist_len; n++) + isn_bits |= (1U << CR_CHAN(cmd->chanlist[n])); } - - return retval; + isn_bits &= subpriv->valid_isns; + /* Enable interrupt sources. */ + subpriv->enabled_isns = isn_bits; + if (board->has_int_sce) + dio200_write8(dev, subpriv->ofs, isn_bits); } static int dio200_inttrig_start_intr(struct comedi_device *dev, @@ -285,7 +238,6 @@ static int dio200_inttrig_start_intr(struct comedi_device *dev, struct dio200_subdev_intr *subpriv = s->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; - int event = 0; if (trig_num != cmd->start_arg) return -EINVAL; @@ -293,13 +245,10 @@ static int dio200_inttrig_start_intr(struct comedi_device *dev, spin_lock_irqsave(&subpriv->spinlock, flags); s->async->inttrig = NULL; if (subpriv->active) - event = dio200_start_intr(dev, s); + dio200_start_intr(dev, s); spin_unlock_irqrestore(&subpriv->spinlock, flags); - if (event) - comedi_event(dev, s); - return 1; } @@ -340,14 +289,10 @@ static void dio200_read_scan_intr(struct comedi_device *dev, } } -/* - * This is called from the interrupt service routine to handle a read - * scan on an 'INTERRUPT' subdevice. - */ static int dio200_handle_read_intr(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_intr *subpriv = s->private; unsigned triggered; unsigned intstat; @@ -359,7 +304,7 @@ static int dio200_handle_read_intr(struct comedi_device *dev, spin_lock_irqsave(&subpriv->spinlock, flags); oldevents = s->async->events; - if (layout->has_int_sce) { + if (board->has_int_sce) { /* * Collect interrupt sources that have triggered and disable * them temporarily. Loop around until no extra interrupt @@ -393,7 +338,7 @@ static int dio200_handle_read_intr(struct comedi_device *dev, * Reenable them NOW to minimize the time they are disabled. */ cur_enabled = subpriv->enabled_isns; - if (layout->has_int_sce) + if (board->has_int_sce) dio200_write8(dev, subpriv->ofs, cur_enabled); if (subpriv->active) { @@ -417,9 +362,6 @@ static int dio200_handle_read_intr(struct comedi_device *dev, return (triggered != 0); } -/* - * 'cancel' function for an 'INTERRUPT' subdevice. - */ static int dio200_subdev_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -435,12 +377,9 @@ static int dio200_subdev_intr_cancel(struct comedi_device *dev, return 0; } -/* - * 'do_cmdtest' function for an 'INTERRUPT' subdevice. - */ -static int -dio200_subdev_intr_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int dio200_subdev_intr_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; @@ -472,16 +411,10 @@ dio200_subdev_intr_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } if (err) return 3; @@ -493,47 +426,34 @@ dio200_subdev_intr_cmdtest(struct comedi_device *dev, return 0; } -/* - * 'do_cmd' function for an 'INTERRUPT' subdevice. - */ static int dio200_subdev_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; struct dio200_subdev_intr *subpriv = s->private; unsigned long flags; - int event = 0; spin_lock_irqsave(&subpriv->spinlock, flags); - subpriv->active = true; - /* Set up end of acquisition. */ - if (cmd->stop_src == TRIG_COUNT) - subpriv->stopcount = cmd->stop_arg; - else /* TRIG_NONE */ - subpriv->stopcount = 0; + subpriv->active = true; + subpriv->stopcount = cmd->stop_arg; if (cmd->start_src == TRIG_INT) s->async->inttrig = dio200_inttrig_start_intr; else /* TRIG_NOW */ - event = dio200_start_intr(dev, s); + dio200_start_intr(dev, s); spin_unlock_irqrestore(&subpriv->spinlock, flags); - if (event) - comedi_event(dev, s); - return 0; } -/* - * This function initializes an 'INTERRUPT' subdevice. - */ -static int -dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int offset, unsigned valid_isns) +static int dio200_subdev_intr_init(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int offset, + unsigned valid_isns) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_intr *subpriv; subpriv = comedi_alloc_spriv(s, sizeof(*subpriv)); @@ -544,13 +464,13 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s, subpriv->valid_isns = valid_isns; spin_lock_init(&subpriv->spinlock); - if (layout->has_int_sce) + if (board->has_int_sce) /* Disable interrupt sources. */ dio200_write8(dev, subpriv->ofs, 0); s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - if (layout->has_int_sce) { + if (board->has_int_sce) { s->n_chan = DIO200_MAX_ISNS; s->len_chanlist = DIO200_MAX_ISNS; } else { @@ -568,35 +488,23 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* - * Interrupt service routine. - */ static irqreturn_t dio200_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct dio200_private *devpriv = dev->private; - struct comedi_subdevice *s; + struct comedi_subdevice *s = dev->read_subdev; int handled; if (!dev->attached) return IRQ_NONE; - if (devpriv->intr_sd >= 0) { - s = &dev->subdevices[devpriv->intr_sd]; - handled = dio200_handle_read_intr(dev, s); - } else { - handled = 0; - } + handled = dio200_handle_read_intr(dev, s); return IRQ_RETVAL(handled); } -/* - * Read an '8254' counter subdevice channel. - */ -static unsigned int -dio200_subdev_8254_read_chan(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int chan) +static unsigned int dio200_subdev_8254_read_chan(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) { struct dio200_subdev_8254 *subpriv = s->private; unsigned int val; @@ -610,13 +518,10 @@ dio200_subdev_8254_read_chan(struct comedi_device *dev, return val; } -/* - * Write an '8254' subdevice channel. - */ -static void -dio200_subdev_8254_write_chan(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int chan, - unsigned int count) +static void dio200_subdev_8254_write_chan(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int count) { struct dio200_subdev_8254 *subpriv = s->private; @@ -625,13 +530,10 @@ dio200_subdev_8254_write_chan(struct comedi_device *dev, dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff); } -/* - * Set mode of an '8254' subdevice channel. - */ -static void -dio200_subdev_8254_set_mode(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int chan, - unsigned int mode) +static void dio200_subdev_8254_set_mode(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int mode) { struct dio200_subdev_8254 *subpriv = s->private; unsigned int byte; @@ -642,12 +544,9 @@ dio200_subdev_8254_set_mode(struct comedi_device *dev, dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte); } -/* - * Read status byte of an '8254' counter subdevice channel. - */ -static unsigned int -dio200_subdev_8254_status(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int chan) +static unsigned int dio200_subdev_8254_status(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) { struct dio200_subdev_8254 *subpriv = s->private; @@ -658,12 +557,10 @@ dio200_subdev_8254_status(struct comedi_device *dev, return dio200_read8(dev, subpriv->ofs + chan); } -/* - * Handle 'insn_read' for an '8254' counter subdevice. - */ -static int -dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dio200_subdev_8254_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct dio200_subdev_8254 *subpriv = s->private; int chan = CR_CHAN(insn->chanspec); @@ -678,12 +575,10 @@ dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -/* - * Handle 'insn_write' for an '8254' counter subdevice. - */ -static int -dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dio200_subdev_8254_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct dio200_subdev_8254 *subpriv = s->private; int chan = CR_CHAN(insn->chanspec); @@ -698,24 +593,20 @@ dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -/* - * Set gate source for an '8254' counter subdevice channel. - */ -static int -dio200_subdev_8254_set_gate_src(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int counter_number, - unsigned int gate_src) +static int dio200_subdev_8254_set_gate_src(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int counter_number, + unsigned int gate_src) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_8254 *subpriv = s->private; unsigned char byte; - if (!layout->has_clk_gat_sce) + if (!board->has_clk_gat_sce) return -1; if (counter_number > 2) return -1; - if (gate_src > (layout->has_enhancements ? 31 : 7)) + if (gate_src > (board->is_pcie ? 31 : 7)) return -1; subpriv->gate_src[counter_number] = gate_src; @@ -725,18 +616,14 @@ dio200_subdev_8254_set_gate_src(struct comedi_device *dev, return 0; } -/* - * Get gate source for an '8254' counter subdevice channel. - */ -static int -dio200_subdev_8254_get_gate_src(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int counter_number) +static int dio200_subdev_8254_get_gate_src(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int counter_number) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_8254 *subpriv = s->private; - if (!layout->has_clk_gat_sce) + if (!board->has_clk_gat_sce) return -1; if (counter_number > 2) return -1; @@ -744,24 +631,20 @@ dio200_subdev_8254_get_gate_src(struct comedi_device *dev, return subpriv->gate_src[counter_number]; } -/* - * Set clock source for an '8254' counter subdevice channel. - */ -static int -dio200_subdev_8254_set_clock_src(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int counter_number, - unsigned int clock_src) +static int dio200_subdev_8254_set_clock_src(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int counter_number, + unsigned int clock_src) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_8254 *subpriv = s->private; unsigned char byte; - if (!layout->has_clk_gat_sce) + if (!board->has_clk_gat_sce) return -1; if (counter_number > 2) return -1; - if (clock_src > (layout->has_enhancements ? 31 : 7)) + if (clock_src > (board->is_pcie ? 31 : 7)) return -1; subpriv->clock_src[counter_number] = clock_src; @@ -771,20 +654,16 @@ dio200_subdev_8254_set_clock_src(struct comedi_device *dev, return 0; } -/* - * Get clock source for an '8254' counter subdevice channel. - */ -static int -dio200_subdev_8254_get_clock_src(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int counter_number, - unsigned int *period_ns) +static int dio200_subdev_8254_get_clock_src(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int counter_number, + unsigned int *period_ns) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_8254 *subpriv = s->private; unsigned clock_src; - if (!layout->has_clk_gat_sce) + if (!board->has_clk_gat_sce) return -1; if (counter_number > 2) return -1; @@ -794,12 +673,10 @@ dio200_subdev_8254_get_clock_src(struct comedi_device *dev, return clock_src; } -/* - * Handle 'insn_config' for an '8254' counter subdevice. - */ -static int -dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dio200_subdev_8254_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct dio200_subdev_8254 *subpriv = s->private; int ret = 0; @@ -851,14 +728,11 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s, return ret < 0 ? ret : insn->n; } -/* - * This function initializes an '8254' counter subdevice. - */ -static int -dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int offset) +static int dio200_subdev_8254_init(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int offset) { - const struct dio200_layout *layout = dio200_dev_layout(dev); + const struct dio200_board *board = dev->board_ptr; struct dio200_subdev_8254 *subpriv; unsigned int chan; @@ -876,7 +750,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, spin_lock_init(&subpriv->spinlock); subpriv->ofs = offset; - if (layout->has_clk_gat_sce) { + if (board->has_clk_gat_sce) { /* Derive CLK_SCE and GAT_SCE register offsets from * 8254 offset. */ subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3); @@ -888,7 +762,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, for (chan = 0; chan < 3; chan++) { dio200_subdev_8254_set_mode(dev, s, chan, I8254_MODE0 | I8254_BINARY); - if (layout->has_clk_gat_sce) { + if (board->has_clk_gat_sce) { /* Gate source 0 is VCC (logic 1). */ dio200_subdev_8254_set_gate_src(dev, s, chan, 0); /* Clock source 0 is the dedicated clock input. */ @@ -899,26 +773,23 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* - * This function sets I/O directions for an '8255' DIO subdevice. - */ static void dio200_subdev_8255_set_dir(struct comedi_device *dev, struct comedi_subdevice *s) { struct dio200_subdev_8255 *subpriv = s->private; int config; - config = CR_CW; + config = I8255_CTRL_CW; /* 1 in io_bits indicates output, 1 in config indicates input */ if (!(s->io_bits & 0x0000ff)) - config |= CR_A_IO; + config |= I8255_CTRL_A_IO; if (!(s->io_bits & 0x00ff00)) - config |= CR_B_IO; + config |= I8255_CTRL_B_IO; if (!(s->io_bits & 0x0f0000)) - config |= CR_C_LO_IO; + config |= I8255_CTRL_C_LO_IO; if (!(s->io_bits & 0xf00000)) - config |= CR_C_HI_IO; - dio200_write8(dev, subpriv->ofs + 3, config); + config |= I8255_CTRL_C_HI_IO; + dio200_write8(dev, subpriv->ofs + I8255_CTRL_REG, config); } static int dio200_subdev_8255_bits(struct comedi_device *dev, @@ -933,27 +804,25 @@ static int dio200_subdev_8255_bits(struct comedi_device *dev, mask = comedi_dio_update_state(s, data); if (mask) { if (mask & 0xff) - dio200_write8(dev, subpriv->ofs, s->state & 0xff); + dio200_write8(dev, subpriv->ofs + I8255_DATA_A_REG, + s->state & 0xff); if (mask & 0xff00) - dio200_write8(dev, subpriv->ofs + 1, + dio200_write8(dev, subpriv->ofs + I8255_DATA_B_REG, (s->state >> 8) & 0xff); if (mask & 0xff0000) - dio200_write8(dev, subpriv->ofs + 2, + dio200_write8(dev, subpriv->ofs + I8255_DATA_C_REG, (s->state >> 16) & 0xff); } - val = dio200_read8(dev, subpriv->ofs); - val |= dio200_read8(dev, subpriv->ofs + 1) << 8; - val |= dio200_read8(dev, subpriv->ofs + 2) << 16; + val = dio200_read8(dev, subpriv->ofs + I8255_DATA_A_REG); + val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_B_REG) << 8; + val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_C_REG) << 16; data[1] = val; return insn->n; } -/* - * Handle 'insn_config' for an '8255' DIO subdevice. - */ static int dio200_subdev_8255_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -981,11 +850,6 @@ static int dio200_subdev_8255_config(struct comedi_device *dev, return insn->n; } -/* - * This function initializes an '8255' DIO subdevice. - * - * offset is the offset to the 8255 chip. - */ static int dio200_subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int offset) @@ -1009,9 +873,6 @@ static int dio200_subdev_8255_init(struct comedi_device *dev, return 0; } -/* - * Handle 'insn_read' for a timer subdevice. - */ static int dio200_subdev_timer_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -1024,9 +885,6 @@ static int dio200_subdev_timer_read(struct comedi_device *dev, return n; } -/* - * Reset timer subdevice. - */ static void dio200_subdev_timer_reset(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1037,9 +895,6 @@ static void dio200_subdev_timer_reset(struct comedi_device *dev, dio200_write32(dev, DIO200_TS_CONFIG, clock); } -/* - * Get timer subdevice clock source and period. - */ static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *src, @@ -1053,9 +908,6 @@ static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev, ts_clock_period[clk] : 0; } -/* - * Set timer subdevice clock source. - */ static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int src) @@ -1066,9 +918,6 @@ static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev, return 0; } -/* - * Handle 'insn_config' for a timer subdevice. - */ static int dio200_subdev_timer_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -1095,23 +944,6 @@ static int dio200_subdev_timer_config(struct comedi_device *dev, return ret < 0 ? ret : insn->n; } -/* - * This function initializes a timer subdevice. - * - * Uses the timestamp timer registers. There is only one timestamp timer. - */ -static int dio200_subdev_timer_init(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = 1; - s->maxdata = 0xFFFFFFFF; - s->insn_read = dio200_subdev_timer_read; - s->insn_config = dio200_subdev_timer_config; - return 0; -} - void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val) { dio200_write8(dev, DIO200_ENHANCE, val); @@ -1121,65 +953,60 @@ EXPORT_SYMBOL_GPL(amplc_dio200_set_enhance); int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq, unsigned long req_irq_flags) { - const struct dio200_board *thisboard = comedi_board(dev); - struct dio200_private *devpriv = dev->private; - const struct dio200_layout *layout = dio200_board_layout(thisboard); + const struct dio200_board *board = dev->board_ptr; struct comedi_subdevice *s; - int sdx; unsigned int n; int ret; - devpriv->intr_sd = -1; - - ret = comedi_alloc_subdevices(dev, layout->n_subdevs); + ret = comedi_alloc_subdevices(dev, board->n_subdevs); if (ret) return ret; for (n = 0; n < dev->n_subdevices; n++) { s = &dev->subdevices[n]; - switch (layout->sdtype[n]) { + switch (board->sdtype[n]) { case sd_8254: /* counter subdevice (8254) */ ret = dio200_subdev_8254_init(dev, s, - layout->sdinfo[n]); + board->sdinfo[n]); if (ret < 0) return ret; break; case sd_8255: /* digital i/o subdevice (8255) */ ret = dio200_subdev_8255_init(dev, s, - layout->sdinfo[n]); + board->sdinfo[n]); if (ret < 0) return ret; break; case sd_intr: /* 'INTERRUPT' subdevice */ - if (irq) { + if (irq && !dev->read_subdev) { ret = dio200_subdev_intr_init(dev, s, DIO200_INT_SCE, - layout->sdinfo[n] - ); + board->sdinfo[n]); if (ret < 0) return ret; - devpriv->intr_sd = n; + dev->read_subdev = s; } else { s->type = COMEDI_SUBD_UNUSED; } break; case sd_timer: - ret = dio200_subdev_timer_init(dev, s); - if (ret < 0) - return ret; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = 1; + s->maxdata = 0xffffffff; + s->insn_read = dio200_subdev_timer_read; + s->insn_config = dio200_subdev_timer_config; break; default: s->type = COMEDI_SUBD_UNUSED; break; } } - sdx = devpriv->intr_sd; - if (sdx >= 0 && sdx < dev->n_subdevices) - dev->read_subdev = &dev->subdevices[sdx]; - if (irq) { + + if (irq && dev->read_subdev) { if (request_irq(irq, dio200_interrupt, req_irq_flags, dev->board_name, dev) >= 0) { dev->irq = irq; @@ -1193,15 +1020,6 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq, } EXPORT_SYMBOL_GPL(amplc_dio200_common_attach); -void amplc_dio200_common_detach(struct comedi_device *dev) -{ - if (dev->irq) { - free_irq(dev->irq, dev); - dev->irq = 0; - } -} -EXPORT_SYMBOL_GPL(amplc_dio200_common_detach); - static int __init amplc_dio200_common_init(void) { return 0; diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c index fbf05687347f..b83d1f5a8fb9 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_pci.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c @@ -242,80 +242,70 @@ enum dio200_pci_model { static const struct dio200_board dio200_pci_boards[] = { [pci215_model] = { - .name = "pci215", - .bustype = pci_bustype, - .mainbar = 2, - .mainsize = DIO200_IO_SIZE, - .layout = { - .n_subdevs = 5, - .sdtype = {sd_8255, sd_8255, sd_8254, sd_8254, sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F}, - .has_int_sce = true, - .has_clk_gat_sce = true, + .name = "pci215", + .mainbar = 2, + .n_subdevs = 5, + .sdtype = { + sd_8255, sd_8255, sd_8254, sd_8254, sd_intr }, + .sdinfo = { 0x00, 0x08, 0x10, 0x14, 0x3f }, + .has_int_sce = true, + .has_clk_gat_sce = true, }, [pci272_model] = { - .name = "pci272", - .bustype = pci_bustype, - .mainbar = 2, - .mainsize = DIO200_IO_SIZE, - .layout = { - .n_subdevs = 4, - .sdtype = {sd_8255, sd_8255, sd_8255, sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x3F}, - .has_int_sce = true, + .name = "pci272", + .mainbar = 2, + .n_subdevs = 4, + .sdtype = { + sd_8255, sd_8255, sd_8255, sd_intr }, + .sdinfo = { 0x00, 0x08, 0x10, 0x3f }, + .has_int_sce = true, }, [pcie215_model] = { - .name = "pcie215", - .bustype = pci_bustype, - .mainbar = 1, - .mainshift = 3, - .mainsize = DIO200_PCIE_IO_SIZE, - .layout = { - .n_subdevs = 8, - .sdtype = {sd_8255, sd_none, sd_8255, sd_none, - sd_8254, sd_8254, sd_timer, sd_intr}, - .sdinfo = {0x00, 0x00, 0x08, 0x00, - 0x10, 0x14, 0x00, 0x3F}, - .has_int_sce = true, - .has_clk_gat_sce = true, - .has_enhancements = true, + .name = "pcie215", + .mainbar = 1, + .n_subdevs = 8, + .sdtype = { + sd_8255, sd_none, sd_8255, sd_none, + sd_8254, sd_8254, sd_timer, sd_intr }, + .sdinfo = { + 0x00, 0x00, 0x08, 0x00, 0x10, 0x14, 0x00, 0x3f + }, + .has_int_sce = true, + .has_clk_gat_sce = true, + .is_pcie = true, }, [pcie236_model] = { - .name = "pcie236", - .bustype = pci_bustype, - .mainbar = 1, - .mainshift = 3, - .mainsize = DIO200_PCIE_IO_SIZE, - .layout = { - .n_subdevs = 8, - .sdtype = {sd_8255, sd_none, sd_none, sd_none, - sd_8254, sd_8254, sd_timer, sd_intr}, - .sdinfo = {0x00, 0x00, 0x00, 0x00, - 0x10, 0x14, 0x00, 0x3F}, - .has_int_sce = true, - .has_clk_gat_sce = true, - .has_enhancements = true, + .name = "pcie236", + .mainbar = 1, + .n_subdevs = 8, + .sdtype = { + sd_8255, sd_none, sd_none, sd_none, + sd_8254, sd_8254, sd_timer, sd_intr + }, + .sdinfo = { + 0x00, 0x00, 0x00, 0x00, 0x10, 0x14, 0x00, 0x3f }, + .has_int_sce = true, + .has_clk_gat_sce = true, + .is_pcie = true, }, [pcie296_model] = { - .name = "pcie296", - .bustype = pci_bustype, - .mainbar = 1, - .mainshift = 3, - .mainsize = DIO200_PCIE_IO_SIZE, - .layout = { - .n_subdevs = 8, - .sdtype = {sd_8255, sd_8255, sd_8255, sd_8255, - sd_8254, sd_8254, sd_timer, sd_intr}, - .sdinfo = {0x00, 0x04, 0x08, 0x0C, - 0x10, 0x14, 0x00, 0x3F}, - .has_int_sce = true, - .has_clk_gat_sce = true, - .has_enhancements = true, + .name = "pcie296", + .mainbar = 1, + .n_subdevs = 8, + .sdtype = { + sd_8255, sd_8255, sd_8255, sd_8255, + sd_8254, sd_8254, sd_timer, sd_intr + }, + .sdinfo = { + 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x00, 0x3f }, + .has_int_sce = true, + .has_clk_gat_sce = true, + .is_pcie = true, }, }; @@ -358,34 +348,25 @@ static int dio200_pci_auto_attach(struct comedi_device *dev, unsigned long context_model) { struct pci_dev *pci_dev = comedi_to_pci_dev(dev); - const struct dio200_board *thisboard = NULL; - struct dio200_private *devpriv; + const struct dio200_board *board = NULL; unsigned int bar; int ret; if (context_model < ARRAY_SIZE(dio200_pci_boards)) - thisboard = &dio200_pci_boards[context_model]; - if (!thisboard) + board = &dio200_pci_boards[context_model]; + if (!board) return -EINVAL; - dev->board_ptr = thisboard; - dev->board_name = thisboard->name; + dev->board_ptr = board; + dev->board_name = board->name; dev_info(dev->class_dev, "%s: attach pci %s (%s)\n", dev->driver->driver_name, pci_name(pci_dev), dev->board_name); - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_pci_enable(dev); if (ret) return ret; - bar = thisboard->mainbar; - if (pci_resource_len(pci_dev, bar) < thisboard->mainsize) { - dev_err(dev->class_dev, "error! PCI region size too small!\n"); - return -EINVAL; - } + bar = board->mainbar; if (pci_resource_flags(pci_dev, bar) & IORESOURCE_MEM) { dev->mmio = pci_ioremap_bar(pci_dev, bar); if (!dev->mmio) { @@ -396,33 +377,21 @@ static int dio200_pci_auto_attach(struct comedi_device *dev, } else { dev->iobase = pci_resource_start(pci_dev, bar); } - switch (context_model) { - case pcie215_model: - case pcie236_model: - case pcie296_model: + + if (board->is_pcie) { ret = dio200_pcie_board_setup(dev); if (ret < 0) return ret; - break; - default: - break; } - return amplc_dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED); -} -static void dio200_pci_detach(struct comedi_device *dev) -{ - amplc_dio200_common_detach(dev); - if (dev->mmio) - iounmap(dev->mmio); - comedi_pci_disable(dev); + return amplc_dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED); } static struct comedi_driver dio200_pci_comedi_driver = { - .driver_name = "amplc_dio200_pci", - .module = THIS_MODULE, - .auto_attach = dio200_pci_auto_attach, - .detach = dio200_pci_detach, + .driver_name = "amplc_dio200_pci", + .module = THIS_MODULE, + .auto_attach = dio200_pci_auto_attach, + .detach = comedi_pci_detach, }; static const struct pci_device_id dio200_pci_table[] = { @@ -443,10 +412,10 @@ static int dio200_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) } static struct pci_driver dio200_pci_pci_driver = { - .name = "amplc_dio200_pci", - .id_table = dio200_pci_table, - .probe = dio200_pci_probe, - .remove = comedi_pci_auto_unconfig, + .name = "amplc_dio200_pci", + .id_table = dio200_pci_table, + .probe = dio200_pci_probe, + .remove = comedi_pci_auto_unconfig, }; module_comedi_pci_driver(dio200_pci_comedi_driver, dio200_pci_pci_driver); diff --git a/drivers/staging/comedi/drivers/amplc_pc236_common.c b/drivers/staging/comedi/drivers/amplc_pc236_common.c index 18e237cca419..963c5d868b81 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236_common.c +++ b/drivers/staging/comedi/drivers/amplc_pc236_common.c @@ -29,7 +29,7 @@ static void pc236_intr_update(struct comedi_device *dev, bool enable) { - const struct pc236_board *thisboard = comedi_board(dev); + const struct pc236_board *thisboard = dev->board_ptr; struct pc236_private *devpriv = dev->private; unsigned long flags; @@ -49,7 +49,7 @@ static void pc236_intr_update(struct comedi_device *dev, bool enable) */ static bool pc236_intr_check(struct comedi_device *dev) { - const struct pc236_board *thisboard = comedi_board(dev); + const struct pc236_board *thisboard = dev->board_ptr; struct pc236_private *devpriv = dev->private; bool retval = false; unsigned long flags; @@ -94,9 +94,6 @@ static int pc236_intr_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check it arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); @@ -108,10 +105,9 @@ static int pc236_intr_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: ignored */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } @@ -160,7 +156,7 @@ int amplc_pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s = &dev->subdevices[0]; /* digital i/o subdevice (8255) */ - ret = subdev_8255_init(dev, s, NULL, iobase); + ret = subdev_8255_init(dev, s, NULL, 0x00); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 45aba1f950fc..3bbbb57f19d6 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -1,102 +1,106 @@ /* - comedi/drivers/amplc_pci224.c - Driver for Amplicon PCI224 and PCI234 AO boards. - - Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/> - - 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. + * comedi/drivers/amplc_pci224.c + * Driver for Amplicon PCI224 and PCI234 AO boards. + * + * Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/> + * + * 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. + */ - 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: amplc_pci224 -Description: Amplicon PCI224, PCI234 -Author: Ian Abbott <abbotti@mev.co.uk> -Devices: [Amplicon] PCI224 (amplc_pci224 or pci224), - PCI234 (amplc_pci224 or pci234) -Updated: Wed, 22 Oct 2008 12:25:08 +0100 -Status: works, but see caveats - -Supports: - - - ao_insn read/write - - ao_do_cmd mode with the following sources: - - - start_src TRIG_INT TRIG_EXT - - scan_begin_src TRIG_TIMER TRIG_EXT - - convert_src TRIG_NOW - - scan_end_src TRIG_COUNT - - stop_src TRIG_COUNT TRIG_EXT TRIG_NONE - - The channel list must contain at least one channel with no repeated - channels. The scan end count must equal the number of channels in - the channel list. - - There is only one external trigger source so only one of start_src, - scan_begin_src or stop_src may use TRIG_EXT. - -Configuration options - PCI224: - [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. - [2] - Select available ranges according to jumper LK1. All channels - are set to the same range: - 0=Jumper position 1-2 (factory default), 4 software-selectable - internal voltage references, giving 4 bipolar and 4 unipolar - ranges: - [-10V,+10V], [-5V,+5V], [-2.5V,+2.5V], [-1.25V,+1.25V], - [0,+10V], [0,+5V], [0,+2.5V], [0,1.25V]. - 1=Jumper position 2-3, 1 external voltage reference, giving - 1 bipolar and 1 unipolar range: - [-Vext,+Vext], [0,+Vext]. - -Configuration options - PCI234: - [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. - [2] - Select internal or external voltage reference according to - jumper LK1. This affects all channels: - 0=Jumper position 1-2 (factory default), Vref=5V internal. - 1=Jumper position 2-3, Vref=Vext external. - [3] - Select channel 0 range according to jumper LK2: - 0=Jumper position 2-3 (factory default), range [-2*Vref,+2*Vref] - (10V bipolar when options[2]=0). - 1=Jumper position 1-2, range [-Vref,+Vref] - (5V bipolar when options[2]=0). - [4] - Select channel 1 range according to jumper LK3: cf. options[3]. - [5] - Select channel 2 range according to jumper LK4: cf. options[3]. - [6] - Select channel 3 range according to jumper LK5: cf. options[3]. - -Passing a zero for an option is the same as leaving it unspecified. - -Caveats: - - 1) All channels on the PCI224 share the same range. Any change to the - range as a result of insn_write or a streaming command will affect - the output voltages of all channels, including those not specified - by the instruction or command. - - 2) For the analog output command, the first scan may be triggered - falsely at the start of acquisition. This occurs when the DAC scan - trigger source is switched from 'none' to 'timer' (scan_begin_src = - TRIG_TIMER) or 'external' (scan_begin_src == TRIG_EXT) at the start - of acquisition and the trigger source is at logic level 1 at the - time of the switch. This is very likely for TRIG_TIMER. For - TRIG_EXT, it depends on the state of the external line and whether - the CR_INVERT flag has been set. The remaining scans are triggered - correctly. -*/ + * Driver: amplc_pci224 + * Description: Amplicon PCI224, PCI234 + * Author: Ian Abbott <abbotti@mev.co.uk> + * Devices: [Amplicon] PCI224 (amplc_pci224), PCI234 + * Updated: Thu, 31 Jul 2014 11:08:03 +0000 + * Status: works, but see caveats + * + * Supports: + * + * - ao_insn read/write + * - ao_do_cmd mode with the following sources: + * + * - start_src TRIG_INT TRIG_EXT + * - scan_begin_src TRIG_TIMER TRIG_EXT + * - convert_src TRIG_NOW + * - scan_end_src TRIG_COUNT + * - stop_src TRIG_COUNT TRIG_EXT TRIG_NONE + * + * The channel list must contain at least one channel with no repeated + * channels. The scan end count must equal the number of channels in + * the channel list. + * + * There is only one external trigger source so only one of start_src, + * scan_begin_src or stop_src may use TRIG_EXT. + * + * Configuration options: + * none + * + * Manual configuration of PCI cards is not supported; they are configured + * automatically. + * + * Output range selection - PCI224: + * + * Output ranges on PCI224 are partly software-selectable and partly + * hardware-selectable according to jumper LK1. All channels are set + * to the same range: + * + * - LK1 position 1-2 (factory default) corresponds to the following + * comedi ranges: + * + * 0: [-10V,+10V]; 1: [-5V,+5V]; 2: [-2.5V,+2.5V], 3: [-1.25V,+1.25V], + * 4: [0,+10V], 5: [0,+5V], 6: [0,+2.5V], 7: [0,+1.25V] + * + * - LK1 position 2-3 corresponds to the following Comedi ranges, using + * an external voltage reference: + * + * 0: [-Vext,+Vext], + * 1: [0,+Vext] + * + * Output range selection - PCI234: + * + * Output ranges on PCI234 are hardware-selectable according to jumper + * LK1 which affects all channels, and jumpers LK2, LK3, LK4 and LK5 + * which affect channels 0, 1, 2 and 3 individually. LK1 chooses between + * an internal 5V reference and an external voltage reference (Vext). + * LK2/3/4/5 choose (per channel) to double the reference or not according + * to the following table: + * + * LK1 position LK2/3/4/5 pos Comedi range + * ------------- ------------- -------------- + * 2-3 (factory) 1-2 (factory) 0: [-10V,+10V] + * 2-3 (factory) 2-3 1: [-5V,+5V] + * 1-2 1-2 (factory) 2: [-2*Vext,+2*Vext] + * 1-2 2-3 3: [-Vext,+Vext] + * + * Caveats: + * + * 1) All channels on the PCI224 share the same range. Any change to the + * range as a result of insn_write or a streaming command will affect + * the output voltages of all channels, including those not specified + * by the instruction or command. + * + * 2) For the analog output command, the first scan may be triggered + * falsely at the start of acquisition. This occurs when the DAC scan + * trigger source is switched from 'none' to 'timer' (scan_begin_src = + * TRIG_TIMER) or 'external' (scan_begin_src == TRIG_EXT) at the start + * of acquisition and the trigger source is at logic level 1 at the + * time of the switch. This is very likely for TRIG_TIMER. For + * TRIG_EXT, it depends on the state of the external line and whether + * the CR_INVERT flag has been set. The remaining scans are triggered + * correctly. + */ #include <linux/module.h> #include <linux/pci.h> @@ -109,13 +113,6 @@ Caveats: #include "8253.h" /* - * PCI IDs. - */ -#define PCI_DEVICE_ID_AMPLICON_PCI224 0x0007 -#define PCI_DEVICE_ID_AMPLICON_PCI234 0x0008 -#define PCI_DEVICE_ID_INVALID 0xffff - -/* * PCI224/234 i/o space 1 (PCIBAR2) registers. */ #define PCI224_Z2_CT0 0x14 /* 82C54 counter/timer 0 */ @@ -261,9 +258,17 @@ Caveats: * Range tables. */ -/* The software selectable internal ranges for PCI224 (option[2] == 0). */ -static const struct comedi_lrange range_pci224_internal = { - 8, { +/* + * The ranges for PCI224. + * + * These are partly hardware-selectable by jumper LK1 and partly + * software-selectable. + * + * All channels share the same hardware range. + */ +static const struct comedi_lrange range_pci224 = { + 10, { + /* jumper LK1 in position 1-2 (factory default) */ BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.5), @@ -271,11 +276,15 @@ static const struct comedi_lrange range_pci224_internal = { UNI_RANGE(10), UNI_RANGE(5), UNI_RANGE(2.5), - UNI_RANGE(1.25) + UNI_RANGE(1.25), + /* jumper LK1 in position 2-3 */ + RANGE_ext(-1, 1), /* bipolar [-Vext,+Vext] */ + RANGE_ext(0, 1), /* unipolar [0,+Vext] */ } }; -static const unsigned short hwrange_pci224_internal[8] = { +static const unsigned short hwrange_pci224[10] = { + /* jumper LK1 in position 1-2 (factory default) */ PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_10, PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_5, PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_2_5, @@ -284,87 +293,87 @@ static const unsigned short hwrange_pci224_internal[8] = { PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_5, PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_2_5, PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_1_25, -}; - -/* The software selectable external ranges for PCI224 (option[2] == 1). */ -static const struct comedi_lrange range_pci224_external = { - 2, { - RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */ - RANGE_ext(0, 1) /* unipolar [0,+Vref] */ - } -}; - -static const unsigned short hwrange_pci224_external[2] = { + /* jumper LK1 in position 2-3 */ PCI224_DACCON_POLAR_BI, PCI224_DACCON_POLAR_UNI, }; -/* The hardware selectable Vref*2 external range for PCI234 - * (option[2] == 1, option[3+n] == 0). */ -static const struct comedi_lrange range_pci234_ext2 = { - 1, { - RANGE_ext(-2, 2) - } +/* Used to check all channels set to the same range on PCI224. */ +static const unsigned char range_check_pci224[10] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, }; -/* The hardware selectable Vref external range for PCI234 - * (option[2] == 1, option[3+n] == 1). */ -static const struct comedi_lrange range_pci234_ext = { - 1, { - RANGE_ext(-1, 1) +/* + * The ranges for PCI234. + * + * These are all hardware-selectable by jumper LK1 affecting all channels, + * and jumpers LK2, LK3, LK4 and LK5 affecting channels 0, 1, 2 and 3 + * individually. + */ +static const struct comedi_lrange range_pci234 = { + 4, { + /* LK1: 1-2 (fact def), LK2/3/4/5: 2-3 (fac def) */ + BIP_RANGE(10), + /* LK1: 1-2 (fact def), LK2/3/4/5: 1-2 */ + BIP_RANGE(5), + /* LK1: 2-3, LK2/3/4/5: 2-3 (fac def) */ + RANGE_ext(-2, 2), /* bipolar [-2*Vext,+2*Vext] */ + /* LK1: 2-3, LK2/3/4/5: 1-2 */ + RANGE_ext(-1, 1), /* bipolar [-Vext,+Vext] */ } }; -/* This serves for all the PCI234 ranges. */ -static const unsigned short hwrange_pci234[1] = { - PCI224_DACCON_POLAR_BI, /* bipolar - hardware ignores it! */ +/* N.B. PCI234 ignores the polarity bit, but software uses it. */ +static const unsigned short hwrange_pci234[4] = { + PCI224_DACCON_POLAR_BI, + PCI224_DACCON_POLAR_BI, + PCI224_DACCON_POLAR_BI, + PCI224_DACCON_POLAR_BI, +}; + +/* Used to check all channels use same LK1 setting on PCI234. */ +static const unsigned char range_check_pci234[4] = { + 0, 0, 1, 1, }; /* * Board descriptions. */ -enum pci224_model { any_model, pci224_model, pci234_model }; +enum pci224_model { pci224_model, pci234_model }; struct pci224_board { const char *name; - unsigned short devid; - enum pci224_model model; unsigned int ao_chans; unsigned int ao_bits; + const struct comedi_lrange *ao_range; + const unsigned short *ao_hwrange; + const unsigned char *ao_range_check; }; static const struct pci224_board pci224_boards[] = { - { - .name = "pci224", - .devid = PCI_DEVICE_ID_AMPLICON_PCI224, - .model = pci224_model, - .ao_chans = 16, - .ao_bits = 12, - }, - { - .name = "pci234", - .devid = PCI_DEVICE_ID_AMPLICON_PCI234, - .model = pci234_model, - .ao_chans = 4, - .ao_bits = 16, - }, - { - .name = "amplc_pci224", - .devid = PCI_DEVICE_ID_INVALID, - .model = any_model, /* wildcard */ - }, + [pci224_model] = { + .name = "pci224", + .ao_chans = 16, + .ao_bits = 12, + .ao_range = &range_pci224, + .ao_hwrange = &hwrange_pci224[0], + .ao_range_check = &range_check_pci224[0], + }, + [pci234_model] = { + .name = "pci234", + .ao_chans = 4, + .ao_bits = 16, + .ao_range = &range_pci234, + .ao_hwrange = &hwrange_pci234[0], + .ao_range_check = &range_check_pci234[0], + }, }; -/* 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 struct comedi_device struct. */ struct pci224_private { - const unsigned short *hwrange; unsigned long iobase1; unsigned long state; - spinlock_t ao_spinlock; - unsigned int *ao_readback; + spinlock_t ao_spinlock; /* spinlock for AO command handling */ unsigned short *ao_scan_vals; unsigned char *ao_scan_order; int intr_cpuid; @@ -384,18 +393,16 @@ static void pci224_ao_set_data(struct comedi_device *dev, int chan, int range, unsigned int data) { - const struct pci224_board *thisboard = comedi_board(dev); + const struct pci224_board *thisboard = dev->board_ptr; struct pci224_private *devpriv = dev->private; unsigned short mangled; - /* Store unmangled data for readback. */ - devpriv->ao_readback[chan] = data; /* Enable the channel. */ outw(1 << chan, dev->iobase + PCI224_DACCEN); /* Set range and reset FIFO. */ - devpriv->daccon = COMBINE(devpriv->daccon, devpriv->hwrange[range], - (PCI224_DACCON_POLAR_MASK | - PCI224_DACCON_VREF_MASK)); + devpriv->daccon = COMBINE(devpriv->daccon, thisboard->ao_hwrange[range], + PCI224_DACCON_POLAR_MASK | + PCI224_DACCON_VREF_MASK); outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); /* @@ -414,51 +421,23 @@ pci224_ao_set_data(struct comedi_device *dev, int chan, int range, inw(dev->iobase + PCI224_SOFTTRIG); } -/* - * 'insn_write' function for AO subdevice. - */ -static int -pci224_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pci224_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = s->readback[chan]; int i; - int chan, range; - - /* Unpack channel and range. */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - - /* 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++) - pci224_ao_set_data(dev, chan, range, data[i]); - - return i; -} - -/* - * 'insn_read' function for AO subdevice. - * - * N.B. The value read will not be valid if the DAC channel has - * never been written successfully since the device was attached - * or since the channel has been used by an AO streaming write - * command. - */ -static int -pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pci224_private *devpriv = dev->private; - int i; - int chan; - - chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + for (i = 0; i < insn->n; i++) { + val = data[i]; + pci224_ao_set_data(dev, chan, range, val); + } + s->readback[chan] = val; - return i; + return insn->n; } /* @@ -496,11 +475,10 @@ static void pci224_ao_stop(struct comedi_device *dev, spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); /* Reconfigure DAC for insn_write usage. */ outw(0, dev->iobase + PCI224_DACCEN); /* Disable channels. */ - devpriv->daccon = COMBINE(devpriv->daccon, - PCI224_DACCON_TRIG_SW | - PCI224_DACCON_FIFOINTR_EMPTY, - PCI224_DACCON_TRIG_MASK | - PCI224_DACCON_FIFOINTR_MASK); + devpriv->daccon = + COMBINE(devpriv->daccon, + PCI224_DACCON_TRIG_SW | PCI224_DACCON_FIFOINTR_EMPTY, + PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK); outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); } @@ -516,21 +494,16 @@ static void pci224_ao_start(struct comedi_device *dev, unsigned long flags; set_bit(AO_CMD_STARTED, &devpriv->state); - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { - /* An empty acquisition! */ - s->async->events |= COMEDI_CB_EOA; - cfc_handle_events(dev, s); - } else { - /* Enable interrupts. */ - spin_lock_irqsave(&devpriv->ao_spinlock, flags); - if (cmd->stop_src == TRIG_EXT) - devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC; - else - devpriv->intsce = PCI224_INTR_DAC; - outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); - spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - } + /* Enable interrupts. */ + spin_lock_irqsave(&devpriv->ao_spinlock, flags); + if (cmd->stop_src == TRIG_EXT) + devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC; + else + devpriv->intsce = PCI224_INTR_DAC; + + outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); } /* @@ -553,7 +526,6 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, /* Fixed number of scans. */ if (num_scans > devpriv->ao_stop_count) num_scans = devpriv->ao_stop_count; - } /* Determine how much room is in the FIFO (in samples). */ @@ -561,7 +533,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, switch (dacstat & PCI224_DACCON_FIFOFL_MASK) { case PCI224_DACCON_FIFOFL_EMPTY: room = PCI224_FIFO_ROOM_EMPTY; - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && + devpriv->ao_stop_count == 0) { /* FIFO empty at end of counted acquisition. */ s->async->events |= COMEDI_CB_EOA; cfc_handle_events(dev, s); @@ -639,10 +612,9 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, trig = PCI224_DACCON_TRIG_EXTN; else trig = PCI224_DACCON_TRIG_EXTP; - } - devpriv->daccon = COMBINE(devpriv->daccon, trig, - PCI224_DACCON_TRIG_MASK); + devpriv->daccon = + COMBINE(devpriv->daccon, trig, PCI224_DACCON_TRIG_MASK); outw(devpriv->daccon, dev->iobase + PCI224_DACCON); } @@ -668,13 +640,14 @@ static int pci224_ao_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + const struct pci224_board *thisboard = dev->board_ptr; + unsigned int range_check_0; unsigned int chan_mask = 0; int i; + range_check_0 = thisboard->ao_range_check[CR_RANGE(cmd->chanlist[0])]; for (i = 0; i < cmd->chanlist_len; i++) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); - unsigned int range = CR_RANGE(cmd->chanlist[i]); if (chan_mask & (1 << chan)) { dev_dbg(dev->class_dev, @@ -682,11 +655,12 @@ static int pci224_ao_check_chanlist(struct comedi_device *dev, __func__); return -EINVAL; } - chan_mask |= (1 << chan); + chan_mask |= 1 << chan; - if (range != range0) { + if (thisboard->ao_range_check[CR_RANGE(cmd->chanlist[i])] != + range_check_0) { dev_dbg(dev->class_dev, - "%s: entries in chanlist must all have the same range index\n", + "%s: entries in chanlist have incompatible ranges\n", __func__); return -EINVAL; } @@ -714,11 +688,11 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_EXT | TRIG_TIMER); + TRIG_EXT | TRIG_TIMER); err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, - TRIG_COUNT | TRIG_EXT | TRIG_NONE); + TRIG_COUNT | TRIG_EXT | TRIG_NONE); if (err) return 1; @@ -756,13 +730,13 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, break; case TRIG_EXT: /* Force to external trigger 0. */ - if ((cmd->start_arg & ~CR_FLAGS_MASK) != 0) { - cmd->start_arg = COMBINE(cmd->start_arg, 0, - ~CR_FLAGS_MASK); + if (cmd->start_arg & ~CR_FLAGS_MASK) { + cmd->start_arg = + COMBINE(cmd->start_arg, 0, ~CR_FLAGS_MASK); err |= -EINVAL; } /* The only flag allowed is CR_EDGE, which is ignored. */ - if ((cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) { + if (cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) { cmd->start_arg = COMBINE(cmd->start_arg, 0, CR_FLAGS_MASK & ~CR_EDGE); err |= -EINVAL; @@ -782,17 +756,17 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, break; case TRIG_EXT: /* Force to external trigger 0. */ - if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) { - cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, - ~CR_FLAGS_MASK); + if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) { + cmd->scan_begin_arg = + COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK); err |= -EINVAL; } /* Only allow flags CR_EDGE and CR_INVERT. Ignore CR_EDGE. */ - if ((cmd->scan_begin_arg & CR_FLAGS_MASK & - ~(CR_EDGE | CR_INVERT)) != 0) { - cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, - CR_FLAGS_MASK & - ~(CR_EDGE | CR_INVERT)); + if (cmd->scan_begin_arg & CR_FLAGS_MASK & + ~(CR_EDGE | CR_INVERT)) { + cmd->scan_begin_arg = + COMBINE(cmd->scan_begin_arg, 0, + CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT)); err |= -EINVAL; } break; @@ -803,19 +777,19 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, switch (cmd->stop_src) { case TRIG_COUNT: - /* Any count allowed. */ + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); break; case TRIG_EXT: /* Force to external trigger 0. */ - if ((cmd->stop_arg & ~CR_FLAGS_MASK) != 0) { - cmd->stop_arg = COMBINE(cmd->stop_arg, 0, - ~CR_FLAGS_MASK); + if (cmd->stop_arg & ~CR_FLAGS_MASK) { + cmd->stop_arg = + COMBINE(cmd->stop_arg, 0, ~CR_FLAGS_MASK); err |= -EINVAL; } /* The only flag allowed is CR_EDGE, which is ignored. */ - if ((cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) { - cmd->stop_arg = COMBINE(cmd->stop_arg, 0, - CR_FLAGS_MASK & ~CR_EDGE); + if (cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) { + cmd->stop_arg = + COMBINE(cmd->stop_arg, 0, CR_FLAGS_MASK & ~CR_EDGE); } break; case TRIG_NONE: @@ -880,6 +854,7 @@ static void pci224_ao_start_pacer(struct comedi_device *dev, static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct pci224_board *thisboard = dev->board_ptr; struct pci224_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int range; @@ -903,7 +878,6 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) for (j = 0; j < cmd->chanlist_len; j++) { if (CR_CHAN(cmd->chanlist[j]) < ch) rank++; - } devpriv->ao_scan_order[rank] = i; } @@ -922,14 +896,12 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * * N.B. DAC FIFO interrupts are currently disabled. */ - devpriv->daccon = COMBINE(devpriv->daccon, - (devpriv-> - hwrange[range] | PCI224_DACCON_TRIG_NONE | - PCI224_DACCON_FIFOINTR_NHALF), - (PCI224_DACCON_POLAR_MASK | - PCI224_DACCON_VREF_MASK | - PCI224_DACCON_TRIG_MASK | - PCI224_DACCON_FIFOINTR_MASK)); + devpriv->daccon = + COMBINE(devpriv->daccon, + thisboard->ao_hwrange[range] | PCI224_DACCON_TRIG_NONE | + PCI224_DACCON_FIFOINTR_NHALF, + PCI224_DACCON_POLAR_MASK | PCI224_DACCON_VREF_MASK | + PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK); outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); @@ -974,8 +946,7 @@ static void pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { - const struct pci224_board *thisboard = comedi_board(dev); - struct pci224_private *devpriv = dev->private; + const struct pci224_board *thisboard = dev->board_ptr; struct comedi_cmd *cmd = &s->async->cmd; unsigned short *array = data; unsigned int length = num_bytes / sizeof(*array); @@ -986,7 +957,7 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, /* The hardware expects 16-bit numbers. */ shift = 16 - thisboard->ao_bits; /* Channels will be all bipolar or all unipolar. */ - if ((devpriv->hwrange[CR_RANGE(cmd->chanlist[0])] & + if ((thisboard->ao_hwrange[CR_RANGE(cmd->chanlist[0])] & PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) { /* Unipolar */ offset = 0; @@ -997,7 +968,6 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, /* Munge the data. */ for (i = 0; i < length; i++) array[i] = (array[i] << shift) - offset; - } /* @@ -1025,7 +995,7 @@ static irqreturn_t pci224_interrupt(int irq, void *d) devpriv->intr_running = 1; devpriv->intr_cpuid = THISCPU; spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - if (valid_intstat != 0) { + if (valid_intstat) { cmd = &s->async->cmd; if (valid_intstat & PCI224_INTR_EXT) { devpriv->intsce &= ~PCI224_INTR_EXT; @@ -1033,11 +1003,9 @@ static irqreturn_t pci224_interrupt(int irq, void *d) pci224_ao_start(dev, s); else if (cmd->stop_src == TRIG_EXT) pci224_ao_stop(dev, s); - } if (valid_intstat & PCI224_INTR_DAC) pci224_ao_handle_fifo(dev, s); - } /* Reenable interrupt sources. */ spin_lock_irqsave(&devpriv->ao_spinlock, flags); @@ -1051,77 +1019,32 @@ static irqreturn_t pci224_interrupt(int irq, void *d) return IRQ_RETVAL(retval); } -/* - * This function looks for a board matching the supplied PCI device. - */ -static const struct pci224_board -*pci224_find_pci_board(struct pci_dev *pci_dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) - if (pci_dev->device == pci224_boards[i].devid) - return &pci224_boards[i]; - return NULL; -} - -/* - * This function looks for a PCI device matching the requested board name, - * bus and slot. - */ -static struct pci_dev *pci224_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - const struct pci224_board *thisboard = comedi_board(dev); - struct pci_dev *pci_dev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pci_dev) { - if (bus || slot) { - if (bus != pci_dev->bus->number || - slot != PCI_SLOT(pci_dev->devfn)) - continue; - } - if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON) - continue; - - if (thisboard->model == any_model) { - /* Match any supported model. */ - const struct pci224_board *board_ptr; - - board_ptr = pci224_find_pci_board(pci_dev); - if (board_ptr == NULL) - continue; - /* Change board_ptr to matched board. */ - dev->board_ptr = board_ptr; - } else { - /* Match specific model name. */ - if (thisboard->devid != pci_dev->device) - continue; - } - return pci_dev; - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -/* - * Common part of attach and auto_attach. - */ -static int pci224_attach_common(struct comedi_device *dev, - struct pci_dev *pci_dev, int *options) +static int +pci224_auto_attach(struct comedi_device *dev, unsigned long context_model) { - const struct pci224_board *thisboard = comedi_board(dev); - struct pci224_private *devpriv = dev->private; + struct pci_dev *pci_dev = comedi_to_pci_dev(dev); + const struct pci224_board *thisboard = NULL; + struct pci224_private *devpriv; struct comedi_subdevice *s; unsigned int irq; - unsigned n; int ret; - comedi_set_hw_dev(dev, &pci_dev->dev); + if (context_model < ARRAY_SIZE(pci224_boards)) + thisboard = &pci224_boards[context_model]; + if (!thisboard || !thisboard->name) { + dev_err(dev->class_dev, + "amplc_pci224: BUG! cannot determine board type!\n"); + return -EINVAL; + } + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; + + dev_info(dev->class_dev, "amplc_pci224: attach pci %s - %s\n", + pci_name(pci_dev), dev->board_name); + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; ret = comedi_pci_enable(dev); if (ret) @@ -1133,13 +1056,6 @@ static int pci224_attach_common(struct comedi_device *dev, dev->iobase = pci_resource_start(pci_dev, 3); irq = pci_dev->irq; - /* Allocate readback buffer for AO channels. */ - devpriv->ao_readback = kmalloc(sizeof(devpriv->ao_readback[0]) * - thisboard->ao_chans, GFP_KERNEL); - if (!devpriv->ao_readback) - return -ENOMEM; - - /* Allocate buffer to hold values for AO channel scan. */ devpriv->ao_scan_vals = kmalloc(sizeof(devpriv->ao_scan_vals[0]) * thisboard->ao_chans, GFP_KERNEL); @@ -1162,9 +1078,8 @@ static int pci224_attach_common(struct comedi_device *dev, outw(PCI224_DACCON_GLOBALRESET, dev->iobase + PCI224_DACCON); outw(0, dev->iobase + PCI224_DACCEN); outw(0, dev->iobase + PCI224_FIFOSIZ); - devpriv->daccon = (PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI | - PCI224_DACCON_FIFOENAB | - PCI224_DACCON_FIFOINTR_EMPTY); + devpriv->daccon = PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI | + PCI224_DACCON_FIFOENAB | PCI224_DACCON_FIFOINTR_EMPTY; outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); @@ -1178,71 +1093,19 @@ static int pci224_attach_common(struct comedi_device *dev, s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; s->n_chan = thisboard->ao_chans; s->maxdata = (1 << thisboard->ao_bits) - 1; - s->insn_write = &pci224_ao_insn_write; - s->insn_read = &pci224_ao_insn_read; + s->range_table = thisboard->ao_range; + s->insn_write = pci224_ao_insn_write; + s->insn_read = comedi_readback_insn_read; s->len_chanlist = s->n_chan; - dev->write_subdev = s; - s->do_cmd = &pci224_ao_cmd; - s->do_cmdtest = &pci224_ao_cmdtest; - s->cancel = &pci224_ao_cancel; - s->munge = &pci224_ao_munge; - - /* Sort out channel range options. */ - if (thisboard->model == pci234_model) { - /* PCI234 range options. */ - const struct comedi_lrange **range_table_list; - - s->range_table_list = range_table_list = - kmalloc(sizeof(struct comedi_lrange *) * s->n_chan, - GFP_KERNEL); - if (!s->range_table_list) - return -ENOMEM; - - if (options) { - for (n = 2; n < 3 + s->n_chan; n++) { - if (options[n] < 0 || options[n] > 1) { - dev_warn(dev->class_dev, - "warning! bad options[%u]=%d\n", - n, options[n]); - } - } - } - for (n = 0; n < s->n_chan; n++) { - if (n < COMEDI_NDEVCONFOPTS - 3 && options && - options[3 + n] == 1) { - if (options[2] == 1) - range_table_list[n] = &range_pci234_ext; - else - range_table_list[n] = &range_bipolar5; - - } else { - if (options && options[2] == 1) { - range_table_list[n] = - &range_pci234_ext2; - } else { - range_table_list[n] = &range_bipolar10; - } - } - } - devpriv->hwrange = hwrange_pci234; - } else { - /* PCI224 range options. */ - if (options && options[2] == 1) { - s->range_table = &range_pci224_external; - devpriv->hwrange = hwrange_pci224_external; - } else { - if (options && options[2] != 0) { - dev_warn(dev->class_dev, - "warning! bad options[2]=%d\n", - options[2]); - } - s->range_table = &range_pci224_internal; - devpriv->hwrange = hwrange_pci224_internal; - } - } + s->do_cmd = pci224_ao_cmd; + s->do_cmdtest = pci224_ao_cmdtest; + s->cancel = pci224_ao_cancel; + s->munge = pci224_ao_munge; - dev->board_name = thisboard->name; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; if (irq) { ret = request_irq(irq, pci224_interrupt, IRQF_SHARED, @@ -1258,80 +1121,20 @@ static int pci224_attach_common(struct comedi_device *dev, return 0; } -static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci224_private *devpriv; - struct pci_dev *pci_dev; - - dev_info(dev->class_dev, "attach\n"); - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - pci_dev = pci224_find_pci_dev(dev, it); - if (!pci_dev) - return -EIO; - - return pci224_attach_common(dev, pci_dev, it->options); -} - -static int -pci224_auto_attach(struct comedi_device *dev, unsigned long context_unused) -{ - struct pci_dev *pci_dev = comedi_to_pci_dev(dev); - struct pci224_private *devpriv; - - dev_info(dev->class_dev, "attach pci %s\n", pci_name(pci_dev)); - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - dev->board_ptr = pci224_find_pci_board(pci_dev); - if (dev->board_ptr == NULL) { - dev_err(dev->class_dev, - "BUG! cannot determine board type!\n"); - return -EINVAL; - } - /* - * Need to 'get' the PCI device to match the 'put' in pci224_detach(). - * TODO: Remove the pci_dev_get() and matching pci_dev_put() once - * support for manual attachment of PCI devices via pci224_attach() - * has been removed. - */ - pci_dev_get(pci_dev); - return pci224_attach_common(dev, pci_dev, NULL); -} - static void pci224_detach(struct comedi_device *dev) { struct pci224_private *devpriv = dev->private; - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->subdevices) { - struct comedi_subdevice *s; - - s = &dev->subdevices[0]; - /* AO subdevice */ - kfree(s->range_table_list); - } + comedi_pci_detach(dev); if (devpriv) { - kfree(devpriv->ao_readback); kfree(devpriv->ao_scan_vals); kfree(devpriv->ao_scan_order); } - comedi_pci_disable(dev); - if (pcidev) - pci_dev_put(pcidev); } static struct comedi_driver amplc_pci224_driver = { .driver_name = "amplc_pci224", .module = THIS_MODULE, - .attach = pci224_attach, .detach = pci224_detach, .auto_attach = pci224_auto_attach, .board_name = &pci224_boards[0].name, @@ -1347,8 +1150,8 @@ static int amplc_pci224_pci_probe(struct pci_dev *dev, } static const struct pci_device_id amplc_pci224_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) }, + { PCI_VDEVICE(AMPLICON, 0x0007), pci224_model }, + { PCI_VDEVICE(AMPLICON, 0x0008), pci234_model }, { 0 } }; MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table); @@ -1362,5 +1165,5 @@ static struct pci_driver amplc_pci224_pci_driver = { module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Amplicon PCI224 and PCI234 AO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 684275d76e8c..01796cd28e5b 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -24,24 +24,19 @@ * Author: Allan Willcox <allanwillcox@ozemail.com.au>, * Steve D Sharples <steve.sharples@nottingham.ac.uk>, * Ian Abbott <abbotti@mev.co.uk> - * Updated: Wed, 22 Oct 2008 12:34:49 +0100 - * Devices: [Amplicon] PCI230 (pci230 or amplc_pci230), - * PCI230+ (pci230+ or amplc_pci230), - * PCI260 (pci260 or amplc_pci230), PCI260+ (pci260+ or amplc_pci230) + * Updated: Mon, 01 Sep 2014 10:09:16 +0000 + * Devices: [Amplicon] PCI230 (amplc_pci230), PCI230+, PCI260, PCI260+ * Status: works * * 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. + * none * - * Configuring a "amplc_pci230" will match any supported card and it will - * choose the best match, picking the "+" models if possible. Configuring - * a "pci230" will match a PCI230 or PCI230+ card and it will be treated as - * a PCI230. Configuring a "pci260" will match a PCI260 or PCI260+ card - * and it will be treated as a PCI260. Configuring a "pci230+" will match - * a PCI230+ card. Configuring a "pci260+" will match a PCI260+ card. + * Manual configuration of PCI cards is not supported; they are configured + * automatically. + * + * The PCI230+ and PCI260+ have the same PCI device IDs as the PCI230 and + * PCI260, but can be distinguished by the the size of the PCI regions. A + * card will be configured as a "+" model if detected as such. * * Subdevices: * @@ -201,7 +196,6 @@ */ #define PCI_DEVICE_ID_PCI230 0x0000 #define PCI_DEVICE_ID_PCI260 0x0006 -#define PCI_DEVICE_ID_INVALID 0xffff /* * PCI230 i/o space 1 registers. @@ -427,16 +421,15 @@ * (Potentially) shared resources and their owners */ enum { - RES_Z2CT0, /* Z2-CT0 */ - RES_Z2CT1, /* Z2-CT1 */ - RES_Z2CT2, /* Z2-CT2 */ - NUM_RESOURCES /* Number of (potentially) shared resources. */ + RES_Z2CT0 = (1U << 0), /* Z2-CT0 */ + RES_Z2CT1 = (1U << 1), /* Z2-CT1 */ + RES_Z2CT2 = (1U << 2) /* Z2-CT2 */ }; enum { - OWNER_NONE, /* Not owned */ OWNER_AICMD, /* Owned by AI command */ - OWNER_AOCMD /* Owned by AO command */ + OWNER_AOCMD, /* Owned by AO command */ + NUM_OWNERS /* Number of owners */ }; /* @@ -449,10 +442,6 @@ enum { /* Current CPU. XXX should this be hard_smp_processor_id()? */ #define THISCPU smp_processor_id() -/* State flags for atomic bit operations */ -#define AI_CMD_STARTED 0 -#define AO_CMD_STARTED 1 - /* * Board descriptions for the two boards supported. */ @@ -460,52 +449,39 @@ enum { struct pci230_board { const char *name; unsigned short id; - int ai_chans; - int ai_bits; - int ao_chans; - int ao_bits; - int have_dio; - unsigned int min_hwver; /* Minimum hardware version supported. */ + unsigned char ai_bits; + unsigned char ao_bits; + unsigned char min_hwver; /* Minimum hardware version supported. */ + bool have_dio:1; }; static const struct pci230_board pci230_boards[] = { { .name = "pci230+", .id = PCI_DEVICE_ID_PCI230, - .ai_chans = 16, .ai_bits = 16, - .ao_chans = 2, .ao_bits = 12, - .have_dio = 1, + .have_dio = true, .min_hwver = 1, }, { .name = "pci260+", .id = PCI_DEVICE_ID_PCI260, - .ai_chans = 16, .ai_bits = 16, .min_hwver = 1, }, { .name = "pci230", .id = PCI_DEVICE_ID_PCI230, - .ai_chans = 16, .ai_bits = 12, - .ao_chans = 2, .ao_bits = 12, - .have_dio = 1, + .have_dio = true, }, { .name = "pci260", .id = PCI_DEVICE_ID_PCI260, - .ai_chans = 16, .ai_bits = 12, }, - { - /* Wildcard matches any above */ - .name = "amplc_pci230", - .id = PCI_DEVICE_ID_INVALID, - }, }; struct pci230_private { @@ -513,9 +489,7 @@ struct pci230_private { spinlock_t res_spinlock; /* Shared resources spin lock */ spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */ spinlock_t ao_stop_spinlock; /* Spin lock for stopping AO command */ - unsigned long state; /* State flags */ - unsigned long iobase1; /* PCI230's I/O space 1 */ - unsigned int ao_readback[2]; /* Used for AO readback */ + unsigned long daqio; /* PCI230's DAQ I/O space */ unsigned int ai_scan_count; /* Number of AI scans remaining */ unsigned int ai_scan_pos; /* Current position within AI scan */ unsigned int ao_scan_count; /* Number of AO scans remaining. */ @@ -525,12 +499,13 @@ struct pci230_private { unsigned short daccon; /* DACCON register value */ unsigned short adcfifothresh; /* ADC FIFO threshold (PCI230+/260+) */ unsigned short adcg; /* ADCG register value */ - unsigned char int_en; /* Interrupt enable bits */ - unsigned char ai_bipolar; /* Flag AI range is bipolar */ - unsigned char ao_bipolar; /* Flag AO range is bipolar */ - unsigned char ier; /* Copy of interrupt enable register */ - unsigned char intr_running; /* Flag set in interrupt routine */ - unsigned char res_owner[NUM_RESOURCES]; /* Shared resource owners */ + unsigned char ier; /* Interrupt enable bits */ + unsigned char res_owned[NUM_OWNERS]; /* Owned resources */ + bool intr_running:1; /* Flag set in interrupt routine */ + bool ai_bipolar:1; /* Flag AI range is bipolar */ + bool ao_bipolar:1; /* Flag AO range is bipolar */ + bool ai_cmd_started:1; /* Flag AI command started */ + bool ao_cmd_started:1; /* Flag AO command started */ }; /* PCI230 clock source periods in ns */ @@ -558,9 +533,6 @@ static const struct comedi_lrange pci230_ai_range = { /* PCI230 analogue gain bits for each input range. */ static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 }; -/* PCI230 adccon bipolar flag for each analogue input range. */ -static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 }; - /* PCI230 analogue output range table */ static const struct comedi_lrange pci230_ao_range = { 2, { @@ -569,170 +541,122 @@ static const struct comedi_lrange pci230_ao_range = { } }; -/* PCI230 daccon bipolar flag for each analogue output range. */ -static const unsigned char pci230_ao_bipolar[2] = { 0, 1 }; - static unsigned short pci230_ai_read(struct comedi_device *dev) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; unsigned short data; /* Read sample. */ - data = inw(dev->iobase + PCI230_ADCDATA); + data = inw(devpriv->daqio + PCI230_ADCDATA); /* * PCI230 is 12 bit - stored in upper bits of 16 bit register * (lower four bits reserved for expansion). PCI230+ is 16 bit AI. - */ - data = data >> (16 - thisboard->ai_bits); - - /* + * * If a bipolar range was specified, mangle it * (twos complement->straight binary). */ if (devpriv->ai_bipolar) - data ^= 1 << (thisboard->ai_bits - 1); - + data ^= 0x8000; + data >>= (16 - thisboard->ai_bits); return data; } -static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, - unsigned short datum) +static unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, + unsigned short datum) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; /* - * If a bipolar range was specified, mangle it - * (straight binary->twos complement). - */ - if (devpriv->ao_bipolar) - datum ^= 1 << (thisboard->ao_bits - 1); - - /* * PCI230 is 12 bit - stored in upper bits of 16 bit register (lower * four bits reserved for expansion). PCI230+ is also 12 bit AO. */ datum <<= (16 - thisboard->ao_bits); + /* + * If a bipolar range was specified, mangle it + * (straight binary->twos complement). + */ + if (devpriv->ao_bipolar) + datum ^= 0x8000; return datum; } -static inline void pci230_ao_write_nofifo(struct comedi_device *dev, - unsigned short datum, - unsigned int chan) +static void pci230_ao_write_nofifo(struct comedi_device *dev, + unsigned short datum, unsigned int chan) { struct pci230_private *devpriv = dev->private; - /* Store unmangled datum to be read back later. */ - devpriv->ao_readback[chan] = datum; - /* Write mangled datum to appropriate DACOUT register. */ outw(pci230_ao_mangle_datum(dev, datum), - dev->iobase + (((chan) == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2)); + devpriv->daqio + ((chan == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2)); } -static inline void pci230_ao_write_fifo(struct comedi_device *dev, - unsigned short datum, unsigned int chan) +static void pci230_ao_write_fifo(struct comedi_device *dev, + unsigned short datum, unsigned int chan) { struct pci230_private *devpriv = dev->private; - /* Store unmangled datum to be read back later. */ - devpriv->ao_readback[chan] = datum; - /* Write mangled datum to appropriate DACDATA register. */ outw(pci230_ao_mangle_datum(dev, datum), - dev->iobase + PCI230P2_DACDATA); + devpriv->daqio + PCI230P2_DACDATA); } -static int get_resources(struct comedi_device *dev, unsigned int res_mask, - unsigned char owner) +static bool pci230_claim_shared(struct comedi_device *dev, + unsigned char res_mask, unsigned int owner) { struct pci230_private *devpriv = dev->private; - int ok; - unsigned int i; - unsigned int b; - unsigned int claimed; + unsigned int o; unsigned long irqflags; - ok = 1; - claimed = 0; spin_lock_irqsave(&devpriv->res_spinlock, irqflags); - for (b = 1, i = 0; (i < NUM_RESOURCES) && res_mask; b <<= 1, i++) { - if (res_mask & b) { - res_mask &= ~b; - if (devpriv->res_owner[i] == OWNER_NONE) { - devpriv->res_owner[i] = owner; - claimed |= b; - } else if (devpriv->res_owner[i] != owner) { - for (b = 1, i = 0; claimed; b <<= 1, i++) { - if (claimed & b) { - devpriv->res_owner[i] = - OWNER_NONE; - claimed &= ~b; - } - } - ok = 0; - break; - } + for (o = 0; o < NUM_OWNERS; o++) { + if (o == owner) + continue; + if (devpriv->res_owned[o] & res_mask) { + spin_unlock_irqrestore(&devpriv->res_spinlock, + irqflags); + return false; } } + devpriv->res_owned[owner] |= res_mask; spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); - return ok; -} - -static inline int get_one_resource(struct comedi_device *dev, - unsigned int resource, unsigned char owner) -{ - return get_resources(dev, (1U << resource), owner); + return true; } -static void put_resources(struct comedi_device *dev, unsigned int res_mask, - unsigned char owner) +static void pci230_release_shared(struct comedi_device *dev, + unsigned char res_mask, unsigned int owner) { struct pci230_private *devpriv = dev->private; - unsigned int i; - unsigned int b; unsigned long irqflags; spin_lock_irqsave(&devpriv->res_spinlock, irqflags); - for (b = 1, i = 0; (i < NUM_RESOURCES) && res_mask; b <<= 1, i++) { - if (res_mask & b) { - res_mask &= ~b; - if (devpriv->res_owner[i] == owner) - devpriv->res_owner[i] = OWNER_NONE; - } - } + devpriv->res_owned[owner] &= ~res_mask; spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); } -static inline void put_one_resource(struct comedi_device *dev, - unsigned int resource, unsigned char owner) +static void pci230_release_all_resources(struct comedi_device *dev, + unsigned int owner) { - put_resources(dev, (1U << resource), owner); + pci230_release_shared(dev, (unsigned char)~0, owner); } -static inline void put_all_resources(struct comedi_device *dev, - unsigned char owner) -{ - put_resources(dev, (1U << NUM_RESOURCES) - 1, owner); -} - -static unsigned int divide_ns(uint64_t ns, unsigned int timebase, - unsigned int flags) +static unsigned int pci230_divide_ns(uint64_t ns, unsigned int timebase, + unsigned int flags) { uint64_t div; unsigned int rem; div = ns; rem = do_div(div, timebase); - switch (flags & TRIG_ROUND_MASK) { + switch (flags & CMDF_ROUND_MASK) { default: - case TRIG_ROUND_NEAREST: + case CMDF_ROUND_NEAREST: div += (rem + (timebase / 2)) / timebase; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: div += (rem + timebase - 1) / timebase; break; } @@ -749,8 +673,8 @@ static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count, unsigned int clk_src, cnt; for (clk_src = CLK_10MHZ;; clk_src++) { - cnt = divide_ns(ns, pci230_timebase[clk_src], flags); - if ((cnt <= 65536) || (clk_src == CLK_1KHZ)) + cnt = pci230_divide_ns(ns, pci230_timebase[clk_src], flags); + if (cnt <= 65536 || clk_src == CLK_1KHZ) break; } *count = cnt; @@ -770,29 +694,25 @@ static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct, unsigned int mode, uint64_t ns, unsigned int flags) { - struct pci230_private *devpriv = dev->private; unsigned int clk_src; unsigned int count; /* Set mode. */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, mode); /* Determine clock source and count. */ clk_src = pci230_choose_clk_count(ns, &count, flags); /* Program clock source. */ - outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE); + outb(CLK_CONFIG(ct, clk_src), dev->iobase + PCI230_ZCLK_SCE); /* Set initial count. */ if (count >= 65536) count = 0; - i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count); + i8254_write(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, count); } static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct) { - struct pci230_private *devpriv = dev->private; - - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, - I8254_MODE1); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, I8254_MODE1); /* Counter ct, 8254 mode 1, initial count not written. */ } @@ -801,17 +721,18 @@ static int pci230_ai_eoc(struct comedi_device *dev, struct comedi_insn *insn, unsigned long context) { + struct pci230_private *devpriv = dev->private; unsigned int status; - status = inw(dev->iobase + PCI230_ADCCON); + status = inw(devpriv->daqio + PCI230_ADCCON); if ((status & PCI230_ADC_FIFO_EMPTY) == 0) return 0; return -EBUSY; } -static int pci230_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int pci230_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct pci230_private *devpriv = dev->private; unsigned int n; @@ -842,8 +763,8 @@ static int pci230_ai_rinsn(struct comedi_device *dev, */ adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN; /* Set Z2-CT2 output low to avoid any false triggers. */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0); - devpriv->ai_bipolar = pci230_ai_bipolar[range]; + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0); + devpriv->ai_bipolar = comedi_range_is_bipolar(s, range); if (aref == AREF_DIFF) { /* Differential. */ gainshift = chan * 2; @@ -874,19 +795,18 @@ static int pci230_ai_rinsn(struct comedi_device *dev, else adccon |= PCI230_ADC_IR_UNI; - /* * Enable only this channel in the scan list - otherwise by default * we'll get one sample from each channel. */ - outw(adcen, dev->iobase + PCI230_ADCEN); + outw(adcen, devpriv->daqio + PCI230_ADCEN); /* Set gain for channel. */ - outw(devpriv->adcg, dev->iobase + PCI230_ADCG); + outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); /* Specify uni/bip, se/diff, conversion source, and reset FIFO. */ devpriv->adccon = adccon; - outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); + outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON); /* Convert n samples */ for (n = 0; n < insn->n; n++) { @@ -894,10 +814,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev, * Trigger conversion by toggling Z2-CT2 output * (finish with output high). */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE0); - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE1); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, + 2, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, + 2, I8254_MODE1); /* wait for conversion to end */ ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0); @@ -912,57 +832,31 @@ static int pci230_ai_rinsn(struct comedi_device *dev, return n; } -/* - * COMEDI_SUBD_AO instructions; - */ -static int pci230_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int pci230_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pci230_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = s->readback[chan]; int i; - int chan, range; - - /* Unpack channel and range. */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); /* * Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale */ - devpriv->ao_bipolar = pci230_ao_bipolar[range]; - outw(range, dev->iobase + PCI230_DACCON); + devpriv->ao_bipolar = comedi_range_is_bipolar(s, range); + outw(range, devpriv->daqio + PCI230_DACCON); - /* - * 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++) { - /* Write value to DAC and store it. */ - pci230_ao_write_nofifo(dev, data[i], chan); + val = data[i]; + pci230_ao_write_nofifo(dev, val, chan); } + s->readback[chan] = val; - /* return the number of samples read/written */ - return i; -} - -/* - * AO subdevices should have a read insn as well as a write insn. - * Usually this means copying a value stored in devpriv. - */ -static int pci230_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - struct pci230_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int pci230_ao_check_chanlist(struct comedi_device *dev, @@ -1000,7 +894,7 @@ static int pci230_ao_check_chanlist(struct comedi_device *dev, static int pci230_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; int err = 0; unsigned int tmp; @@ -1010,7 +904,7 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); tmp = TRIG_TIMER | TRIG_INT; - if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) { + if (thisboard->min_hwver > 0 && devpriv->hwver >= 2) { /* * For PCI230+ hardware version 2 onwards, allow external * trigger from EXTTRIG/EXTCONVCLK input (PCI230+ pin 25). @@ -1078,11 +972,11 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, * The only flags allowed are CR_EDGE and CR_INVERT. * The CR_EDGE flag is ignored. */ - if (cmd->scan_begin_arg & - (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) { - cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, - CR_FLAGS_MASK & - ~(CR_EDGE | CR_INVERT)); + if (cmd->scan_begin_arg & CR_FLAGS_MASK & + ~(CR_EDGE | CR_INVERT)) { + cmd->scan_begin_arg = + COMBINE(cmd->scan_begin_arg, 0, + CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT)); err |= -EINVAL; } break; @@ -1093,7 +987,9 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -1127,11 +1023,12 @@ static void pci230_ao_stop(struct comedi_device *dev, struct pci230_private *devpriv = dev->private; unsigned long irqflags; unsigned char intsrc; - int started; + bool started; struct comedi_cmd *cmd; spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); - started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state); + started = devpriv->ao_cmd_started; + devpriv->ao_cmd_started = false; spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); if (!started) return; @@ -1153,15 +1050,12 @@ static void pci230_ao_stop(struct comedi_device *dev, * unless we are called from the interrupt routine. */ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - devpriv->int_en &= ~intsrc; + devpriv->ier &= ~intsrc; while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) { spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); } - if (devpriv->ier != devpriv->int_en) { - devpriv->ier = devpriv->int_en; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - } + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); if (devpriv->hwver >= 2) { /* @@ -1171,10 +1065,10 @@ static void pci230_ao_stop(struct comedi_device *dev, devpriv->daccon &= PCI230_DAC_OR_MASK; outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR, - dev->iobase + PCI230_DACCON); + devpriv->daqio + PCI230_DACCON); } /* Release resources. */ - put_all_resources(dev, OWNER_AOCMD); + pci230_release_all_resources(dev, OWNER_AOCMD); } static void pci230_handle_ao_nofifo(struct comedi_device *dev, @@ -1189,6 +1083,8 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) return; for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + /* Read sample from Comedi's circular buffer. */ ret = comedi_buf_get(s, &data); if (ret == 0) { @@ -1197,8 +1093,8 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, dev_err(dev->class_dev, "AO buffer underrun\n"); return; } - /* Write value to DAC. */ - pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i])); + pci230_ao_write_nofifo(dev, data, chan); + s->readback[chan] = data; } async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; if (cmd->stop_src == TRIG_COUNT) { @@ -1211,10 +1107,12 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, } } -/* Loads DAC FIFO (if using it) from buffer. */ -/* Returns 0 if AO finished due to completion or error, 1 if still going. */ -static int pci230_handle_ao_fifo(struct comedi_device *dev, - struct comedi_subdevice *s) +/* + * Loads DAC FIFO (if using it) from buffer. + * Returns false if AO finished due to completion or error, true if still going. + */ +static bool pci230_handle_ao_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pci230_private *devpriv = dev->private; struct comedi_async *async = s->async; @@ -1224,10 +1122,10 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, unsigned short dacstat; unsigned int i, n; unsigned int events = 0; - int running; + bool running; /* Get DAC FIFO status. */ - dacstat = inw(dev->iobase + PCI230_DACCON); + dacstat = inw(devpriv->daqio + PCI230_DACCON); /* Determine number of scans available in buffer. */ num_scans = comedi_buf_read_n_available(s) / cfc_bytes_per_scan(s); if (cmd->stop_src == TRIG_COUNT) { @@ -1250,8 +1148,8 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, * (otherwise there will be loads of "DAC FIFO not half full" * interrupts). */ - if ((num_scans == 0) && - ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) { + if (num_scans == 0 && + (dacstat & PCI230P2_DAC_FIFO_HALF) == 0) { dev_err(dev->class_dev, "AO buffer underrun\n"); events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; } @@ -1274,11 +1172,12 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, /* Process scans. */ for (n = 0; n < num_scans; n++) { for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned short datum; comedi_buf_get(s, &datum); - pci230_ao_write_fifo(dev, datum, - CR_CHAN(cmd->chanlist[i])); + pci230_ao_write_fifo(dev, datum, chan); + s->readback[chan] = datum; } } events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK; @@ -1295,11 +1194,11 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, ~PCI230P2_DAC_INT_FIFO_MASK) | PCI230P2_DAC_INT_FIFO_EMPTY; outw(devpriv->daccon, - dev->iobase + PCI230_DACCON); + devpriv->daqio + PCI230_DACCON); } } /* Check if FIFO underrun occurred while writing to FIFO. */ - dacstat = inw(dev->iobase + PCI230_DACCON); + dacstat = inw(devpriv->daqio + PCI230_DACCON); if (dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) { dev_err(dev->class_dev, "AO FIFO underrun\n"); events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; @@ -1308,9 +1207,9 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { /* Stopping AO due to completion or error. */ pci230_ao_stop(dev, s); - running = 0; + running = false; } else { - running = 1; + running = true; } async->events |= events; return running; @@ -1327,28 +1226,25 @@ static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, return -EINVAL; spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); - if (test_bit(AO_CMD_STARTED, &devpriv->state)) { - /* Perform scan. */ - if (devpriv->hwver < 2) { - /* Not using DAC FIFO. */ - spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, - irqflags); - pci230_handle_ao_nofifo(dev, s); - comedi_event(dev, s); - } else { - /* Using DAC FIFO. */ - /* Read DACSWTRIG register to trigger conversion. */ - inw(dev->iobase + PCI230P2_DACSWTRIG); - spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, - irqflags); - } - /* Delay. Should driver be responsible for this? */ - /* XXX TODO: See if DAC busy bit can be used. */ - udelay(8); + if (!devpriv->ao_cmd_started) { + spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); + return 1; + } + /* Perform scan. */ + if (devpriv->hwver < 2) { + /* Not using DAC FIFO. */ + spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); + pci230_handle_ao_nofifo(dev, s); + comedi_event(dev, s); } else { + /* Using DAC FIFO. */ + /* Read DACSWTRIG register to trigger conversion. */ + inw(devpriv->daqio + PCI230P2_DACSWTRIG); spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); } - + /* Delay. Should driver be responsible for this? */ + /* XXX TODO: See if DAC busy bit can be used. */ + udelay(8); return 1; } @@ -1360,84 +1256,71 @@ static void pci230_ao_start(struct comedi_device *dev, struct comedi_cmd *cmd = &async->cmd; unsigned long irqflags; - set_bit(AO_CMD_STARTED, &devpriv->state); - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) { - /* An empty acquisition! */ - async->events |= COMEDI_CB_EOA; - pci230_ao_stop(dev, s); + devpriv->ao_cmd_started = true; + + if (devpriv->hwver >= 2) { + /* Using DAC FIFO. */ + unsigned short scantrig; + bool run; + + /* Preload FIFO data. */ + run = pci230_handle_ao_fifo(dev, s); comedi_event(dev, s); - } else { - if (devpriv->hwver >= 2) { - /* Using DAC FIFO. */ - unsigned short scantrig; - int run; - - /* Preload FIFO data. */ - run = pci230_handle_ao_fifo(dev, s); - comedi_event(dev, s); - if (!run) { - /* Stopped. */ - return; - } - /* Set scan trigger source. */ - switch (cmd->scan_begin_src) { - case TRIG_TIMER: - scantrig = PCI230P2_DAC_TRIG_Z2CT1; - break; - case TRIG_EXT: - /* Trigger on EXTTRIG/EXTCONVCLK pin. */ - if ((cmd->scan_begin_arg & CR_INVERT) == 0) { - /* +ve edge */ - scantrig = PCI230P2_DAC_TRIG_EXTP; - } else { - /* -ve edge */ - scantrig = PCI230P2_DAC_TRIG_EXTN; - } - break; - case TRIG_INT: - scantrig = PCI230P2_DAC_TRIG_SW; - break; - default: - /* Shouldn't get here. */ - scantrig = PCI230P2_DAC_TRIG_NONE; - break; - } - devpriv->daccon = - (devpriv->daccon & ~PCI230P2_DAC_TRIG_MASK) | - scantrig; - outw(devpriv->daccon, dev->iobase + PCI230_DACCON); + if (!run) { + /* Stopped. */ + return; } + /* Set scan trigger source. */ switch (cmd->scan_begin_src) { case TRIG_TIMER: - if (devpriv->hwver < 2) { - /* Not using DAC FIFO. */ - /* Enable CT1 timer interrupt. */ - spin_lock_irqsave(&devpriv->isr_spinlock, - irqflags); - devpriv->int_en |= PCI230_INT_ZCLK_CT1; - devpriv->ier |= PCI230_INT_ZCLK_CT1; - outb(devpriv->ier, - devpriv->iobase1 + PCI230_INT_SCE); - spin_unlock_irqrestore(&devpriv->isr_spinlock, - irqflags); + scantrig = PCI230P2_DAC_TRIG_Z2CT1; + break; + case TRIG_EXT: + /* Trigger on EXTTRIG/EXTCONVCLK pin. */ + if ((cmd->scan_begin_arg & CR_INVERT) == 0) { + /* +ve edge */ + scantrig = PCI230P2_DAC_TRIG_EXTP; + } else { + /* -ve edge */ + scantrig = PCI230P2_DAC_TRIG_EXTN; } - /* Set CT1 gate high to start counting. */ - outb(GAT_CONFIG(1, GAT_VCC), - devpriv->iobase1 + PCI230_ZGAT_SCE); break; case TRIG_INT: - async->inttrig = pci230_ao_inttrig_scan_begin; + scantrig = PCI230P2_DAC_TRIG_SW; + break; + default: + /* Shouldn't get here. */ + scantrig = PCI230P2_DAC_TRIG_NONE; break; } - if (devpriv->hwver >= 2) { - /* Using DAC FIFO. Enable DAC FIFO interrupt. */ + devpriv->daccon = + (devpriv->daccon & ~PCI230P2_DAC_TRIG_MASK) | scantrig; + outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON); + } + switch (cmd->scan_begin_src) { + case TRIG_TIMER: + if (devpriv->hwver < 2) { + /* Not using DAC FIFO. */ + /* Enable CT1 timer interrupt. */ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - devpriv->int_en |= PCI230P2_INT_DAC; - devpriv->ier |= PCI230P2_INT_DAC; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); + devpriv->ier |= PCI230_INT_ZCLK_CT1; + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); } + /* Set CT1 gate high to start counting. */ + outb(GAT_CONFIG(1, GAT_VCC), dev->iobase + PCI230_ZGAT_SCE); + break; + case TRIG_INT: + async->inttrig = pci230_ao_inttrig_scan_begin; + break; + } + if (devpriv->hwver >= 2) { + /* Using DAC FIFO. Enable DAC FIFO interrupt. */ + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + devpriv->ier |= PCI230P2_INT_DAC; + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); } } @@ -1467,22 +1350,18 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->scan_begin_src == TRIG_TIMER) { /* Claim Z2-CT1. */ - if (!get_one_resource(dev, RES_Z2CT1, OWNER_AOCMD)) + if (!pci230_claim_shared(dev, RES_Z2CT1, OWNER_AOCMD)) return -EBUSY; } - /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->ao_scan_count = cmd->stop_arg; - else /* TRIG_NONE, user calls cancel */ - devpriv->ao_scan_count = 0; + devpriv->ao_scan_count = cmd->stop_arg; /* * Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale */ range = CR_RANGE(cmd->chanlist[0]); - devpriv->ao_bipolar = pci230_ao_bipolar[range]; + devpriv->ao_bipolar = comedi_range_is_bipolar(s, range); daccon = devpriv->ao_bipolar ? PCI230_DAC_OR_BIP : PCI230_DAC_OR_UNI; /* Use DAC FIFO for hardware version 2 onwards. */ if (devpriv->hwver >= 2) { @@ -1494,7 +1373,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dacen |= 1 << CR_CHAN(cmd->chanlist[i]); /* Set channel scan list. */ - outw(dacen, dev->iobase + PCI230P2_DACEN); + outw(dacen, devpriv->daqio + PCI230P2_DACEN); /* * Enable DAC FIFO. * Set DAC scan source to 'none'. @@ -1509,7 +1388,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Set DACCON. */ - outw(daccon, dev->iobase + PCI230_DACCON); + outw(daccon, devpriv->daqio + PCI230_DACCON); /* Preserve most of DACCON apart from write-only, transient bits. */ devpriv->daccon = daccon & ~(PCI230P2_DAC_FIFO_RESET | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR); @@ -1520,8 +1399,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * cmd->scan_begin_arg is sampling period in ns. * Gate it off for now. */ - outb(GAT_CONFIG(1, GAT_GND), - devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(GAT_CONFIG(1, GAT_GND), dev->iobase + PCI230_ZGAT_SCE); pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3, cmd->scan_begin_arg, cmd->flags); @@ -1550,8 +1428,8 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd) chanlist_len = 1; min_scan_period = chanlist_len * cmd->convert_arg; - if ((min_scan_period < chanlist_len) || - (min_scan_period < cmd->convert_arg)) { + if (min_scan_period < chanlist_len || + min_scan_period < cmd->convert_arg) { /* Arithmetic overflow. */ min_scan_period = UINT_MAX; err++; @@ -1573,7 +1451,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, unsigned int prev_chan = 0; unsigned int prev_range = 0; unsigned int prev_aref = 0; - unsigned int prev_polarity = 0; + bool prev_bipolar = false; unsigned int subseq_len = 0; int i; @@ -1582,7 +1460,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, unsigned int chan = CR_CHAN(chanspec); unsigned int range = CR_RANGE(chanspec); unsigned int aref = CR_AREF(chanspec); - unsigned int polarity = pci230_ai_bipolar[range]; + bool bipolar = comedi_range_is_bipolar(s, range); if (aref == AREF_DIFF && chan >= max_diff_chan) { dev_dbg(dev->class_dev, @@ -1614,7 +1492,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, return -EINVAL; } - if (polarity != prev_polarity) { + if (bipolar != prev_bipolar) { dev_dbg(dev->class_dev, "%s: channel sequence ranges must be all bipolar or all unipolar\n", __func__); @@ -1632,7 +1510,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, prev_chan = chan; prev_range = range; prev_aref = aref; - prev_polarity = polarity; + prev_bipolar = bipolar; } if (subseq_len == 0) @@ -1670,7 +1548,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev, static int pci230_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pci230_board *thisboard = comedi_board(dev); + const struct pci230_board *thisboard = dev->board_ptr; struct pci230_private *devpriv = dev->private; int err = 0; unsigned int tmp; @@ -1680,7 +1558,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT; - if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) { + if (thisboard->have_dio || thisboard->min_hwver > 0) { /* * Unfortunately, we cannot trigger a scan off an external * source on the PCI260 board, since it uses the PPIC0 (DIO) @@ -1711,8 +1589,8 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, * If scan_begin_src is not TRIG_FOLLOW, then a monostable will be * set up to generate a fixed number of timed conversion pulses. */ - if ((cmd->scan_begin_src != TRIG_FOLLOW) && - (cmd->convert_src != TRIG_TIMER)) + if (cmd->scan_begin_src != TRIG_FOLLOW && + cmd->convert_src != TRIG_TIMER) err |= -EINVAL; if (err) @@ -1739,7 +1617,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, * PCI230 or PCI260. Max speed depends whether * single-ended or pseudo-differential. */ - if (cmd->chanlist && (cmd->chanlist_len > 0)) { + if (cmd->chanlist && cmd->chanlist_len > 0) { /* Peek analogue reference of first channel. */ if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF) max_speed_ai = MAX_SPEED_AI_DIFF; @@ -1779,13 +1657,12 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, * The only flags allowed are CR_INVERT and CR_EDGE. * CR_EDGE is required. */ - if ((cmd->convert_arg & - (CR_FLAGS_MASK & ~CR_INVERT)) != CR_EDGE) { + if ((cmd->convert_arg & CR_FLAGS_MASK & ~CR_INVERT) != + CR_EDGE) { /* Set CR_EDGE, preserve CR_INVERT. */ - cmd->convert_arg = COMBINE(cmd->start_arg, - (CR_EDGE | 0), - CR_FLAGS_MASK & - ~CR_INVERT); + cmd->convert_arg = + COMBINE(cmd->start_arg, CR_EDGE | 0, + CR_FLAGS_MASK & ~CR_INVERT); err |= -EINVAL; } } else { @@ -1802,7 +1679,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (cmd->scan_begin_src == TRIG_EXT) { @@ -1850,7 +1729,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, if (!pci230_ai_check_scan_period(cmd)) { /* Was below minimum required. Round up. */ pci230_ns_to_single_timer(&cmd->scan_begin_arg, - TRIG_ROUND_UP); + CMDF_ROUND_UP); pci230_ai_check_scan_period(cmd); } if (tmp != cmd->scan_begin_arg) @@ -1880,37 +1759,30 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, unsigned short triglev; unsigned short adccon; - if (cmd->flags & TRIG_WAKE_EOS) { - /* Wake at end of scan. */ + if (cmd->flags & CMDF_WAKE_EOS) wake = scanlen - devpriv->ai_scan_pos; - } else { - if (cmd->stop_src != TRIG_COUNT || - devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || - scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) { - wake = PCI230_ADC_FIFOLEVEL_HALFFULL; - } else { - wake = (devpriv->ai_scan_count * scanlen) - - devpriv->ai_scan_pos; - } - } + else if (cmd->stop_src != TRIG_COUNT || + devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || + scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) + wake = PCI230_ADC_FIFOLEVEL_HALFFULL; + else + wake = devpriv->ai_scan_count * scanlen - devpriv->ai_scan_pos; if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) { triglev = PCI230_ADC_INT_FIFO_HALF; - } else { - if ((wake > 1) && (devpriv->hwver > 0)) { - /* PCI230+/260+ programmable FIFO interrupt level. */ - if (devpriv->adcfifothresh != wake) { - devpriv->adcfifothresh = wake; - outw(wake, dev->iobase + PCI230P_ADCFFTH); - } - triglev = PCI230P_ADC_INT_FIFO_THRESH; - } else { - triglev = PCI230_ADC_INT_FIFO_NEMPTY; + } else if (wake > 1 && devpriv->hwver > 0) { + /* PCI230+/260+ programmable FIFO interrupt level. */ + if (devpriv->adcfifothresh != wake) { + devpriv->adcfifothresh = wake; + outw(wake, devpriv->daqio + PCI230P_ADCFFTH); } + triglev = PCI230P_ADC_INT_FIFO_THRESH; + } else { + triglev = PCI230_ADC_INT_FIFO_NEMPTY; } adccon = (devpriv->adccon & ~PCI230_ADC_INT_FIFO_MASK) | triglev; if (adccon != devpriv->adccon) { devpriv->adccon = adccon; - outw(adccon, dev->iobase + PCI230_ADCCON); + outw(adccon, devpriv->daqio + PCI230_ADCCON); } } @@ -1920,43 +1792,39 @@ static int pci230_ai_inttrig_convert(struct comedi_device *dev, { struct pci230_private *devpriv = dev->private; unsigned long irqflags; + unsigned int delayus; if (trig_num) return -EINVAL; spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); - if (test_bit(AI_CMD_STARTED, &devpriv->state)) { - unsigned int delayus; - - /* - * Trigger conversion by toggling Z2-CT2 output. - * Finish with output high. - */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE0); - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, - I8254_MODE1); - /* - * Delay. Should driver be responsible for this? An - * alternative would be to wait until conversion is complete, - * but we can't tell when it's complete because the ADC busy - * bit has a different meaning when FIFO enabled (and when - * FIFO not enabled, it only works for software triggers). - */ - if (((devpriv->adccon & PCI230_ADC_IM_MASK) == - PCI230_ADC_IM_DIF) && (devpriv->hwver == 0)) { - /* PCI230/260 in differential mode */ - delayus = 8; - } else { - /* single-ended or PCI230+/260+ */ - delayus = 4; - } + if (!devpriv->ai_cmd_started) { spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); - udelay(delayus); + return 1; + } + /* + * Trigger conversion by toggling Z2-CT2 output. + * Finish with output high. + */ + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); + /* + * Delay. Should driver be responsible for this? An + * alternative would be to wait until conversion is complete, + * but we can't tell when it's complete because the ADC busy + * bit has a different meaning when FIFO enabled (and when + * FIFO not enabled, it only works for software triggers). + */ + if ((devpriv->adccon & PCI230_ADC_IM_MASK) == PCI230_ADC_IM_DIF && + devpriv->hwver == 0) { + /* PCI230/260 in differential mode */ + delayus = 8; } else { - spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); + /* single-ended or PCI230+/260+ */ + delayus = 4; } - + spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); + udelay(delayus); return 1; } @@ -1972,12 +1840,12 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev, return -EINVAL; spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); - if (test_bit(AI_CMD_STARTED, &devpriv->state)) { + if (devpriv->ai_cmd_started) { /* Trigger scan by waggling CT0 gate source. */ zgat = GAT_CONFIG(0, GAT_GND); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); zgat = GAT_CONFIG(0, GAT_VCC); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); } spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); @@ -1990,10 +1858,11 @@ static void pci230_ai_stop(struct comedi_device *dev, struct pci230_private *devpriv = dev->private; unsigned long irqflags; struct comedi_cmd *cmd; - int started; + bool started; spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); - started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state); + started = devpriv->ai_cmd_started; + devpriv->ai_cmd_started = false; spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); if (!started) return; @@ -2011,15 +1880,12 @@ static void pci230_ai_stop(struct comedi_device *dev, * Disable ADC interrupt and wait for interrupt routine to finish * running unless we are called from the interrupt routine. */ - devpriv->int_en &= ~PCI230_INT_ADC; + devpriv->ier &= ~PCI230_INT_ADC; while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) { spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); } - if (devpriv->ier != devpriv->int_en) { - devpriv->ier = devpriv->int_en; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - } + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); /* * Reset FIFO, disable FIFO and set start conversion source to none. @@ -2029,9 +1895,9 @@ static void pci230_ai_stop(struct comedi_device *dev, (devpriv->adccon & (PCI230_ADC_IR_MASK | PCI230_ADC_IM_MASK)) | PCI230_ADC_TRIG_NONE; outw(devpriv->adccon | PCI230_ADC_FIFO_RESET, - dev->iobase + PCI230_ADCCON); + devpriv->daqio + PCI230_ADCCON); /* Release resources. */ - put_all_resources(dev, OWNER_AICMD); + pci230_release_all_resources(dev, OWNER_AICMD); } static void pci230_ai_start(struct comedi_device *dev, @@ -2043,145 +1909,132 @@ static void pci230_ai_start(struct comedi_device *dev, struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - set_bit(AI_CMD_STARTED, &devpriv->state); - if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { - /* An empty acquisition! */ - async->events |= COMEDI_CB_EOA; - pci230_ai_stop(dev, s); - comedi_event(dev, s); - } else { - /* Enable ADC FIFO trigger level interrupt. */ - spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - devpriv->int_en |= PCI230_INT_ADC; - devpriv->ier |= PCI230_INT_ADC; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + devpriv->ai_cmd_started = true; - /* - * Update conversion trigger source which is currently set - * to CT2 output, which is currently stuck high. - */ - switch (cmd->convert_src) { - default: - conv = PCI230_ADC_TRIG_NONE; - break; - case TRIG_TIMER: - /* Using CT2 output. */ - conv = PCI230_ADC_TRIG_Z2CT2; - break; - case TRIG_EXT: - if (cmd->convert_arg & CR_EDGE) { - if ((cmd->convert_arg & CR_INVERT) == 0) { - /* Trigger on +ve edge. */ - conv = PCI230_ADC_TRIG_EXTP; - } else { - /* Trigger on -ve edge. */ - conv = PCI230_ADC_TRIG_EXTN; - } + /* Enable ADC FIFO trigger level interrupt. */ + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + devpriv->ier |= PCI230_INT_ADC; + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + + /* + * Update conversion trigger source which is currently set + * to CT2 output, which is currently stuck high. + */ + switch (cmd->convert_src) { + default: + conv = PCI230_ADC_TRIG_NONE; + break; + case TRIG_TIMER: + /* Using CT2 output. */ + conv = PCI230_ADC_TRIG_Z2CT2; + break; + case TRIG_EXT: + if (cmd->convert_arg & CR_EDGE) { + if ((cmd->convert_arg & CR_INVERT) == 0) { + /* Trigger on +ve edge. */ + conv = PCI230_ADC_TRIG_EXTP; } else { - /* Backwards compatibility. */ - if (cmd->convert_arg) { - /* Trigger on +ve edge. */ - conv = PCI230_ADC_TRIG_EXTP; - } else { - /* Trigger on -ve edge. */ - conv = PCI230_ADC_TRIG_EXTN; - } + /* Trigger on -ve edge. */ + conv = PCI230_ADC_TRIG_EXTN; + } + } else { + /* Backwards compatibility. */ + if (cmd->convert_arg) { + /* Trigger on +ve edge. */ + conv = PCI230_ADC_TRIG_EXTP; + } else { + /* Trigger on -ve edge. */ + conv = PCI230_ADC_TRIG_EXTN; } - break; - case TRIG_INT: - /* - * Use CT2 output for software trigger due to problems - * in differential mode on PCI230/260. - */ - conv = PCI230_ADC_TRIG_Z2CT2; - break; } - devpriv->adccon = - (devpriv->adccon & ~PCI230_ADC_TRIG_MASK) | conv; - outw(devpriv->adccon, dev->iobase + PCI230_ADCCON); - if (cmd->convert_src == TRIG_INT) - async->inttrig = pci230_ai_inttrig_convert; - + break; + case TRIG_INT: /* - * Update FIFO interrupt trigger level, which is currently - * set to "full". + * Use CT2 output for software trigger due to problems + * in differential mode on PCI230/260. */ - pci230_ai_update_fifo_trigger_level(dev, s); - if (cmd->convert_src == TRIG_TIMER) { - /* Update timer gates. */ - unsigned char zgat; + conv = PCI230_ADC_TRIG_Z2CT2; + break; + } + devpriv->adccon = (devpriv->adccon & ~PCI230_ADC_TRIG_MASK) | conv; + outw(devpriv->adccon, devpriv->daqio + PCI230_ADCCON); + if (cmd->convert_src == TRIG_INT) + async->inttrig = pci230_ai_inttrig_convert; - if (cmd->scan_begin_src != TRIG_FOLLOW) { + /* + * Update FIFO interrupt trigger level, which is currently + * set to "full". + */ + pci230_ai_update_fifo_trigger_level(dev, s); + if (cmd->convert_src == TRIG_TIMER) { + /* Update timer gates. */ + unsigned char zgat; + + if (cmd->scan_begin_src != TRIG_FOLLOW) { + /* + * Conversion timer CT2 needs to be gated by + * inverted output of monostable CT2. + */ + zgat = GAT_CONFIG(2, GAT_NOUTNM2); + } else { + /* + * Conversion timer CT2 needs to be gated on + * continuously. + */ + zgat = GAT_CONFIG(2, GAT_VCC); + } + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); + if (cmd->scan_begin_src != TRIG_FOLLOW) { + /* Set monostable CT0 trigger source. */ + switch (cmd->scan_begin_src) { + default: + zgat = GAT_CONFIG(0, GAT_VCC); + break; + case TRIG_EXT: /* - * Conversion timer CT2 needs to be gated by - * inverted output of monostable CT2. + * For CT0 on PCI230, the external trigger + * (gate) signal comes from PPC0, which is + * channel 16 of the DIO subdevice. The + * application needs to configure this as an + * input in order to use it as an external scan + * trigger. */ - zgat = GAT_CONFIG(2, GAT_NOUTNM2); - } else { + zgat = GAT_CONFIG(0, GAT_EXT); + break; + case TRIG_TIMER: /* - * Conversion timer CT2 needs to be gated on - * continuously. + * Monostable CT0 triggered by rising edge on + * inverted output of CT1 (falling edge on CT1). */ - zgat = GAT_CONFIG(2, GAT_VCC); + zgat = GAT_CONFIG(0, GAT_NOUTNM2); + break; + case TRIG_INT: + /* + * Monostable CT0 is triggered by inttrig + * function waggling the CT0 gate source. + */ + zgat = GAT_CONFIG(0, GAT_VCC); + break; } - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); - if (cmd->scan_begin_src != TRIG_FOLLOW) { - /* Set monostable CT0 trigger source. */ - switch (cmd->scan_begin_src) { - default: - zgat = GAT_CONFIG(0, GAT_VCC); - break; - case TRIG_EXT: - /* - * For CT0 on PCI230, the external - * trigger (gate) signal comes from - * PPC0, which is channel 16 of the DIO - * subdevice. The application needs to - * configure this as an input in order - * to use it as an external scan - * trigger. - */ - zgat = GAT_CONFIG(0, GAT_EXT); - break; - case TRIG_TIMER: - /* - * Monostable CT0 triggered by rising - * edge on inverted output of CT1 - * (falling edge on CT1). - */ - zgat = GAT_CONFIG(0, GAT_NOUTNM2); - break; - case TRIG_INT: - /* - * Monostable CT0 is triggered by - * inttrig function waggling the CT0 - * gate source. - */ - zgat = GAT_CONFIG(0, GAT_VCC); - break; - } - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); - switch (cmd->scan_begin_src) { - case TRIG_TIMER: - /* - * Scan period timer CT1 needs to be - * gated on to start counting. - */ - zgat = GAT_CONFIG(1, GAT_VCC); - outb(zgat, devpriv->iobase1 + - PCI230_ZGAT_SCE); - break; - case TRIG_INT: - async->inttrig = - pci230_ai_inttrig_scan_begin; - break; - } + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); + switch (cmd->scan_begin_src) { + case TRIG_TIMER: + /* + * Scan period timer CT1 needs to be + * gated on to start counting. + */ + zgat = GAT_CONFIG(1, GAT_VCC); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); + break; + case TRIG_INT: + async->inttrig = pci230_ai_inttrig_scan_begin; + break; } - } else if (cmd->convert_src != TRIG_INT) { - /* No longer need Z2-CT2. */ - put_one_resource(dev, RES_Z2CT2, OWNER_AICMD); } + } else if (cmd->convert_src != TRIG_INT) { + /* No longer need Z2-CT2. */ + pci230_release_shared(dev, RES_Z2CT2, OWNER_AICMD); } } @@ -2218,12 +2071,11 @@ static void pci230_handle_ai(struct comedi_device *dev, todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } else if (devpriv->ai_scan_count == 0) { todo = 0; - } else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL) || - (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) { + } else if (devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL || + scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL) { todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } else { - todo = (devpriv->ai_scan_count * scanlen) - - devpriv->ai_scan_pos; + todo = devpriv->ai_scan_count * scanlen - devpriv->ai_scan_pos; if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL) todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } @@ -2233,7 +2085,7 @@ static void pci230_handle_ai(struct comedi_device *dev, for (i = 0; i < todo; i++) { if (fifoamount == 0) { /* Read FIFO state. */ - status_fifo = inw(dev->iobase + PCI230_ADCCON); + status_fifo = inw(devpriv->daqio + PCI230_ADCCON); if (status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) { /* * Report error otherwise FIFO overruns will go @@ -2248,19 +2100,15 @@ static void pci230_handle_ai(struct comedi_device *dev, } else if (status_fifo & PCI230_ADC_FIFO_HALF) { /* FIFO half full. */ fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL; + } else if (devpriv->hwver > 0) { + /* Read PCI230+/260+ ADC FIFO level. */ + fifoamount = inw(devpriv->daqio + + PCI230P_ADCFFLEV); + if (fifoamount == 0) + break; /* Shouldn't happen. */ } else { /* FIFO not empty. */ - if (devpriv->hwver > 0) { - /* Read PCI230+/260+ ADC FIFO level. */ - fifoamount = - inw(dev->iobase + PCI230P_ADCFFLEV); - if (fifoamount == 0) { - /* Shouldn't happen. */ - break; - } - } else { - fifoamount = 1; - } + fifoamount = 1; } } /* Read sample and store in Comedi's circular buffer. */ @@ -2316,25 +2164,20 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * Need Z2-CT2 to supply a conversion trigger source at a high * logic level, even if not doing timed conversions. */ - res_mask |= (1U << RES_Z2CT2); + res_mask |= RES_Z2CT2; if (cmd->scan_begin_src != TRIG_FOLLOW) { /* Using Z2-CT0 monostable to gate Z2-CT2 conversion timer */ - res_mask |= (1U << RES_Z2CT0); + res_mask |= RES_Z2CT0; if (cmd->scan_begin_src == TRIG_TIMER) { /* Using Z2-CT1 for scan frequency */ - res_mask |= (1U << RES_Z2CT1); + res_mask |= RES_Z2CT1; } } /* Claim resources. */ - if (!get_resources(dev, res_mask, OWNER_AICMD)) + if (!pci230_claim_shared(dev, res_mask, OWNER_AICMD)) return -EBUSY; - - /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scan_count = cmd->stop_arg; - else /* TRIG_NONE, user calls cancel */ - devpriv->ai_scan_count = 0; + devpriv->ai_scan_count = cmd->stop_arg; devpriv->ai_scan_pos = 0; /* Position within scan. */ /* @@ -2369,7 +2212,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } range = CR_RANGE(cmd->chanlist[0]); - devpriv->ai_bipolar = pci230_ai_bipolar[range]; + devpriv->ai_bipolar = comedi_range_is_bipolar(s, range); if (devpriv->ai_bipolar) adccon |= PCI230_ADC_IR_BIP; else @@ -2396,7 +2239,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) adcen |= 1 << gainshift; } } else { - gainshift = (chan & ~1); + gainshift = chan & ~1; adcen |= 1 << chan; } devpriv->adcg = (devpriv->adcg & ~(3 << gainshift)) | @@ -2404,16 +2247,16 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Set channel scan list. */ - outw(adcen, dev->iobase + PCI230_ADCEN); + outw(adcen, devpriv->daqio + PCI230_ADCEN); /* Set channel gains. */ - outw(devpriv->adcg, dev->iobase + PCI230_ADCG); + outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); /* * Set counter/timer 2 output high for use as the initial start * conversion source. */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); + i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); /* * Temporarily use CT2 output as conversion trigger source and @@ -2429,7 +2272,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * PCI230/260, but that will be dealt with later. */ devpriv->adccon = adccon; - outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); + outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON); /* * Delay - @@ -2443,7 +2286,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) usleep_range(25, 100); /* Reset FIFO again. */ - outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); + outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON); if (cmd->convert_src == TRIG_TIMER) { /* @@ -2452,7 +2295,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * connector: PCI230 pin 21, PCI260 pin 18. */ zgat = GAT_CONFIG(2, GAT_GND); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); /* Set counter/timer 2 to the specified conversion period. */ pci230_ct_setup_ns_mode(dev, 2, I8254_MODE3, cmd->convert_arg, cmd->flags); @@ -2470,11 +2313,11 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * source will be changed later. */ zgat = GAT_CONFIG(0, GAT_VCC); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); pci230_ct_setup_ns_mode(dev, 0, I8254_MODE1, ((uint64_t)cmd->convert_arg * cmd->scan_end_arg), - TRIG_ROUND_UP); + CMDF_ROUND_UP); if (cmd->scan_begin_src == TRIG_TIMER) { /* * Monostable on CT0 will be triggered by @@ -2483,7 +2326,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * Set up CT1 but gate it off for now. */ zgat = GAT_CONFIG(1, GAT_GND); - outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); + outb(zgat, dev->iobase + PCI230_ZGAT_SCE); pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3, cmd->scan_begin_arg, cmd->flags); @@ -2509,29 +2352,28 @@ static int pci230_ai_cancel(struct comedi_device *dev, /* Interrupt handler */ static irqreturn_t pci230_interrupt(int irq, void *d) { - unsigned char status_int, valid_status_int; + unsigned char status_int, valid_status_int, temp_ier; struct comedi_device *dev = (struct comedi_device *)d; struct pci230_private *devpriv = dev->private; struct comedi_subdevice *s; unsigned long irqflags; /* Read interrupt status/enable register. */ - status_int = inb(devpriv->iobase1 + PCI230_INT_STAT); + status_int = inb(dev->iobase + PCI230_INT_STAT); if (status_int == PCI230_INT_DISABLE) return IRQ_NONE; - spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - valid_status_int = devpriv->int_en & status_int; + valid_status_int = devpriv->ier & status_int; /* * Disable triggered interrupts. * (Only those interrupts that need re-enabling, are, later in the * handler). */ - devpriv->ier = devpriv->int_en & ~status_int; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - devpriv->intr_running = 1; + temp_ier = devpriv->ier & ~status_int; + outb(temp_ier, dev->iobase + PCI230_INT_SCE); + devpriv->intr_running = true; devpriv->intr_cpuid = THISCPU; spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); @@ -2563,11 +2405,9 @@ static irqreturn_t pci230_interrupt(int irq, void *d) /* Reenable interrupts. */ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - if (devpriv->ier != devpriv->int_en) { - devpriv->ier = devpriv->int_en; - outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - } - devpriv->intr_running = 0; + if (devpriv->ier != temp_ier) + outb(devpriv->ier, dev->iobase + PCI230_INT_SCE); + devpriv->intr_running = false; spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); return IRQ_HANDLED; @@ -2603,49 +2443,17 @@ static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev) return NULL; } -/* Look for PCI device matching requested board name, bus and slot. */ -static struct pci_dev *pci230_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - const struct pci230_board *thisboard = comedi_board(dev); - struct pci_dev *pci_dev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pci_dev) { - /* Check vendor ID (same for all supported PCI boards). */ - if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON) - continue; - /* If bus/slot specified, check them. */ - if ((bus || slot) && - (bus != pci_dev->bus->number || - slot != PCI_SLOT(pci_dev->devfn))) - continue; - if (thisboard->id == PCI_DEVICE_ID_INVALID) { - /* Wildcard board matches any supported PCI board. */ - const struct pci230_board *foundboard; - - foundboard = pci230_find_pci_board(pci_dev); - if (foundboard == NULL) - continue; - /* Replace wildcard board_ptr. */ - dev->board_ptr = foundboard; - } else { - /* Need to match a specific board. */ - if (!pci230_match_pci_board(thisboard, pci_dev)) - continue; - } - return pci_dev; - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -static int pci230_alloc_private(struct comedi_device *dev) +static int pci230_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { + struct pci_dev *pci_dev = comedi_to_pci_dev(dev); + const struct pci230_board *thisboard; struct pci230_private *devpriv; + struct comedi_subdevice *s; + int rc; + + dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n", + pci_name(pci_dev)); devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -2655,22 +2463,14 @@ static int pci230_alloc_private(struct comedi_device *dev) spin_lock_init(&devpriv->res_spinlock); spin_lock_init(&devpriv->ai_stop_spinlock); spin_lock_init(&devpriv->ao_stop_spinlock); - return 0; -} - -/* Common part of attach and auto_attach. */ -static int pci230_attach_common(struct comedi_device *dev, - struct pci_dev *pci_dev) -{ - const struct pci230_board *thisboard = comedi_board(dev); - struct pci230_private *devpriv = dev->private; - struct comedi_subdevice *s; - unsigned long iobase1, iobase2; - /* PCI230's I/O spaces 1 and 2 respectively. */ - int rc; - - comedi_set_hw_dev(dev, &pci_dev->dev); + dev->board_ptr = pci230_find_pci_board(pci_dev); + if (dev->board_ptr == NULL) { + dev_err(dev->class_dev, + "amplc_pci230: BUG! cannot determine board type!\n"); + return -EINVAL; + } + thisboard = dev->board_ptr; dev->board_name = thisboard->name; rc = comedi_pci_enable(dev); @@ -2681,15 +2481,14 @@ static int pci230_attach_common(struct comedi_device *dev, * Read base addresses of the PCI230's two I/O regions from PCI * configuration register. */ - iobase1 = pci_resource_start(pci_dev, 2); - iobase2 = pci_resource_start(pci_dev, 3); + dev->iobase = pci_resource_start(pci_dev, 2); + devpriv->daqio = pci_resource_start(pci_dev, 3); dev_dbg(dev->class_dev, "%s I/O region 1 0x%04lx I/O region 2 0x%04lx\n", - dev->board_name, iobase1, iobase2); - devpriv->iobase1 = iobase1; - dev->iobase = iobase2; + dev->board_name, dev->iobase, devpriv->daqio); /* Read bits of DACCON register - only the output range. */ - devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK; + devpriv->daccon = inw(devpriv->daqio + PCI230_DACCON) & + PCI230_DAC_OR_MASK; /* * Read hardware version register and set extended function register * if they exist. @@ -2697,7 +2496,7 @@ static int pci230_attach_common(struct comedi_device *dev, if (pci_resource_len(pci_dev, 3) >= 32) { unsigned short extfunc = 0; - devpriv->hwver = inw(dev->iobase + PCI230P_HWVER); + devpriv->hwver = inw(devpriv->daqio + PCI230P_HWVER); if (devpriv->hwver < thisboard->min_hwver) { dev_err(dev->class_dev, "%s - bad hardware version - got %u, need %u\n", @@ -2716,13 +2515,12 @@ static int pci230_attach_common(struct comedi_device *dev, */ extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG; } - if ((thisboard->ao_chans > 0) && - (devpriv->hwver >= 2)) { + if (thisboard->ao_bits && devpriv->hwver >= 2) { /* Enable DAC FIFO functionality. */ extfunc |= PCI230P2_EXTFUNC_DACFIFO; } } - outw(extfunc, dev->iobase + PCI230P_EXTFUNC); + outw(extfunc, devpriv->daqio + PCI230P_EXTFUNC); if (extfunc & PCI230P2_EXTFUNC_DACFIFO) { /* * Temporarily enable DAC FIFO, reset it and disable @@ -2730,23 +2528,23 @@ static int pci230_attach_common(struct comedi_device *dev, */ outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN | PCI230P2_DAC_FIFO_RESET, - dev->iobase + PCI230_DACCON); + devpriv->daqio + PCI230_DACCON); /* Clear DAC FIFO channel enable register. */ - outw(0, dev->iobase + PCI230P2_DACEN); + outw(0, devpriv->daqio + PCI230P2_DACEN); /* Disable DAC FIFO. */ - outw(devpriv->daccon, dev->iobase + PCI230_DACCON); + outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON); } } /* Disable board's interrupts. */ - outb(0, devpriv->iobase1 + PCI230_INT_SCE); + outb(0, dev->iobase + PCI230_INT_SCE); /* Set ADC to a reasonable state. */ devpriv->adcg = 0; devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE | PCI230_ADC_IR_BIP; - outw(1 << 0, dev->iobase + PCI230_ADCEN); - outw(devpriv->adcg, dev->iobase + PCI230_ADCG); + outw(1 << 0, devpriv->daqio + PCI230_ADCEN); + outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); outw(devpriv->adccon | PCI230_ADC_FIFO_RESET, - dev->iobase + PCI230_ADCCON); + devpriv->daqio + PCI230_ADCCON); if (pci_dev->irq) { rc = request_irq(pci_dev->irq, pci230_interrupt, IRQF_SHARED, @@ -2763,10 +2561,10 @@ static int pci230_attach_common(struct comedi_device *dev, /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND; - s->n_chan = thisboard->ai_chans; + s->n_chan = 16; s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = &pci230_ai_range; - s->insn_read = pci230_ai_rinsn; + s->insn_read = pci230_ai_insn_read; s->len_chanlist = 256; /* but there are restrictions. */ if (dev->irq) { dev->read_subdev = s; @@ -2778,15 +2576,15 @@ static int pci230_attach_common(struct comedi_device *dev, s = &dev->subdevices[1]; /* analog output subdevice */ - if (thisboard->ao_chans > 0) { + if (thisboard->ao_bits) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = thisboard->ao_chans; + s->n_chan = 2; s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = &pci230_ao_range; - s->insn_write = pci230_ao_winsn; - s->insn_read = pci230_ao_rinsn; - s->len_chanlist = thisboard->ao_chans; + s->insn_write = pci230_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + s->len_chanlist = 2; if (dev->irq) { dev->write_subdev = s; s->subdev_flags |= SDF_CMD_WRITE; @@ -2794,6 +2592,10 @@ static int pci230_attach_common(struct comedi_device *dev, s->do_cmdtest = pci230_ao_cmdtest; s->cancel = pci230_ao_cancel; } + + rc = comedi_alloc_subdev_readback(s); + if (rc) + return rc; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -2801,8 +2603,7 @@ static int pci230_attach_common(struct comedi_device *dev, s = &dev->subdevices[2]; /* digital i/o subdevice */ if (thisboard->have_dio) { - rc = subdev_8255_init(dev, s, NULL, - devpriv->iobase1 + PCI230_PPI_X_BASE); + rc = subdev_8255_init(dev, s, NULL, PCI230_PPI_X_BASE); if (rc) return rc; } else { @@ -2812,74 +2613,11 @@ static int pci230_attach_common(struct comedi_device *dev, return 0; } -static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct pci230_board *thisboard = comedi_board(dev); - struct pci_dev *pci_dev; - int rc; - - dev_info(dev->class_dev, "amplc_pci230: attach %s %d,%d\n", - thisboard->name, it->options[0], it->options[1]); - - rc = pci230_alloc_private(dev); - if (rc) - return rc; - - pci_dev = pci230_find_pci_dev(dev, it); - if (!pci_dev) - return -EIO; - return pci230_attach_common(dev, pci_dev); -} - -static int pci230_auto_attach(struct comedi_device *dev, - unsigned long context_unused) -{ - struct pci_dev *pci_dev = comedi_to_pci_dev(dev); - int rc; - - dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n", - pci_name(pci_dev)); - - rc = pci230_alloc_private(dev); - if (rc) - return rc; - - dev->board_ptr = pci230_find_pci_board(pci_dev); - if (dev->board_ptr == NULL) { - dev_err(dev->class_dev, - "amplc_pci230: BUG! cannot determine board type!\n"); - return -EINVAL; - } - /* - * Need to 'get' the PCI device to match the 'put' in pci230_detach(). - * TODO: Remove the pci_dev_get() and matching pci_dev_put() once - * support for manual attachment of PCI devices via pci230_attach() - * has been removed. - */ - pci_dev_get(pci_dev); - return pci230_attach_common(dev, pci_dev); -} - -static void pci230_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); - if (pcidev) - pci_dev_put(pcidev); -} - static struct comedi_driver amplc_pci230_driver = { .driver_name = "amplc_pci230", .module = THIS_MODULE, - .attach = pci230_attach, .auto_attach = pci230_auto_attach, - .detach = pci230_detach, - .board_name = &pci230_boards[0].name, - .offset = sizeof(pci230_boards[0]), - .num_names = ARRAY_SIZE(pci230_boards), + .detach = comedi_pci_detach, }; static int amplc_pci230_pci_probe(struct pci_dev *dev, @@ -2905,5 +2643,5 @@ static struct pci_driver amplc_pci230_pci_driver = { module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Amplicon PCI230(+) and PCI260(+)"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_pci236.c b/drivers/staging/comedi/drivers/amplc_pci236.c index 436aebaf7621..ad1e93dd13a0 100644 --- a/drivers/staging/comedi/drivers/amplc_pci236.c +++ b/drivers/staging/comedi/drivers/amplc_pci236.c @@ -119,18 +119,11 @@ static int pci236_auto_attach(struct comedi_device *dev, IRQF_SHARED); } -static void pci236_detach(struct comedi_device *dev) -{ - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); -} - static struct comedi_driver amplc_pci236_driver = { .driver_name = "amplc_pci236", .module = THIS_MODULE, .auto_attach = pci236_auto_attach, - .detach = pci236_detach, + .detach = comedi_pci_detach, }; static const struct pci_device_id pci236_pci_table[] = { diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index 748a6b108f32..2259bee98d48 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -86,7 +86,7 @@ static struct comedi_driver amplc_pci263_driver = { .driver_name = "amplc_pci263", .module = THIS_MODULE, .auto_attach = pci263_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static const struct pci_device_id pci263_pci_table[] = { diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 853733e28845..f88880aea6da 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -79,7 +79,6 @@ static const struct das16cs_board das16cs_boards[] = { }; struct das16cs_private { - unsigned int ao_readback[2]; unsigned short status1; unsigned short status2; }; @@ -153,20 +152,20 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, return i; } -static int das16cs_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16cs_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das16cs_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; unsigned short status1; - unsigned short d; int bit; + int i; for (i = 0; i < insn->n; i++) { - devpriv->ao_readback[chan] = data[i]; - d = data[i]; + val = data[i]; outw(devpriv->status1, dev->iobase + DAS16CS_MISC1); udelay(1); @@ -181,7 +180,7 @@ static int das16cs_ao_winsn(struct comedi_device *dev, udelay(1); for (bit = 15; bit >= 0; bit--) { - int b = (d >> bit) & 0x1; + int b = (val >> bit) & 0x1; b <<= 1; outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1); @@ -195,22 +194,9 @@ static int das16cs_ao_winsn(struct comedi_device *dev, */ outw(status1 | 0x9, dev->iobase + DAS16CS_MISC1); } + s->readback[chan] = val; - return i; -} - -static int das16cs_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct das16cs_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int das16cs_dio_insn_bits(struct comedi_device *dev, @@ -318,8 +304,12 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->n_chan = board->n_ao_chans; s->maxdata = 0xffff; s->range_table = &range_bipolar10; - s->insn_write = &das16cs_ao_winsn; - s->insn_read = &das16cs_ao_rinsn; + s->insn_write = &das16cs_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 4a7bd4e5dd72..1ec363b7505c 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -342,7 +342,6 @@ struct cb_pcidas_private { unsigned long s5933_config; unsigned long control_status; unsigned long adc_fifo; - unsigned long pacer_counter_dio; unsigned long ao_registers; /* divisors of master clock for analog input pacing */ unsigned int divisor1; @@ -361,8 +360,6 @@ struct cb_pcidas_private { unsigned int ao_divisor2; /* number of analog output samples remaining */ unsigned int ao_count; - /* cached values for readback */ - unsigned short ao_value[2]; unsigned int caldac_value[NUM_CHANNELS_8800]; unsigned int trimpot_value[NUM_CHANNELS_8402]; unsigned int dac08_value; @@ -485,7 +482,7 @@ static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev, spin_unlock_irqrestore(&dev->spinlock, flags); /* remember value for readback */ - devpriv->ao_value[chan] = data[0]; + s->readback[chan] = data[0]; /* send data */ outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan)); @@ -516,7 +513,7 @@ static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, spin_unlock_irqrestore(&dev->spinlock, flags); /* remember value for readback */ - devpriv->ao_value[chan] = data[0]; + s->readback[chan] = data[0]; /* send data */ outw(data[0], devpriv->ao_registers + DACDATA); @@ -524,18 +521,6 @@ static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, return insn->n; } -static int cb_pcidas_ao_readback_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct cb_pcidas_private *devpriv = dev->private; - - data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; - - return 1; -} - static int wait_for_nvram_ready(unsigned long s5933_base_addr) { static const int timeout = 1000; @@ -758,7 +743,7 @@ static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, static int cb_pcidas_trimpot_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { - const struct cb_pcidas_board *thisboard = comedi_board(dev); + const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; if (devpriv->trimpot_value[channel] == value) @@ -832,7 +817,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct cb_pcidas_board *thisboard = comedi_board(dev); + const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -901,7 +886,9 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -942,7 +929,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, static void cb_pcidas_ai_load_counters(struct comedi_device *dev) { struct cb_pcidas_private *devpriv = dev->private; - unsigned long timer_base = devpriv->pacer_counter_dio + ADC8254; + unsigned long timer_base = dev->iobase + ADC8254; i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); @@ -954,7 +941,7 @@ static void cb_pcidas_ai_load_counters(struct comedi_device *dev) static int cb_pcidas_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct cb_pcidas_board *thisboard = comedi_board(dev); + const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -996,7 +983,7 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, spin_lock_irqsave(&dev->spinlock, flags); devpriv->adc_fifo_bits |= INTE; devpriv->adc_fifo_bits &= ~INT_MASK; - if (cmd->flags & TRIG_WAKE_EOS) { + 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; @@ -1057,7 +1044,7 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct cb_pcidas_board *thisboard = comedi_board(dev); + const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -1094,7 +1081,9 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -1149,7 +1138,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { - const struct cb_pcidas_board *thisboard = comedi_board(dev); + const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; unsigned int num_bytes, num_points = thisboard->fifo_size; struct comedi_async *async = s->async; @@ -1194,7 +1183,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, static void cb_pcidas_ao_load_counters(struct comedi_device *dev) { struct cb_pcidas_private *devpriv = dev->private; - unsigned long timer_base = devpriv->pacer_counter_dio + DAC8254; + unsigned long timer_base = dev->iobase + DAC8254; i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); @@ -1281,7 +1270,7 @@ static int cb_pcidas_ao_cancel(struct comedi_device *dev, static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) { - const struct cb_pcidas_board *thisboard = comedi_board(dev); + const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; struct comedi_subdevice *s = dev->write_subdev; struct comedi_async *async = s->async; @@ -1336,7 +1325,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) static irqreturn_t cb_pcidas_interrupt(int irq, void *d) { struct comedi_device *dev = (struct comedi_device *)d; - const struct cb_pcidas_board *thisboard = comedi_board(dev); + const struct cb_pcidas_board *thisboard = dev->board_ptr; struct cb_pcidas_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async; @@ -1463,7 +1452,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, 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->pacer_counter_dio = pci_resource_start(pcidev, 3); + dev->iobase = pci_resource_start(pcidev, 3); if (thisboard->ao_nchan) devpriv->ao_registers = pci_resource_start(pcidev, 4); @@ -1512,16 +1501,22 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, */ s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = &cb_pcidas_ao_ranges; - s->insn_read = cb_pcidas_ao_readback_insn; + /* default to no fifo (*insn_write) */ + s->insn_write = cb_pcidas_ao_nofifo_winsn; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + if (thisboard->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; - } else { - s->insn_write = cb_pcidas_ao_nofifo_winsn; } } else { s->type = COMEDI_SUBD_UNUSED; @@ -1529,8 +1524,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, /* 8255 */ s = &dev->subdevices[2]; - ret = subdev_8255_init(dev, s, NULL, - devpriv->pacer_counter_dio + DIO_8255); + ret = subdev_8255_init(dev, s, NULL, DIO_8255); if (ret) return ret; @@ -1599,15 +1593,11 @@ static void cb_pcidas_detach(struct comedi_device *dev) { struct cb_pcidas_private *devpriv = dev->private; - if (devpriv) { - if (devpriv->s5933_config) { - outl(INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); - } + if (devpriv && devpriv->s5933_config) { + outl(INTCSR_INBOX_INTR_STATUS, + devpriv->s5933_config + AMCC_OP_REG_INTCSR); } - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver cb_pcidas_driver = { diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index fa12614cef2a..3b6bffc66918 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1038,7 +1038,7 @@ static const struct pcidas64_board pcidas64_boards[] = { static inline unsigned short se_diff_bit_6xxx(struct comedi_device *dev, int use_differential) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; if ((thisboard->layout == LAYOUT_64XX && !use_differential) || (thisboard->layout == LAYOUT_60XX && use_differential)) @@ -1089,8 +1089,6 @@ struct pcidas64_private { unsigned int ao_dma_index; /* number of analog output samples remaining */ unsigned long ao_count; - /* remember what the analog outputs are set to, to allow readback */ - unsigned int ao_value[2]; unsigned int hw_revision; /* stc chip hardware revision number */ /* last bits sent to INTR_ENABLE_REG register */ unsigned int intr_enable_bits; @@ -1123,7 +1121,7 @@ struct pcidas64_private { static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, unsigned int range_index) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; const struct comedi_krange *range = &thisboard->ai_range_table->range[range_index]; unsigned int bits = 0; @@ -1168,7 +1166,7 @@ static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, static unsigned int hw_revision(const struct comedi_device *dev, uint16_t hw_status_bits) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; if (thisboard->layout == LAYOUT_4020) return (hw_status_bits >> 13) & 0x7; @@ -1180,7 +1178,7 @@ static void set_dac_range_bits(struct comedi_device *dev, uint16_t *bits, unsigned int channel, unsigned int range) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; unsigned int code = thisboard->ao_range_code[range]; if (channel > 1) @@ -1237,7 +1235,7 @@ static void disable_ai_interrupts(struct comedi_device *dev) static void enable_ai_interrupts(struct comedi_device *dev, const struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; uint32_t bits; unsigned long flags; @@ -1245,8 +1243,8 @@ static void enable_ai_interrupts(struct comedi_device *dev, bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT | EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT; /* Use pio transfer and interrupt on end of conversion - * if TRIG_WAKE_EOS flag is set. */ - if (cmd->flags & TRIG_WAKE_EOS) { + * if CMDF_WAKE_EOS flag is set. */ + if (cmd->flags & CMDF_WAKE_EOS) { /* 4020 doesn't support pio transfers except for fifo dregs */ if (thisboard->layout != LAYOUT_4020) bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT; @@ -1261,7 +1259,7 @@ static void enable_ai_interrupts(struct comedi_device *dev, /* initialize plx9080 chip */ static void init_plx9080(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; uint32_t bits; void __iomem *plx_iobase = devpriv->plx9080_iobase; @@ -1339,7 +1337,7 @@ static void disable_ai_pacing(struct comedi_device *dev) static int set_ai_fifo_segment_length(struct comedi_device *dev, unsigned int num_entries) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; static const int increment_size = 0x100; const struct hw_fifo_info *const fifo = thisboard->ai_fifo; @@ -1368,7 +1366,7 @@ static int set_ai_fifo_segment_length(struct comedi_device *dev, /* adjusts the size of hardware fifo (which determines block size for dma xfers) */ static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; unsigned int num_fifo_entries; int retval; const struct hw_fifo_info *const fifo = thisboard->ai_fifo; @@ -1389,7 +1387,7 @@ static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples) /* query length of fifo */ static unsigned int ai_fifo_size(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; return devpriv->ai_fifo_segment_length * @@ -1399,7 +1397,7 @@ static unsigned int ai_fifo_size(struct comedi_device *dev) static void init_stc_registers(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; uint16_t bits; unsigned long flags; @@ -1445,7 +1443,7 @@ static void init_stc_registers(struct comedi_device *dev) static int alloc_and_init_dma_members(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct pcidas64_private *devpriv = dev->private; int i; @@ -1526,6 +1524,46 @@ static int alloc_and_init_dma_members(struct comedi_device *dev) return 0; } +static void cb_pcidas64_free_dma(struct comedi_device *dev) +{ + const struct pcidas64_board *thisboard = dev->board_ptr; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct pcidas64_private *devpriv = dev->private; + int i; + + if (!devpriv) + return; + + /* free pci dma buffers */ + for (i = 0; i < ai_dma_ring_count(thisboard); i++) { + if (devpriv->ai_buffer[i]) + pci_free_consistent(pcidev, + DMA_BUFFER_SIZE, + devpriv->ai_buffer[i], + devpriv->ai_buffer_bus_addr[i]); + } + for (i = 0; i < AO_DMA_RING_COUNT; i++) { + if (devpriv->ao_buffer[i]) + pci_free_consistent(pcidev, + DMA_BUFFER_SIZE, + devpriv->ao_buffer[i], + devpriv->ao_buffer_bus_addr[i]); + } + /* free dma descriptors */ + if (devpriv->ai_dma_desc) + pci_free_consistent(pcidev, + sizeof(struct plx_dma_desc) * + ai_dma_ring_count(thisboard), + devpriv->ai_dma_desc, + devpriv->ai_dma_desc_bus_addr); + if (devpriv->ao_dma_desc) + pci_free_consistent(pcidev, + sizeof(struct plx_dma_desc) * + AO_DMA_RING_COUNT, + devpriv->ao_dma_desc, + devpriv->ao_dma_desc_bus_addr); +} + static inline void warn_external_queue(struct comedi_device *dev) { dev_err(dev->class_dev, @@ -1668,7 +1706,7 @@ static int cb_pcidas64_ai_eoc(struct comedi_device *dev, struct comedi_insn *insn, unsigned long context) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; unsigned int status; @@ -1687,7 +1725,7 @@ static int cb_pcidas64_ai_eoc(struct comedi_device *dev, static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; unsigned int bits = 0, n; unsigned int channel, range, aref; @@ -1807,7 +1845,7 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, static int ai_config_calibration_source(struct comedi_device *dev, unsigned int *data) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; unsigned int source = data[1]; int num_calibration_sources; @@ -1829,7 +1867,7 @@ static int ai_config_calibration_source(struct comedi_device *dev, static int ai_config_block_size(struct comedi_device *dev, unsigned int *data) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; int fifo_size; const struct hw_fifo_info *const fifo = thisboard->ai_fifo; unsigned int block_size, requested_block_size; @@ -1883,7 +1921,7 @@ static int ai_config_master_clock_4020(struct comedi_device *dev, /* XXX could add support for 60xx series */ static int ai_config_master_clock(struct comedi_device *dev, unsigned int *data) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; switch (thisboard->layout) { case LAYOUT_4020: @@ -1920,14 +1958,14 @@ static unsigned int get_divisor(unsigned int ns, unsigned int flags) { unsigned int divisor; - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_UP: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_UP: divisor = (ns + TIMER_BASE - 1) / TIMER_BASE; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: divisor = ns / TIMER_BASE; break; - case TRIG_ROUND_NEAREST: + case CMDF_ROUND_NEAREST: default: divisor = (ns + TIMER_BASE / 2) / TIMER_BASE; break; @@ -1941,7 +1979,7 @@ static unsigned int get_divisor(unsigned int ns, unsigned int flags) */ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; unsigned int convert_divisor = 0, scan_divisor; static const int min_convert_divisor = 3; static const int max_convert_divisor = @@ -1989,7 +2027,7 @@ static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcidas64_board *board = comedi_board(dev); + const struct pcidas64_board *board = dev->board_ptr; unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; @@ -2028,7 +2066,7 @@ static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev, static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; int err = 0; unsigned int tmp_arg, tmp_arg2; unsigned int triggers; @@ -2178,7 +2216,7 @@ static void setup_sample_counters(struct comedi_device *dev, static inline unsigned int dma_transfer_size(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; unsigned int num_samples; @@ -2265,7 +2303,7 @@ static void select_master_clock_4020(struct comedi_device *dev, static void select_master_clock(struct comedi_device *dev, const struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; switch (thisboard->layout) { case LAYOUT_4020: @@ -2297,7 +2335,7 @@ static inline void dma_start_sync(struct comedi_device *dev, static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; uint32_t convert_counter = 0, scan_counter = 0; @@ -2346,7 +2384,7 @@ static int use_internal_queue_6xxx(const struct comedi_cmd *cmd) static int setup_channel_queue(struct comedi_device *dev, const struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; unsigned short bits; int i; @@ -2483,7 +2521,7 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev, static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -2541,7 +2579,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* clear adc buffer */ writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG); - if ((cmd->flags & TRIG_WAKE_EOS) == 0 || + if ((cmd->flags & CMDF_WAKE_EOS) == 0 || thisboard->layout == LAYOUT_4020) { devpriv->ai_dma_index = 0; @@ -2575,7 +2613,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* enable pacing, triggering, etc */ bits = ADC_ENABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT; - if (cmd->flags & TRIG_WAKE_EOS) + if (cmd->flags & CMDF_WAKE_EOS) bits |= ADC_DMA_DISABLE_BIT; /* set start trigger */ if (cmd->start_src == TRIG_EXT) { @@ -2700,7 +2738,7 @@ static void pio_drain_ai_fifo_32(struct comedi_device *dev) /* empty fifo */ static void pio_drain_ai_fifo(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; if (thisboard->layout == LAYOUT_4020) pio_drain_ai_fifo_32(dev); @@ -2710,7 +2748,7 @@ static void pio_drain_ai_fifo(struct comedi_device *dev) static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; struct comedi_async *async = dev->read_subdev->async; struct comedi_cmd *cmd = &async->cmd; @@ -2755,7 +2793,7 @@ static void handle_ai_interrupt(struct comedi_device *dev, unsigned short status, unsigned int plx_status) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; @@ -2782,7 +2820,7 @@ static void handle_ai_interrupt(struct comedi_device *dev, /* drain fifo with pio */ if ((status & ADC_DONE_BIT) || - ((cmd->flags & TRIG_WAKE_EOS) && + ((cmd->flags & CMDF_WAKE_EOS) && (status & ADC_INTR_PENDING_BIT) && (thisboard->layout != LAYOUT_4020))) { spin_lock_irqsave(&dev->spinlock, flags); @@ -3037,7 +3075,7 @@ static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); @@ -3061,18 +3099,7 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, } /* remember output value */ - devpriv->ao_value[chan] = data[0]; - - return 1; -} - -static int ao_readback_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pcidas64_private *devpriv = dev->private; - - data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; + s->readback[chan] = data[0]; return 1; } @@ -3200,7 +3227,7 @@ static inline int external_ai_queue_in_use(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; if (s->busy) return 0; @@ -3284,7 +3311,7 @@ static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev, static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; int err = 0; unsigned int tmp_arg; @@ -3369,26 +3396,16 @@ static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -static int dio_callback(int dir, int port, int data, unsigned long arg) -{ - void __iomem *iobase = (void __iomem *)arg; - - if (dir) { - writeb(data, iobase + port); - return 0; - } - return readb(iobase + port); -} - -static int dio_callback_4020(int dir, int port, int data, unsigned long arg) +static int dio_callback_4020(struct comedi_device *dev, + int dir, int port, int data, unsigned long iobase) { - void __iomem *iobase = (void __iomem *)arg; + struct pcidas64_private *devpriv = dev->private; if (dir) { - writew(data, iobase + 2 * port); + writew(data, devpriv->main_iobase + iobase + 2 * port); return 0; } - return readw(iobase + 2 * port); + return readw(devpriv->main_iobase + iobase + 2 * port); } static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, @@ -3562,7 +3579,7 @@ static int caldac_i2c_write(struct comedi_device *dev, static void caldac_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; devpriv->caldac_state[channel] = value; @@ -3748,10 +3765,9 @@ static int eeprom_read_insn(struct comedi_device *dev, */ static int setup_subdevices(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); + const struct pcidas64_board *thisboard = dev->board_ptr; struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s; - void __iomem *dio_8255_iobase; int i; int ret; @@ -3799,8 +3815,13 @@ static int setup_subdevices(struct comedi_device *dev) s->n_chan = thisboard->ao_nchan; s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = thisboard->ao_range_table; - s->insn_read = ao_readback_insn; s->insn_write = ao_winsn; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + if (ao_cmd_is_supported(thisboard)) { dev->write_subdev = s; s->do_cmdtest = ao_cmdtest; @@ -3840,13 +3861,11 @@ static int setup_subdevices(struct comedi_device *dev) s = &dev->subdevices[4]; if (thisboard->has_8255) { if (thisboard->layout == LAYOUT_4020) { - dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG; ret = subdev_8255_init(dev, s, dio_callback_4020, - (unsigned long)dio_8255_iobase); + I8255_4020_REG); } else { - dio_8255_iobase = dev->mmio + DIO_8255_OFFSET; - ret = subdev_8255_init(dev, s, dio_callback, - (unsigned long)dio_8255_iobase); + ret = subdev_8255_mm_init(dev, s, NULL, + DIO_8255_OFFSET); } if (ret) return ret; @@ -3996,54 +4015,22 @@ static int auto_attach(struct comedi_device *dev, static void detach(struct comedi_device *dev) { - const struct pcidas64_board *thisboard = comedi_board(dev); - struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct pcidas64_private *devpriv = dev->private; - unsigned int i; if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { - if (pcidev) { - if (devpriv->plx9080_iobase) { - disable_plx_interrupts(dev); - iounmap(devpriv->plx9080_iobase); - } - if (devpriv->main_iobase) - iounmap(devpriv->main_iobase); - if (dev->mmio) - iounmap(dev->mmio); - /* free pci dma buffers */ - for (i = 0; i < ai_dma_ring_count(thisboard); i++) { - if (devpriv->ai_buffer[i]) - pci_free_consistent(pcidev, - DMA_BUFFER_SIZE, - devpriv->ai_buffer[i], - devpriv->ai_buffer_bus_addr[i]); - } - for (i = 0; i < AO_DMA_RING_COUNT; i++) { - if (devpriv->ao_buffer[i]) - pci_free_consistent(pcidev, - DMA_BUFFER_SIZE, - devpriv->ao_buffer[i], - devpriv->ao_buffer_bus_addr[i]); - } - /* free dma descriptors */ - if (devpriv->ai_dma_desc) - pci_free_consistent(pcidev, - sizeof(struct plx_dma_desc) * - ai_dma_ring_count(thisboard), - devpriv->ai_dma_desc, - devpriv->ai_dma_desc_bus_addr); - if (devpriv->ao_dma_desc) - pci_free_consistent(pcidev, - sizeof(struct plx_dma_desc) * - AO_DMA_RING_COUNT, - devpriv->ao_dma_desc, - devpriv->ao_dma_desc_bus_addr); + if (devpriv->plx9080_iobase) { + disable_plx_interrupts(dev); + iounmap(devpriv->plx9080_iobase); } + if (devpriv->main_iobase) + iounmap(devpriv->main_iobase); + if (dev->mmio) + iounmap(dev->mmio); } comedi_pci_disable(dev); + cb_pcidas64_free_dma(dev); } static struct comedi_driver cb_pcidas64_driver = { diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 901dc5d1bb72..01875d7c376f 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -154,6 +154,7 @@ static const struct cb_pcidda_board cb_pcidda_boards[] = { }; struct cb_pcidda_private { + unsigned long daqio; /* bits last written to da calibration register 1 */ unsigned int dac_cal1_bits; /* current range settings for output channels */ @@ -164,13 +165,14 @@ struct cb_pcidda_private { /* lowlevel read from eeprom */ static unsigned int cb_pcidda_serial_in(struct comedi_device *dev) { + struct cb_pcidda_private *devpriv = dev->private; unsigned int value = 0; int i; const int value_width = 16; /* number of bits wide values are */ for (i = 1; i <= value_width; i++) { /* read bits most significant bit first */ - if (inw_p(dev->iobase + DACALIBRATION1) & SERIAL_OUT_BIT) + if (inw_p(devpriv->daqio + DACALIBRATION1) & SERIAL_OUT_BIT) value |= 1 << (value_width - i); } @@ -190,7 +192,7 @@ static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, devpriv->dac_cal1_bits |= SERIAL_IN_BIT; else devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT; - outw_p(devpriv->dac_cal1_bits, dev->iobase + DACALIBRATION1); + outw_p(devpriv->dac_cal1_bits, devpriv->daqio + DACALIBRATION1); } } @@ -198,6 +200,7 @@ static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, unsigned int address) { + struct cb_pcidda_private *devpriv = dev->private; unsigned int i; unsigned int cal2_bits; unsigned int value; @@ -213,7 +216,7 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, /* deactivate caldacs (one caldac for every two channels) */ for (i = 0; i < max_num_caldacs; i++) cal2_bits |= DESELECT_CALDAC_BIT(i); - outw_p(cal2_bits, dev->iobase + DACALIBRATION2); + outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2); /* tell eeprom we want to read */ cb_pcidda_serial_out(dev, read_instruction, instruction_length); @@ -224,7 +227,7 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, /* deactivate eeprom */ cal2_bits &= ~SELECT_EEPROM_BIT; - outw_p(cal2_bits, dev->iobase + DACALIBRATION2); + outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2); return value; } @@ -234,6 +237,7 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev, unsigned int caldac, unsigned int channel, unsigned int value) { + struct cb_pcidda_private *devpriv = dev->private; unsigned int cal2_bits; unsigned int i; /* caldacs use 3 bit channel specification */ @@ -256,10 +260,10 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev, cal2_bits |= DESELECT_CALDAC_BIT(i); /* activate the caldac we want */ cal2_bits &= ~DESELECT_CALDAC_BIT(caldac); - outw_p(cal2_bits, dev->iobase + DACALIBRATION2); + outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2); /* deactivate caldac */ cal2_bits |= DESELECT_CALDAC_BIT(caldac); - outw_p(cal2_bits, dev->iobase + DACALIBRATION2); + outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2); } /* set caldacs to eeprom values for given channel and range */ @@ -324,9 +328,9 @@ static int cb_pcidda_ao_insn_write(struct comedi_device *dev, if (range > 2) ctrl |= CB_DDA_DA_CTRL_UNIP; - outw(ctrl, dev->iobase + CB_DDA_DA_CTRL_REG); + outw(ctrl, devpriv->daqio + CB_DDA_DA_CTRL_REG); - outw(data[0], dev->iobase + CB_DDA_DA_DATA_REG(channel)); + outw(data[0], devpriv->daqio + CB_DDA_DA_DATA_REG(channel)); return insn->n; } @@ -338,7 +342,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, const struct cb_pcidda_board *thisboard = NULL; struct cb_pcidda_private *devpriv; struct comedi_subdevice *s; - unsigned long iobase_8255; int i; int ret; @@ -356,8 +359,8 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, ret = comedi_pci_enable(dev); if (ret) return ret; - dev->iobase = pci_resource_start(pcidev, 3); - iobase_8255 = pci_resource_start(pcidev, 2); + dev->iobase = pci_resource_start(pcidev, 2); + devpriv->daqio = pci_resource_start(pcidev, 3); ret = comedi_alloc_subdevices(dev, 3); if (ret) @@ -375,7 +378,7 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, /* two 8255 digital io subdevices */ for (i = 0; i < 2; i++) { s = &dev->subdevices[1 + i]; - ret = subdev_8255_init(dev, s, NULL, iobase_8255 + (i * 4)); + ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); if (ret) return ret; } @@ -395,7 +398,7 @@ static struct comedi_driver cb_pcidda_driver = { .driver_name = "cb_pcidda", .module = THIS_MODULE, .auto_attach = cb_pcidda_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int cb_pcidda_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index ccb9c72bc0c3..fe4d2544f3dc 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -77,10 +77,8 @@ See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. */ struct cb_pcimdas_private { /* base addresses */ + unsigned long daqio; unsigned long BADR3; - - /* Used for AO readback */ - unsigned int ao_readback[2]; }; static int cb_pcimdas_ai_eoc(struct comedi_device *dev, @@ -143,7 +141,7 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ - outw(0, dev->iobase + 0); + outw(0, devpriv->daqio + 0); /* wait for conversion to end */ ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0); @@ -151,55 +149,31 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, return ret; /* read data */ - data[n] = inw(dev->iobase + 0); + data[n] = inw(devpriv->daqio + 0); } /* return the number of samples read/written */ return n; } -static int cb_pcimdas_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcimdas_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct cb_pcimdas_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; + unsigned int reg = (chan) ? DAC1_OFFSET : DAC0_OFFSET; int i; - int chan = CR_CHAN(insn->chanspec); - /* 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++) { - switch (chan) { - case 0: - outw(data[i] & 0x0FFF, dev->iobase + DAC0_OFFSET); - break; - case 1: - outw(data[i] & 0x0FFF, dev->iobase + DAC1_OFFSET); - break; - default: - return -1; - } - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + outw(val, devpriv->daqio + reg); } + s->readback[chan] = val; - /* return the number of samples read/written */ - return i; -} - -/* AO subdevices should have a read insn as well as a write insn. - * Usually this means copying a value stored in devpriv. */ -static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct cb_pcimdas_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int cb_pcimdas_auto_attach(struct comedi_device *dev, @@ -208,7 +182,6 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct cb_pcimdas_private *devpriv; struct comedi_subdevice *s; - unsigned long iobase_8255; int ret; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); @@ -219,9 +192,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, if (ret) return ret; - dev->iobase = pci_resource_start(pcidev, 2); + devpriv->daqio = pci_resource_start(pcidev, 2); devpriv->BADR3 = pci_resource_start(pcidev, 3); - iobase_8255 = pci_resource_start(pcidev, 4); + dev->iobase = pci_resource_start(pcidev, 4); ret = comedi_alloc_subdevices(dev, 3); if (ret) @@ -247,30 +220,27 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, s->maxdata = 0xfff; /* ranges are hardware settable, but not software readable. */ s->range_table = &range_unknown; - s->insn_write = &cb_pcimdas_ao_winsn; - s->insn_read = &cb_pcimdas_ao_rinsn; + s->insn_write = cb_pcimdas_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* digital i/o subdevice */ - ret = subdev_8255_init(dev, s, NULL, iobase_8255); + ret = subdev_8255_init(dev, s, NULL, 0x00); if (ret) return ret; return 0; } -static void cb_pcimdas_detach(struct comedi_device *dev) -{ - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); -} - static struct comedi_driver cb_pcimdas_driver = { .driver_name = "cb_pcimdas", .module = THIS_MODULE, .auto_attach = cb_pcimdas_auto_attach, - .detach = cb_pcimdas_detach, + .detach = comedi_pci_detach, }; static int cb_pcimdas_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 4a2b200de01b..03043e7b9b58 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -90,21 +90,14 @@ Configuration Options: not applicable, uses PCI auto config #define PCIMDDA_DA_CHAN(x) (0x00 + (x) * 2) #define PCIMDDA_8255_BASE_REG 0x0c -#define MAX_AO_READBACK_CHANNELS 6 - -struct cb_pcimdda_private { - unsigned int ao_readback[MAX_AO_READBACK_CHANNELS]; -}; - -static int cb_pcimdda_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int cb_pcimdda_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct cb_pcimdda_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan); - unsigned int val = 0; + unsigned int val = s->readback[chan]; int i; for (i = 0; i < insn->n; i++) { @@ -122,45 +115,31 @@ static int cb_pcimdda_ao_winsn(struct comedi_device *dev, outb(val & 0x00ff, offset); outb((val >> 8) & 0x00ff, offset + 1); } - - /* Cache the last value for readback */ - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; return insn->n; } -static int cb_pcimdda_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int cb_pcimdda_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct cb_pcimdda_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan); - int i; - - for (i = 0; i < insn->n; i++) { - /* Initiate the simultaneous transfer */ - inw(offset); + unsigned int chan = CR_CHAN(insn->chanspec); - data[i] = devpriv->ao_readback[chan]; - } + /* Initiate the simultaneous transfer */ + inw(dev->iobase + PCIMDDA_DA_CHAN(chan)); - return insn->n; + return comedi_readback_insn_read(dev, s, insn, data); } static int cb_pcimdda_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct cb_pcimdda_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; @@ -177,13 +156,16 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, s->n_chan = 6; s->maxdata = 0xffff; s->range_table = &range_bipolar5; - s->insn_write = cb_pcimdda_ao_winsn; - s->insn_read = cb_pcimdda_ao_rinsn; + s->insn_write = cb_pcimdda_ao_insn_write; + s->insn_read = cb_pcimdda_ao_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[1]; /* digital i/o subdevice */ - ret = subdev_8255_init(dev, s, NULL, - dev->iobase + PCIMDDA_8255_BASE_REG); + ret = subdev_8255_init(dev, s, NULL, PCIMDDA_8255_BASE_REG); if (ret) return ret; @@ -194,7 +176,7 @@ static struct comedi_driver cb_pcimdda_driver = { .driver_name = "cb_pcimdda", .module = THIS_MODULE, .auto_attach = cb_pcimdda_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int cb_pcimdda_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c deleted file mode 100644 index c33c3e5680a6..000000000000 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * comedi_fc.c - * This is a place for code driver writers wish to share between - * two or more drivers. fc is short for frank-common. - * - * Author: Frank Mori Hess <fmhess@users.sourceforge.net> - * Copyright (C) 2002 Frank Mori Hess - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include "../comedidev.h" - -#include "comedi_fc.h" - -unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) -{ - struct comedi_cmd *cmd = &s->async->cmd; - unsigned int num_samples; - unsigned int bits_per_sample; - - switch (s->type) { - case COMEDI_SUBD_DI: - case COMEDI_SUBD_DO: - case COMEDI_SUBD_DIO: - bits_per_sample = 8 * bytes_per_sample(s); - num_samples = (cmd->chanlist_len + bits_per_sample - 1) / - bits_per_sample; - break; - default: - num_samples = cmd->chanlist_len; - break; - } - return num_samples * bytes_per_sample(s); -} -EXPORT_SYMBOL_GPL(cfc_bytes_per_scan); - -void cfc_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes) -{ - struct comedi_async *async = s->async; - unsigned int scan_length = cfc_bytes_per_scan(s); - - async->scan_progress += num_bytes; - if (async->scan_progress >= scan_length) { - async->scan_progress %= scan_length; - async->events |= COMEDI_CB_EOS; - } -} -EXPORT_SYMBOL_GPL(cfc_inc_scan_progress); - -/* Writes an array of data points to comedi's buffer */ -unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s, - void *data, unsigned int num_bytes) -{ - struct comedi_async *async = s->async; - unsigned int retval; - - if (num_bytes == 0) - return 0; - - retval = comedi_buf_write_alloc(s, num_bytes); - if (retval != num_bytes) { - dev_warn(s->device->class_dev, "buffer overrun\n"); - async->events |= COMEDI_CB_OVERFLOW; - return 0; - } - - comedi_buf_memcpy_to(s, 0, data, num_bytes); - comedi_buf_write_free(s, num_bytes); - cfc_inc_scan_progress(s, num_bytes); - async->events |= COMEDI_CB_BLOCK; - - return num_bytes; -} -EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer); - -unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *s, - void *data, unsigned int num_bytes) -{ - if (num_bytes == 0) - return 0; - - num_bytes = comedi_buf_read_alloc(s, num_bytes); - comedi_buf_memcpy_from(s, 0, data, num_bytes); - comedi_buf_read_free(s, num_bytes); - cfc_inc_scan_progress(s, num_bytes); - s->async->events |= COMEDI_CB_BLOCK; - - return num_bytes; -} -EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer); - -unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned int events = s->async->events; - - if (events == 0) - return events; - - if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) - s->cancel(dev, s); - - comedi_event(dev, s); - - return events; -} -EXPORT_SYMBOL_GPL(cfc_handle_events); - -static int __init comedi_fc_init_module(void) -{ - return 0; -} -module_init(comedi_fc_init_module); - -static void __exit comedi_fc_cleanup_module(void) -{ -} -module_exit(comedi_fc_cleanup_module); - -MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); -MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index 541b9371d3da..ce2835972507 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -23,30 +23,48 @@ #include "../comedidev.h" -unsigned int cfc_bytes_per_scan(struct comedi_subdevice *); -void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes); +static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) +{ + return comedi_bytes_per_scan(s); +} -/* Writes an array of data points to comedi's buffer */ -unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *, - void *data, unsigned int num_bytes); +static inline void cfc_inc_scan_progress(struct comedi_subdevice *s, + unsigned int num_bytes) +{ + comedi_inc_scan_progress(s, num_bytes); +} + +static inline unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s, + const void *data, + unsigned int num_bytes) +{ + return comedi_write_array_to_buffer(s, data, num_bytes); +} static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s, unsigned short data) { - return cfc_write_array_to_buffer(s, &data, sizeof(data)); + return comedi_write_array_to_buffer(s, &data, sizeof(data)); }; static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s, unsigned int data) { - return cfc_write_array_to_buffer(s, &data, sizeof(data)); + return comedi_write_array_to_buffer(s, &data, sizeof(data)); }; -unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *, - void *data, unsigned int num_bytes); +static inline unsigned int +cfc_read_array_from_buffer(struct comedi_subdevice *s, void *data, + unsigned int num_bytes) +{ + return comedi_read_array_from_buffer(s, data, num_bytes); +} -unsigned int cfc_handle_events(struct comedi_device *, - struct comedi_subdevice *); +static inline unsigned int cfc_handle_events(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + return comedi_handle_events(dev, s); +} /** * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index a42748692357..bf002988192d 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -173,9 +173,6 @@ static int parport_intr_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); @@ -187,10 +184,9 @@ static int parport_intr_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: ignored */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index 845a67905ca6..00c03df72523 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -302,7 +302,7 @@ static int waveform_ai_cmd(struct comedi_device *dev, struct waveform_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - if (cmd->flags & TRIG_RT) { + if (cmd->flags & CMDF_PRIORITY) { dev_err(dev->class_dev, "commands at RT priority not supported in this driver\n"); return -1; @@ -415,14 +415,14 @@ static int waveform_attach(struct comedi_device *dev, for (i = 0; i < s->n_chan; i++) devpriv->ao_loopbacks[i] = s->maxdata / 2; - init_timer(&(devpriv->timer)); + init_timer(&devpriv->timer); devpriv->timer.function = waveform_ai_interrupt; devpriv->timer.data = (unsigned long)dev; dev_info(dev->class_dev, - "%s: %i microvolt, %li microsecond waveform attached\n", - dev->board_name, - devpriv->uvolt_amplitude, devpriv->usec_period); + "%s: %i microvolt, %li microsecond waveform attached\n", + dev->board_name, + devpriv->uvolt_amplitude, devpriv->usec_period); return 0; } diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index f066fb06dc1d..205f9df345a2 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -97,7 +97,7 @@ static struct comedi_driver contec_pci_dio_driver = { .driver_name = "contec_pci_dio", .module = THIS_MODULE, .auto_attach = contec_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int contec_pci_dio_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c index df46e0a5bade..34cbe83f0ce7 100644 --- a/drivers/staging/comedi/drivers/dac02.c +++ b/drivers/staging/comedi/drivers/dac02.c @@ -68,10 +68,6 @@ static const struct comedi_lrange das02_ao_ranges = { } }; -struct dac02_private { - unsigned int ao_readback[2]; -}; - /* * Register I/O map */ @@ -83,7 +79,6 @@ static int dac02_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct dac02_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); unsigned int val; @@ -92,7 +87,7 @@ static int dac02_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; /* * Unipolar outputs are true binary encoding. @@ -113,31 +108,11 @@ static int dac02_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int dac02_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct dac02_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; -} - static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct dac02_private *devpriv; struct comedi_subdevice *s; int ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_request_region(dev, it->options[0], 0x08); if (ret) return ret; @@ -154,7 +129,11 @@ static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = &das02_ao_ranges; s->insn_write = dac02_ao_insn_write; - s->insn_read = dac02_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; return 0; } diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index cd369cd40114..e5b5a8133b34 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -275,7 +275,6 @@ struct daqboard2000_private { card_daqboard_2000 } card; void __iomem *plx; - unsigned int ao_readback[2]; }; static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry) @@ -401,21 +400,6 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, return i; } -static int daqboard2000_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct daqboard2000_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; -} - static int daqboard2000_ao_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -435,38 +419,23 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct daqboard2000_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int ret; + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) { -#if 0 - /* - * OK, since it works OK without enabling the DAC's, - * let's keep it as simple as possible... - */ - writew((chan + 2) * 0x0010 | 0x0001, dev->mmio + dacControl); - udelay(1000); -#endif - writew(data[i], dev->mmio + dacSetting(chan)); + unsigned int val = data[i]; + int ret; + + writew(val, dev->mmio + dacSetting(chan)); ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0); if (ret) return ret; - devpriv->ao_readback[chan] = data[i]; -#if 0 - /* - * Since we never enabled the DAC's, we don't need - * to disable it... - */ - writew((chan + 2) * 0x0010 | 0x0000, dev->mmio + dacControl); - udelay(1000); -#endif + s->readback[chan] = val; } - return i; + return insn->n; } static void daqboard2000_resetLocalBus(struct comedi_device *dev) @@ -651,16 +620,15 @@ static void daqboard2000_initializeDac(struct comedi_device *dev) daqboard2000_dacDisarm(dev); } -static int daqboard2000_8255_cb(int dir, int port, int data, - unsigned long ioaddr) +static int daqboard2000_8255_cb(struct comedi_device *dev, + int dir, int port, int data, + unsigned long iobase) { - void __iomem *mmio_base = (void __iomem *)ioaddr; - if (dir) { - writew(data, mmio_base + port * 2); + writew(data, dev->mmio + iobase + port * 2); return 0; } - return readw(mmio_base + port * 2); + return readw(dev->mmio + iobase + port * 2); } static const void *daqboard2000_find_boardinfo(struct comedi_device *dev, @@ -738,13 +706,17 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = 0xffff; - s->insn_read = daqboard2000_ao_insn_read; s->insn_write = daqboard2000_ao_insn_write; + s->insn_read = comedi_readback_insn_read; s->range_table = &range_bipolar10; + result = comedi_alloc_subdev_readback(s); + if (result) + return result; + s = &dev->subdevices[2]; result = subdev_8255_init(dev, s, daqboard2000_8255_cb, - (unsigned long)(dev->mmio + dioP2ExpansionIO8Bit)); + dioP2ExpansionIO8Bit); if (result) return result; @@ -755,15 +727,9 @@ static void daqboard2000_detach(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv) { - if (dev->mmio) - iounmap(dev->mmio); - if (devpriv->plx) - iounmap(devpriv->plx); - } - comedi_pci_disable(dev); + if (devpriv && devpriv->plx) + iounmap(devpriv->plx); + comedi_pci_detach(dev); } static struct comedi_driver daqboard2000_driver = { diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index fcf916a80c8d..bdb671a66e22 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -217,7 +217,7 @@ static int das08_ai_eoc(struct comedi_device *dev, static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct das08_board_struct *thisboard = comedi_board(dev); + const struct das08_board_struct *thisboard = dev->board_ptr; struct das08_private_struct *devpriv = dev->private; int n; int chan; @@ -337,8 +337,7 @@ static int das08jr_do_wbits(struct comedi_device *dev, static void das08_ao_set_data(struct comedi_device *dev, unsigned int chan, unsigned int data) { - const struct das08_board_struct *thisboard = comedi_board(dev); - struct das08_private_struct *devpriv = dev->private; + const struct das08_board_struct *thisboard = dev->board_ptr; unsigned char lsb; unsigned char msb; @@ -355,54 +354,29 @@ static void das08_ao_set_data(struct comedi_device *dev, /* load DACs */ inb(dev->iobase + DAS08AO_AO_UPDATE); } - devpriv->ao_readback[chan] = data; -} - -static void das08_ao_initialize(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - int n; - unsigned int data; - - data = s->maxdata / 2; /* should be about 0 volts */ - for (n = 0; n < s->n_chan; n++) - das08_ao_set_data(dev, n, data); -} - -static int das08_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int n; - unsigned int chan; - - chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) - das08_ao_set_data(dev, chan, *data); - - return n; } -static int das08_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct das08_private_struct *devpriv = dev->private; - unsigned int n; - unsigned int chan; - - chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; + int i; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + for (i = 0; i < insn->n; i++) { + val = data[i]; + das08_ao_set_data(dev, chan, val); + } + s->readback[chan] = val; - return n; + return insn->n; } static void i8254_initialize(struct comedi_device *dev) { - const struct das08_board_struct *thisboard = comedi_board(dev); + const struct das08_board_struct *thisboard = dev->board_ptr; unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; unsigned int mode = I8254_MODE0 | I8254_BINARY; int i; @@ -415,7 +389,7 @@ static int das08_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct das08_board_struct *thisboard = comedi_board(dev); + const struct das08_board_struct *thisboard = dev->board_ptr; unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; @@ -427,7 +401,7 @@ static int das08_counter_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct das08_board_struct *thisboard = comedi_board(dev); + const struct das08_board_struct *thisboard = dev->board_ptr; unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; @@ -439,7 +413,7 @@ static int das08_counter_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct das08_board_struct *thisboard = comedi_board(dev); + const struct das08_board_struct *thisboard = dev->board_ptr; unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; @@ -458,10 +432,11 @@ static int das08_counter_config(struct comedi_device *dev, int das08_common_attach(struct comedi_device *dev, unsigned long iobase) { - const struct das08_board_struct *thisboard = comedi_board(dev); + const struct das08_board_struct *thisboard = dev->board_ptr; struct das08_private_struct *devpriv = dev->private; struct comedi_subdevice *s; int ret; + int i; dev->iobase = iobase; @@ -498,9 +473,18 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->n_chan = 2; s->maxdata = (1 << thisboard->ao_nbits) - 1; s->range_table = &range_bipolar5; - s->insn_write = das08_ao_winsn; - s->insn_read = das08_ao_rinsn; - das08_ao_initialize(dev, s); + s->insn_write = das08_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + /* intialize all channels to 0V */ + for (i = 0; i < s->n_chan; i++) { + s->readback[i] = s->maxdata / 2; + das08_ao_set_data(dev, i, s->readback[i]); + } } else { s->type = COMEDI_SUBD_UNUSED; } @@ -536,8 +520,7 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s = &dev->subdevices[4]; /* 8255 */ if (thisboard->i8255_offset != 0) { - ret = subdev_8255_init(dev, s, NULL, - dev->iobase + thisboard->i8255_offset); + ret = subdev_8255_init(dev, s, NULL, thisboard->i8255_offset); if (ret) return ret; } else { diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index 18cc170facd0..f86167da5895 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -44,7 +44,6 @@ struct das08_private_struct { * without separate do register */ const unsigned int *pg_gainlist; - unsigned int ao_readback[2]; /* assume 2 AO channels */ }; int das08_common_attach(struct comedi_device *dev, unsigned long iobase); diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c index 4fb03d3852d3..e4ba268e78ab 100644 --- a/drivers/staging/comedi/drivers/das08_isa.c +++ b/drivers/staging/comedi/drivers/das08_isa.c @@ -174,7 +174,7 @@ static const struct das08_board_struct das08_isa_boards[] = { static int das08_isa_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das08_board_struct *thisboard = comedi_board(dev); + const struct das08_board_struct *thisboard = dev->board_ptr; struct das08_private_struct *devpriv; int ret; diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c index 4ce3eb0a64cc..0987ce554945 100644 --- a/drivers/staging/comedi/drivers/das08_pci.c +++ b/drivers/staging/comedi/drivers/das08_pci.c @@ -77,7 +77,7 @@ static struct comedi_driver das08_pci_comedi_driver = { .driver_name = "pci-das08", .module = THIS_MODULE, .auto_attach = das08_pci_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int das08_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 057bc16f8ddc..2d8e86cec47a 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -631,7 +631,7 @@ static int das16_ai_check_chanlist(struct comedi_device *dev, static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct das16_board *board = comedi_board(dev); + const struct das16_board *board = dev->board_ptr; struct das16_private_struct *devpriv = dev->private; int err = 0; unsigned int trig_mask; @@ -692,7 +692,9 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -748,7 +750,7 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct das16_board *board = comedi_board(dev); + const struct das16_board *board = dev->board_ptr; struct das16_private_struct *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -756,9 +758,9 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) unsigned long flags; int range; - if (cmd->flags & TRIG_RT) { + if (cmd->flags & CMDF_PRIORITY) { dev_err(dev->class_dev, - "isa dma transfers cannot be performed with TRIG_RT, aborting\n"); + "isa dma transfers cannot be performed with CMDF_PRIORITY, aborting\n"); return -1; } @@ -883,7 +885,7 @@ static int das16_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - const struct das16_board *board = comedi_board(dev); + const struct das16_board *board = dev->board_ptr; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); unsigned int val; @@ -927,11 +929,13 @@ static int das16_ao_insn_write(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val; int i; for (i = 0; i < insn->n; i++) { - val = data[i]; + unsigned int val = data[i]; + + s->readback[chan] = val; + val <<= 4; outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan)); @@ -966,7 +970,7 @@ static int das16_do_insn_bits(struct comedi_device *dev, static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das16_board *board = comedi_board(dev); + const struct das16_board *board = dev->board_ptr; int diobits; /* diobits indicates boards */ @@ -991,7 +995,7 @@ static void das16_reset(struct comedi_device *dev) static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das16_board *board = comedi_board(dev); + const struct das16_board *board = dev->board_ptr; struct das16_private_struct *devpriv; struct comedi_subdevice *s; struct comedi_lrange *lrange; @@ -1163,6 +1167,11 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = devpriv->user_ao_range_table; s->insn_write = das16_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -1191,8 +1200,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* 8255 Digital I/O subdevice */ if (board->has_8255) { s = &dev->subdevices[4]; - ret = subdev_8255_init(dev, s, NULL, - dev->iobase + board->i8255_offset); + ret = subdev_8255_init(dev, s, NULL, board->i8255_offset); if (ret) return ret; } @@ -1213,7 +1221,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void das16_detach(struct comedi_device *dev) { - const struct das16_board *board = comedi_board(dev); + const struct das16_board *board = dev->board_ptr; struct das16_private_struct *devpriv = dev->private; int i; diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 5b6998b54060..24b63c452f51 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -218,12 +218,10 @@ static int das16m1_cmd_test(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { - /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -608,7 +606,7 @@ static int das16m1_attach(struct comedi_device *dev, s = &dev->subdevices[3]; /* 8255 */ - ret = subdev_8255_init(dev, s, NULL, devpriv->extra_iobase); + ret = subdev_8255_init(dev, s, NULL, DAS16M1_82C55); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 0cfca33965f6..a53d87ce9b14 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -453,7 +453,7 @@ static const struct comedi_lrange range_ao_2 = { static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev, uint16_t sample) { - const struct das1800_board *thisboard = comedi_board(dev); + const struct das1800_board *thisboard = dev->board_ptr; sample += 1 << (thisboard->resolution - 1); return sample; @@ -731,15 +731,15 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int flags) convert_arg = 64000; /* the conversion time must be an integral number of microseconds */ - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: micro_sec = (convert_arg + 500) / 1000; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: micro_sec = convert_arg / 1000; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: micro_sec = (convert_arg - 1) / 1000 + 1; break; } @@ -773,7 +773,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct das1800_board *thisboard = comedi_board(dev); + const struct das1800_board *thisboard = dev->board_ptr; struct das1800_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -1088,14 +1088,14 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, struct comedi_async *async = s->async; const struct comedi_cmd *cmd = &async->cmd; - /* disable dma on TRIG_WAKE_EOS, or TRIG_RT + /* disable dma on CMDF_WAKE_EOS, or CMDF_PRIORITY * (because dma in handler is unsafe at hard real-time priority) */ - if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) + if (cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY)) devpriv->irq_dma_bits &= ~DMA_ENABLED; else devpriv->irq_dma_bits |= devpriv->dma_bits; - /* interrupt on end of conversion for TRIG_WAKE_EOS */ - if (cmd->flags & TRIG_WAKE_EOS) { + /* interrupt on end of conversion for CMDF_WAKE_EOS */ + if (cmd->flags & CMDF_WAKE_EOS) { /* interrupt fifo not empty */ devpriv->irq_dma_bits &= ~FIMD; } else { @@ -1136,7 +1136,7 @@ static int das1800_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct das1800_board *thisboard = comedi_board(dev); + const struct das1800_board *thisboard = dev->board_ptr; int i, n; int chan, range, aref, chan_range; int timeout = 1000; @@ -1200,7 +1200,7 @@ static int das1800_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct das1800_board *thisboard = comedi_board(dev); + const struct das1800_board *thisboard = dev->board_ptr; struct das1800_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); /* int range = CR_RANGE(insn->chanspec); */ @@ -1329,7 +1329,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, static int das1800_probe(struct comedi_device *dev) { - const struct das1800_board *board = comedi_board(dev); + const struct das1800_board *board = dev->board_ptr; int index; int id; @@ -1412,7 +1412,7 @@ static int das1800_attach(struct comedi_device *dev, } dev->board_ptr = das1800_boards + board; - thisboard = comedi_board(dev); + thisboard = dev->board_ptr; dev->board_name = thisboard->name; /* if it is an 'ao' board with fancy analog out then we need extra io ports */ diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index d18eea6c01aa..ab6e40608885 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -143,7 +143,6 @@ struct das6402_private { unsigned int divider2; unsigned int ao_range; - unsigned int ao_readback[2]; }; static void das6402_set_mode(struct comedi_device *dev, @@ -328,7 +327,7 @@ static int das6402_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; if (s->maxdata == 0x0fff) { /* @@ -358,9 +357,7 @@ static int das6402_ao_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct das6402_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - int i; /* * If XFER mode is enabled, reading any DAC register @@ -368,10 +365,7 @@ static int das6402_ao_insn_read(struct comedi_device *dev, */ inw(dev->iobase + DAS6402_AO_LSB_REG(chan)); - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; + return comedi_readback_insn_read(dev, s, insn, data); } static int das6402_di_insn_bits(struct comedi_device *dev, @@ -440,7 +434,7 @@ static void das6402_reset(struct comedi_device *dev) static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das6402_boardinfo *board = comedi_board(dev); + const struct das6402_boardinfo *board = dev->board_ptr; struct das6402_private *devpriv; struct comedi_subdevice *s; int ret; @@ -510,6 +504,10 @@ static int das6402_attach(struct comedi_device *dev, s->insn_write = das6402_ao_insn_write; s->insn_read = das6402_ao_insn_read; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + /* Digital Input subdevice */ s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index cbbb29797b83..d75e5528258c 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -248,7 +248,7 @@ static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg) static void das800_enable(struct comedi_device *dev) { - const struct das800_board *thisboard = comedi_board(dev); + const struct das800_board *thisboard = dev->board_ptr; struct das800_private *devpriv = dev->private; unsigned long irq_flags; @@ -325,7 +325,7 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct das800_board *thisboard = comedi_board(dev); + const struct das800_board *thisboard = dev->board_ptr; struct das800_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -398,7 +398,7 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, static int das800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct das800_board *thisboard = comedi_board(dev); + const struct das800_board *thisboard = dev->board_ptr; struct das800_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -633,7 +633,7 @@ static int das800_do_insn_bits(struct comedi_device *dev, static int das800_probe(struct comedi_device *dev) { - const struct das800_board *thisboard = comedi_board(dev); + const struct das800_board *thisboard = dev->board_ptr; int board = thisboard ? thisboard - das800_boards : -EINVAL; int id_bits; unsigned long irq_flags; @@ -695,7 +695,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) return -ENODEV; } dev->board_ptr = das800_boards + board; - thisboard = comedi_board(dev); + thisboard = dev->board_ptr; dev->board_name = thisboard->name; if (irq > 1 && irq <= 7) { diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index e9cd2517ad81..7215e09305cf 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -47,9 +47,10 @@ Configuration Options: #define DMM32AT_AILOW 0x02 #define DMM32AT_AIHIGH 0x03 -#define DMM32AT_DACLSB 0x04 #define DMM32AT_DACSTAT 0x04 -#define DMM32AT_DACMSB 0x05 +#define DMM32AT_DACLSB_REG 0x04 +#define DMM32AT_DACMSB_REG 0x05 +#define DMM32AT_DACMSB_CHAN(x) ((x) << 6) #define DMM32AT_FIFOCNTRL 0x07 #define DMM32AT_FIFOSTAT 0x07 @@ -150,15 +151,10 @@ static const struct comedi_lrange dmm32at_aoranges = { }; struct dmm32at_private { - int data; int ai_inuse; unsigned int ai_scans_left; - - /* Used for AO readback */ - unsigned int ao_readback[4]; unsigned char dio_config; - }; static int dmm32at_ai_status(struct comedi_device *dev, @@ -540,56 +536,35 @@ static int dmm32at_ao_eoc(struct comedi_device *dev, return -EBUSY; } -static int dmm32at_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dmm32at_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct dmm32at_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); - unsigned char hi, lo, status; - int ret; - /* Writing a list of values to an AO channel is probably not - * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; i++) { + unsigned int val = data[i]; + int ret; - devpriv->ao_readback[chan] = data[i]; - - /* get the low byte */ - lo = data[i] & 0x00ff; - /* high byte also contains channel number */ - hi = (data[i] >> 8) + chan * (1 << 6); - /* write the low and high values to the board */ - outb(lo, dev->iobase + DMM32AT_DACLSB); - outb(hi, dev->iobase + DMM32AT_DACMSB); + /* write LSB then MSB + chan to load DAC */ + outb(val & 0xff, dev->iobase + DMM32AT_DACLSB_REG); + outb((val >> 8) | DMM32AT_DACMSB_CHAN(chan), + dev->iobase + DMM32AT_DACMSB_REG); /* wait for circuit to settle */ ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0); if (ret) return ret; - /* dummy read to update trigger the output */ - status = inb(dev->iobase + DMM32AT_DACMSB); + /* dummy read to update DAC */ + inb(dev->iobase + DMM32AT_DACMSB_REG); + s->readback[chan] = val; } - /* return the number of samples read/written */ - return i; -} - -static int dmm32at_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct dmm32at_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int dmm32at_dio_insn_bits(struct comedi_device *dev, @@ -764,8 +739,12 @@ static int dmm32at_attach(struct comedi_device *dev, s->n_chan = 4; s->maxdata = 0x0fff; s->range_table = &dmm32at_aoranges; - s->insn_write = dmm32at_ao_winsn; - s->insn_read = dmm32at_ao_rinsn; + s->insn_write = dmm32at_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* digital i/o subdevice */ diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index ad8ba0be4878..e97386343a0e 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -207,9 +207,7 @@ static const struct dt2801_board boardtypes[] = { }; struct dt2801_private { - const struct comedi_lrange *dac_range_types[2]; - unsigned int ao_readback[2]; }; /* These are the low-level routines: @@ -309,7 +307,7 @@ static int dt2801_wait_for_ready(struct comedi_device *dev) return -ETIME; } -static int dt2801_writecmd(struct comedi_device *dev, int command) +static void dt2801_writecmd(struct comedi_device *dev, int command) { int stat; @@ -323,8 +321,6 @@ static int dt2801_writecmd(struct comedi_device *dev, int command) if (!(stat & DT_S_READY)) dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__); outb_p(command, dev->iobase + DT2801_CMD); - - return 0; } static int dt2801_reset(struct comedi_device *dev) @@ -380,7 +376,7 @@ static int probe_number_of_ai_chans(struct comedi_device *dev) int data; for (n_chans = 0; n_chans < 16; n_chans++) { - stat = dt2801_writecmd(dev, DT_C_READ_ADIM); + dt2801_writecmd(dev, DT_C_READ_ADIM); dt2801_writedata(dev, 0); dt2801_writedata(dev, n_chans); stat = dt2801_readdata2(dev, &data); @@ -451,7 +447,7 @@ static int dt2801_ai_insn_read(struct comedi_device *dev, int i; for (i = 0; i < insn->n; i++) { - stat = dt2801_writecmd(dev, DT_C_READ_ADIM); + dt2801_writecmd(dev, DT_C_READ_ADIM); dt2801_writedata(dev, CR_RANGE(insn->chanspec)); dt2801_writedata(dev, CR_CHAN(insn->chanspec)); stat = dt2801_readdata2(dev, &d); @@ -465,28 +461,18 @@ static int dt2801_ai_insn_read(struct comedi_device *dev, return i; } -static int dt2801_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct dt2801_private *devpriv = dev->private; - - data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; - - return 1; -} - static int dt2801_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct dt2801_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); dt2801_writecmd(dev, DT_C_WRITE_DAIM); - dt2801_writedata(dev, CR_CHAN(insn->chanspec)); + dt2801_writedata(dev, chan); dt2801_writedata2(dev, data[0]); - devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; + s->readback[chan] = data[0]; return 1; } @@ -571,7 +557,7 @@ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) havetype: dev->board_ptr = boardtypes + type; - board = comedi_board(dev); + board = dev->board_ptr; n_ai_chans = probe_number_of_ai_chans(dev); @@ -610,8 +596,12 @@ havetype: s->range_table_list = devpriv->dac_range_types; devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); - s->insn_read = dt2801_ao_insn_read; s->insn_write = dt2801_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* 1st digital subdevice */ diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index a2e9caf3256f..1736e397ad2c 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -213,7 +213,6 @@ struct dt2811_private { dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5 } dac_range[2]; const struct comedi_lrange *range_type_list[2]; - unsigned int ao_readback[2]; }; static const struct comedi_lrange *dac_range_types[] = { @@ -257,39 +256,24 @@ static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dt2811_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct dt2811_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; int i; - int chan; - - chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) { - outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); - outb((data[i] >> 8) & 0xff, + val = data[i]; + outb(val & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); + outb((val >> 8) & 0xff, dev->iobase + DT2811_DADAT0HI + 2 * chan); - devpriv->ao_readback[chan] = data[i]; } + s->readback[chan] = val; - return i; -} - -static int dt2811_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct dt2811_private *devpriv = dev->private; - int i; - int chan; - - chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int dt2811_di_insn_bits(struct comedi_device *dev, @@ -337,7 +321,7 @@ static int dt2811_do_insn_bits(struct comedi_device *dev, static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { /* int i; */ - const struct dt2811_board *board = comedi_board(dev); + const struct dt2811_board *board = dev->board_ptr; struct dt2811_private *devpriv; int ret; struct comedi_subdevice *s; @@ -429,12 +413,16 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; - s->insn_write = dt2811_ao_insn; - s->insn_read = dt2811_ao_insn_read; s->maxdata = 0xfff; s->range_table_list = devpriv->range_type_list; devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]]; devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]]; + s->insn_write = dt2811_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* di subdevice */ diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 5de26745783a..cc974a5e5cf6 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -315,8 +315,6 @@ struct dt282x_private { unsigned int divisor; - unsigned short ao_readback[2]; - int dacsr; /* software copies of registers */ int adcsr; int supcsr; @@ -405,15 +403,15 @@ static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags) if (prescale == 1) continue; base = 250 * (1 << prescale); - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: divider = (*ns + base / 2) / base; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: divider = (*ns) / base; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: divider = (*ns + base - 1) / base; break; } @@ -683,7 +681,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct dt282x_board *board = comedi_board(dev); + const struct dt282x_board *board = dev->board_ptr; struct dt282x_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -730,11 +728,10 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_EXT | TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -826,21 +823,6 @@ static int dt282x_ai_cancel(struct comedi_device *dev, return 0; } -static int dt282x_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct dt282x_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; -} - static int dt282x_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -849,14 +831,14 @@ static int dt282x_ao_insn_write(struct comedi_device *dev, struct dt282x_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val; int i; devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan); for (i = 0; i < insn->n; i++) { - val = data[i]; - devpriv->ao_readback[chan] = val; + unsigned int val = data[i]; + + s->readback[chan] = val; if (comedi_range_is_bipolar(s, range)) val = comedi_offset_munge(s, val); @@ -907,11 +889,10 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_EXT | TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -1166,7 +1147,7 @@ static int dt282x_initialize(struct comedi_device *dev) */ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct dt282x_board *board = comedi_board(dev); + const struct dt282x_board *board = dev->board_ptr; struct dt282x_private *devpriv; struct comedi_subdevice *s; int ret; @@ -1252,12 +1233,10 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->subdev_flags = SDF_WRITABLE; s->n_chan = board->dachan; s->maxdata = board->ao_maxdata; - /* ranges are per-channel, set by jumpers on the board */ s->range_table = &dt282x_ao_range; - - s->insn_read = dt282x_ao_insn_read; s->insn_write = dt282x_ao_insn_write; + s->insn_read = comedi_readback_insn_read; if (dev->irq) { dev->write_subdev = s; s->subdev_flags |= SDF_CMD_WRITE; @@ -1266,6 +1245,10 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->do_cmd = dt282x_ao_cmd; s->cancel = dt282x_ao_cancel; } + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 56e21cc2dcfe..825561046b6f 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -245,7 +245,6 @@ static const struct dt3k_boardtype dt3k_boardtypes[] = { struct dt3k_private { unsigned int lock; - unsigned int ao_readback[2]; unsigned int ai_front; unsigned int ai_rear; }; @@ -378,15 +377,15 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, for (prescale = 0; prescale < 16; prescale++) { base = timer_base * (prescale + 1); - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: divider = (*nanosec + base / 2) / base; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: divider = (*nanosec) / base; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: divider = (*nanosec) / base; break; } @@ -406,7 +405,7 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, static int dt3k_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct dt3k_boardtype *this_board = comedi_board(dev); + const struct dt3k_boardtype *this_board = dev->board_ptr; int err = 0; unsigned int arg; @@ -424,9 +423,6 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); @@ -488,7 +484,6 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) unsigned int chan, range, aref; unsigned int divider; unsigned int tscandiv; - unsigned int mode; for (i = 0; i < cmd->chanlist_len; i++) { chan = CR_CHAN(cmd->chanlist[i]); @@ -513,8 +508,7 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4)); } - mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0; - writew(mode, dev->mmio + DPR_Params(5)); + writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5)); writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6)); writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7)); @@ -550,35 +544,22 @@ static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dt3k_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct dt3k_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; int i; - unsigned int chan; - chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) { - dt3k_writesingle(dev, SUBS_AO, chan, data[i]); - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + dt3k_writesingle(dev, SUBS_AO, chan, val); } + s->readback[chan] = val; - return i; -} - -static int dt3k_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct dt3k_private *devpriv = dev->private; - int i; - unsigned int chan; - - chan = CR_CHAN(insn->chanspec); - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static void dt3k_dio_config(struct comedi_device *dev, int bits) @@ -714,11 +695,15 @@ static int dt3000_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; - s->insn_read = dt3k_ao_insn_read; - s->insn_write = dt3k_ao_insn; s->maxdata = (1 << this_board->dabits) - 1; s->len_chanlist = 1; s->range_table = &range_bipolar10; + s->insn_write = dt3k_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* dio subsystem */ @@ -750,20 +735,11 @@ static int dt3000_auto_attach(struct comedi_device *dev, return 0; } -static void dt3000_detach(struct comedi_device *dev) -{ - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->mmio) - iounmap(dev->mmio); - comedi_pci_disable(dev); -} - static struct comedi_driver dt3000_driver = { .driver_name = "dt3000", .module = THIS_MODULE, .auto_attach = dt3000_auto_attach, - .detach = dt3000_detach, + .detach = comedi_pci_detach, }; static int dt3000_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index bd2ca2b371e6..77bb89fee327 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -240,7 +240,6 @@ struct dt9812_private { size_t size; } cmd_wr, cmd_rd; u16 device; - u16 ao_shadow[2]; }; static int dt9812_read_info(struct comedi_device *dev, @@ -546,7 +545,6 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) break; } ret = dt9812_rmw_multiple_registers(dev, 3, rmw); - devpriv->ao_shadow[channel] = value; up(&devpriv->sem); @@ -609,15 +607,13 @@ static int dt9812_ao_insn_read(struct comedi_device *dev, unsigned int *data) { struct dt9812_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; + int ret; down(&devpriv->sem); - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_shadow[chan]; + ret = comedi_readback_insn_read(dev, s, insn, data); up(&devpriv->sem); - return insn->n; + return ret; } static int dt9812_ao_insn_write(struct comedi_device *dev, @@ -626,13 +622,17 @@ static int dt9812_ao_insn_write(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - int ret; int i; for (i = 0; i < insn->n; i++) { - ret = dt9812_analog_out(dev, chan, data[i]); + unsigned int val = data[i]; + int ret; + + ret = dt9812_analog_out(dev, chan, val); if (ret) return ret; + + s->readback[chan] = val; } return insn->n; @@ -769,6 +769,7 @@ static int dt9812_auto_attach(struct comedi_device *dev, struct comedi_subdevice *s; bool is_unipolar; int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -828,8 +829,12 @@ static int dt9812_auto_attach(struct comedi_device *dev, s->insn_write = dt9812_ao_insn_write; s->insn_read = dt9812_ao_insn_read; - devpriv->ao_shadow[0] = is_unipolar ? 0x0000 : 0x0800; - devpriv->ao_shadow[1] = is_unipolar ? 0x0000 : 0x0800; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + for (i = 0; i < s->n_chan; i++) + s->readback[i] = is_unipolar ? 0x0000 : 0x0800; return 0; } diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index e5593f8c7406..608aee0c3a15 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -243,9 +243,9 @@ static void dyna_pci10xx_detach(struct comedi_device *dev) { struct dyna_pci10xx_private *devpriv = dev->private; + comedi_pci_detach(dev); if (devpriv) mutex_destroy(&devpriv->mutex); - comedi_pci_disable(dev); } static struct comedi_driver dyna_pci10xx_driver = { diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index 4e410f3b0e24..5a1e3c8fc01c 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -44,10 +44,6 @@ #define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2)) #define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2)) -struct fl512_private { - unsigned short ao_readback[2]; -}; - static const struct comedi_lrange range_fl512 = { 4, { BIP_RANGE(0.5), @@ -92,9 +88,8 @@ static int fl512_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct fl512_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val = devpriv->ao_readback[chan]; + unsigned int val = s->readback[chan]; int i; for (i = 0; i < insn->n; i++) { @@ -105,29 +100,13 @@ static int fl512_ao_insn_write(struct comedi_device *dev, outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan)); inb(dev->iobase + FL512_AO_TRIG_REG(chan)); } - devpriv->ao_readback[chan] = val; - - return insn->n; -} - -static int fl512_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct fl512_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + s->readback[chan] = val; return insn->n; } static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct fl512_private *devpriv; struct comedi_subdevice *s; int ret; @@ -135,10 +114,6 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; @@ -160,7 +135,11 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = &range_fl512; s->insn_write = fl512_ao_insn_write; - s->insn_read = fl512_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; return 0; } diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 91c1e8cf5d24..b8975a4606ea 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -422,12 +422,10 @@ static int gsc_hpdi_cmd_test(struct comedi_device *dev, if (err) return 3; - /* step 4: fix up any arguments */ - - if (err) - return 4; + /* Step 4: fix up any arguments */ /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) err |= gsc_hpdi_check_chanlist(dev, s, cmd); @@ -507,6 +505,32 @@ static int gsc_hpdi_dio_insn_config(struct comedi_device *dev, return insn->n; } +static void gsc_hpdi_free_dma(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct hpdi_private *devpriv = dev->private; + int i; + + if (!devpriv) + return; + + /* free pci dma buffers */ + for (i = 0; i < NUM_DMA_BUFFERS; i++) { + if (devpriv->dio_buffer[i]) + pci_free_consistent(pcidev, + DMA_BUFFER_SIZE, + devpriv->dio_buffer[i], + devpriv->dio_buffer_phys_addr[i]); + } + /* free dma descriptors */ + if (devpriv->dma_desc) + pci_free_consistent(pcidev, + sizeof(struct plx_dma_desc) * + NUM_DMA_DESCRIPTORS, + devpriv->dma_desc, + devpriv->dma_desc_phys_addr); +} + static int gsc_hpdi_init(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; @@ -681,9 +705,7 @@ static int gsc_hpdi_auto_attach(struct comedi_device *dev, static void gsc_hpdi_detach(struct comedi_device *dev) { - struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct hpdi_private *devpriv = dev->private; - unsigned int i; if (dev->irq) free_irq(dev->irq, dev); @@ -694,24 +716,9 @@ static void gsc_hpdi_detach(struct comedi_device *dev) } if (dev->mmio) iounmap(dev->mmio); - /* free pci dma buffers */ - for (i = 0; i < NUM_DMA_BUFFERS; i++) { - if (devpriv->dio_buffer[i]) - pci_free_consistent(pcidev, - DMA_BUFFER_SIZE, - devpriv->dio_buffer[i], - devpriv-> - dio_buffer_phys_addr[i]); - } - /* free dma descriptors */ - if (devpriv->dma_desc) - pci_free_consistent(pcidev, - sizeof(struct plx_dma_desc) * - NUM_DMA_DESCRIPTORS, - devpriv->dma_desc, - devpriv->dma_desc_phys_addr); } comedi_pci_disable(dev); + gsc_hpdi_free_dma(dev); } static struct comedi_driver gsc_hpdi_driver = { diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index a98cef2106a9..f4e1c1cf4178 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -107,7 +107,6 @@ static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; */ struct icp_multi_private { - char valid; /* card is usable */ unsigned int AdcCmdStatus; /* ADC Command/Status register */ unsigned int DacCmdStatus; /* DAC Command/Status register */ unsigned int IntEnable; /* Interrupt Enable register */ @@ -116,7 +115,6 @@ struct icp_multi_private { 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 short ao_data[4]; /* data output buffer */ unsigned int do_data; /* Remember digital output data */ }; @@ -240,14 +238,15 @@ static int icp_multi_ao_eoc(struct comedi_device *dev, return -EBUSY; } -static int icp_multi_insn_write_ao(struct comedi_device *dev, +static int icp_multi_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, chan, range; - int ret; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int i; /* Disable D/A conversion ready interrupt */ devpriv->IntEnable &= ~DAC_READY; @@ -257,10 +256,6 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, devpriv->IntStatus |= DAC_READY; writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - /* Get channel number and range */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - /* Set up range and channel data */ /* Bit 4 = 1 : Bipolar */ /* Bit 5 = 0 : 5V */ @@ -272,7 +267,10 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR); - for (n = 0; n < insn->n; n++) { + 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); @@ -287,42 +285,20 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - /* Clear data received */ - devpriv->ao_data[chan] = 0; - return ret; } - /* Write data to analogue output data register */ - writew(data[n], dev->mmio + ICP_MULTI_AO); + 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; - /* Save analogue output data */ - devpriv->ao_data[chan] = data[n]; + s->readback[chan] = val; } - return n; -} - -static int icp_multi_insn_read_ao(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct icp_multi_private *devpriv = dev->private; - int n, chan; - - /* Get channel number */ - chan = CR_CHAN(insn->chanspec); - - /* Read analogue outputs */ - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_data[chan]; - - return n; + return insn->n; } static int icp_multi_insn_bits_di(struct comedi_device *dev, @@ -518,8 +494,12 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->len_chanlist = 4; s->range_table = &range_analog; - s->insn_write = icp_multi_insn_write_ao; - s->insn_read = icp_multi_insn_read_ao; + s->insn_write = icp_multi_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; @@ -549,23 +529,14 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s->insn_read = icp_multi_insn_read_ctr; s->insn_write = icp_multi_insn_write_ctr; - devpriv->valid = 1; - return 0; } static void icp_multi_detach(struct comedi_device *dev) { - struct icp_multi_private *devpriv = dev->private; - - if (devpriv) - if (devpriv->valid) - icp_multi_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); if (dev->mmio) - iounmap(dev->mmio); - comedi_pci_disable(dev); + icp_multi_reset(dev); + comedi_pci_detach(dev); } static struct comedi_driver icp_multi_driver = { diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 687db433e131..cc5fd75b8bc0 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -132,44 +132,25 @@ static const struct comedi_lrange ii20k_ai_ranges = { }, }; -struct ii20k_ao_private { - unsigned int last_data[2]; -}; - static void __iomem *ii20k_module_iobase(struct comedi_device *dev, struct comedi_subdevice *s) { return dev->mmio + (s->index + 1) * II20K_MOD_OFFSET; } -static int ii20k_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct ii20k_ao_private *ao_spriv = s->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = ao_spriv->last_data[chan]; - - return insn->n; -} - static int ii20k_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct ii20k_ao_private *ao_spriv = s->private; void __iomem *iobase = ii20k_module_iobase(dev, s); unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val = ao_spriv->last_data[chan]; int i; for (i = 0; i < insn->n; i++) { - val = data[i]; + unsigned int val = data[i]; + + s->readback[chan] = val; /* munge data */ val += ((s->maxdata + 1) >> 1); @@ -180,8 +161,6 @@ static int ii20k_ao_insn_write(struct comedi_device *dev, writeb(0x00, iobase + II20K_AO_STRB_REG(chan)); } - ao_spriv->last_data[chan] = val; - return insn->n; } @@ -398,26 +377,26 @@ static int ii20k_dio_insn_bits(struct comedi_device *dev, static int ii20k_init_module(struct comedi_device *dev, struct comedi_subdevice *s) { - struct ii20k_ao_private *ao_spriv; void __iomem *iobase = ii20k_module_iobase(dev, s); unsigned char id; + int ret; id = readb(iobase + II20K_ID_REG); switch (id) { case II20K_ID_PCI20006M_1: case II20K_ID_PCI20006M_2: - ao_spriv = comedi_alloc_spriv(s, sizeof(*ao_spriv)); - if (!ao_spriv) - return -ENOMEM; - /* Analog Output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = (id == II20K_ID_PCI20006M_2) ? 2 : 1; s->maxdata = 0xffff; s->range_table = &ii20k_ao_ranges; - s->insn_read = ii20k_ao_insn_read; s->insn_write = ii20k_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; break; case II20K_ID_PCI20341M_1: /* Analog Input subdevice */ diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 7b20e19ecbf7..81fab2dfafa4 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -681,7 +681,7 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, unsigned long context) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - static const struct jr3_pci_board *board = NULL; + static const struct jr3_pci_board *board; struct jr3_pci_dev_private *devpriv; struct jr3_pci_subdev_private *spriv; struct comedi_subdevice *s; diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index f46722c2648f..77e94a34b51e 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -212,7 +212,7 @@ static struct comedi_driver ke_counter_driver = { .driver_name = "ke_counter", .module = THIS_MODULE, .auto_attach = ke_counter_auto_attach, - .detach = comedi_pci_disable, + .detach = comedi_pci_detach, }; static int ke_counter_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 9a5c535451a1..6561b00bea59 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -176,8 +176,6 @@ broken. struct me4000_info { unsigned long plx_regbase; unsigned long timer_regbase; - - unsigned int ao_readback[4]; }; enum me4000_boardid { @@ -473,7 +471,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *subdevice, struct comedi_insn *insn, unsigned int *data) { - const struct me4000_board *thisboard = comedi_board(dev); + const struct me4000_board *thisboard = dev->board_ptr; int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); @@ -601,7 +599,7 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct me4000_board *board = comedi_board(dev); + const struct me4000_board *board = dev->board_ptr; unsigned int max_diff_chan = board->ai_diff_nchan; unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; @@ -617,7 +615,7 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev, return -EINVAL; } - if (aref == SDF_DIFF) { + if (aref == AREF_DIFF) { if (chan >= max_diff_chan) { dev_dbg(dev->class_dev, "Channel number to high\n"); @@ -652,10 +650,10 @@ static int ai_round_cmd_args(struct comedi_device *dev, *init_ticks = (cmd->start_arg * 33) / 1000; rest = (cmd->start_arg * 33) % 1000; - if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) { + if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) { if (rest > 33) (*init_ticks)++; - } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) { + } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) { if (rest) (*init_ticks)++; } @@ -665,10 +663,10 @@ static int ai_round_cmd_args(struct comedi_device *dev, *scan_ticks = (cmd->scan_begin_arg * 33) / 1000; rest = (cmd->scan_begin_arg * 33) % 1000; - if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) { + if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) { if (rest > 33) (*scan_ticks)++; - } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) { + } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) { if (rest) (*scan_ticks)++; } @@ -678,10 +676,10 @@ static int ai_round_cmd_args(struct comedi_device *dev, *chan_ticks = (cmd->convert_arg * 33) / 1000; rest = (cmd->convert_arg * 33) % 1000; - if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) { + if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) { if (rest > 33) (*chan_ticks)++; - } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) { + } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) { if (rest) (*chan_ticks)++; } @@ -731,7 +729,7 @@ static int ai_write_chanlist(struct comedi_device *dev, else entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; - if (aref == SDF_DIFF) + if (aref == AREF_DIFF) entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; else entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; @@ -851,7 +849,7 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, int err = 0; /* Only rounding flags are implemented */ - cmd->flags &= TRIG_ROUND_NEAREST | TRIG_ROUND_UP | TRIG_ROUND_DOWN; + cmd->flags &= CMDF_ROUND_NEAREST | CMDF_ROUND_UP | CMDF_ROUND_DOWN; /* Round the timer arguments */ ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks); @@ -925,6 +923,11 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, err |= -EINVAL; } + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + if (err) return 3; @@ -1031,13 +1034,6 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, err++; } } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg == 0) { - dev_err(dev->class_dev, "Invalid stop arg\n"); - cmd->stop_arg = 1; - err++; - } - } if (cmd->scan_end_src == TRIG_COUNT) { if (cmd->scan_end_arg == 0) { dev_err(dev->class_dev, "Invalid scan end arg\n"); @@ -1188,44 +1184,14 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) return IRQ_HANDLED; } -/*============================================================================= - Analog output section - ===========================================================================*/ - static int me4000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - const struct me4000_board *thisboard = comedi_board(dev); - struct me4000_info *info = dev->private; int chan = CR_CHAN(insn->chanspec); - int rang = CR_RANGE(insn->chanspec); - int aref = CR_AREF(insn->chanspec); unsigned int tmp; - if (insn->n == 0) { - return 0; - } else if (insn->n > 1) { - dev_err(dev->class_dev, "Invalid instruction length %d\n", - insn->n); - return -EINVAL; - } - - if (chan >= thisboard->ao_nchan) { - dev_err(dev->class_dev, "Invalid channel %d\n", insn->n); - return -EINVAL; - } - - if (rang != 0) { - dev_err(dev->class_dev, "Invalid range %d\n", insn->n); - return -EINVAL; - } - - if (aref != AREF_GROUND && aref != AREF_COMMON) { - dev_err(dev->class_dev, "Invalid aref %d\n", insn->n); - return -EINVAL; - } - /* Stop any running conversion */ tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan)); tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; @@ -1238,26 +1204,7 @@ static int me4000_ao_insn_write(struct comedi_device *dev, outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Store in the mirror */ - info->ao_readback[chan] = data[0]; - - return 1; -} - -static int me4000_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct me4000_info *info = dev->private; - int chan = CR_CHAN(insn->chanspec); - - if (insn->n == 0) { - return 0; - } else if (insn->n > 1) { - dev_err(dev->class_dev, "Invalid instruction length\n"); - return -EINVAL; - } - - data[0] = info->ao_readback[chan]; + s->readback[chan] = data[0]; return 1; } @@ -1507,7 +1454,11 @@ static int me4000_auto_attach(struct comedi_device *dev, s->maxdata = 0xFFFF; /* 16 bit DAC */ s->range_table = &range_bipolar10; s->insn_write = me4000_ao_insn_write; - s->insn_read = me4000_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + result = comedi_alloc_subdev_readback(s); + if (result) + return result; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -1563,11 +1514,9 @@ static int me4000_auto_attach(struct comedi_device *dev, static void me4000_detach(struct comedi_device *dev) { - if (dev->irq) - free_irq(dev->irq, dev); if (dev->iobase) me4000_reset(dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver me4000_driver = { diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 37a6fa92c656..00eaaf8ac148 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -171,7 +171,6 @@ struct me_private_data { 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 */ - int ao_readback[4]; /* Mirror of analog output data */ }; static inline void sleep(unsigned sec) @@ -325,6 +324,7 @@ static int me_ao_insn_write(struct comedi_device *dev, struct me_private_data *dev_private = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int val = s->readback[chan]; int i; /* Enable all DAC */ @@ -353,10 +353,11 @@ static int me_ao_insn_write(struct comedi_device *dev, /* Set data register */ for (i = 0; i < insn->n; i++) { - writew((data[0] & s->maxdata), - dev->mmio + ME_DAC_DATA_A + (chan << 1)); - dev_private->ao_readback[chan] = (data[0] & s->maxdata); + val = data[i]; + + writew(val, dev->mmio + ME_DAC_DATA_A + (chan << 1)); } + s->readback[chan] = val; /* Update dac with data registers */ readw(dev->mmio + ME_DAC_UPDATE); @@ -364,21 +365,6 @@ static int me_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int me_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct me_private_data *dev_private = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = dev_private->ao_readback[chan]; - - return insn->n; -} - static int me2600_xilinx_download(struct comedi_device *dev, const u8 *data, size_t size, unsigned long context) @@ -530,8 +516,12 @@ static int me_auto_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->len_chanlist = 4; s->range_table = &me_ao_range; - s->insn_read = me_ao_insn_read; s->insn_write = me_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -554,14 +544,12 @@ static void me_detach(struct comedi_device *dev) struct me_private_data *dev_private = dev->private; if (dev_private) { - if (dev->mmio) { + if (dev->mmio) me_reset(dev); - iounmap(dev->mmio); - } if (dev_private->plx_regbase) iounmap(dev_private->plx_regbase); } - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver me_daq_driver = { diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c index 464f4b4745c7..c8d3a22c5896 100644 --- a/drivers/staging/comedi/drivers/mf6x4.c +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -58,7 +58,6 @@ #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_DA_M 0x3fff /* BAR2 registers */ #define MF634_GPIOC_R 0x68 @@ -101,9 +100,6 @@ struct mf6x4_private { * offsets -- this variable makes the access easier */ void __iomem *gpioc_R; - - /* DAC value cache -- used for insn_read function */ - int ao_readback[8]; }; static int mf6x4_di_insn_bits(struct comedi_device *dev, @@ -182,6 +178,7 @@ 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; int i; @@ -191,24 +188,10 @@ static int mf6x4_ao_insn_write(struct comedi_device *dev, devpriv->gpioc_R); for (i = 0; i < insn->n; i++) { - iowrite16(data[i] & MF6X4_DA_M, dev->mmio + MF6X4_DAC_R(chan)); - - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + iowrite16(val, dev->mmio + MF6X4_DAC_R(chan)); } - - return insn->n; -} - -static int mf6x4_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct mf6x4_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + s->readback[chan] = val; return insn->n; } @@ -276,7 +259,11 @@ static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context) s->maxdata = 0x3fff; /* 14 bits DAC */ s->range_table = &range_bipolar10; s->insn_write = mf6x4_ao_insn_write; - s->insn_read = mf6x4_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; /* DIN */ s = &dev->subdevices[2]; @@ -303,14 +290,13 @@ static void mf6x4_detach(struct comedi_device *dev) { struct mf6x4_private *devpriv = dev->private; - if (devpriv->bar0_mem) - iounmap(devpriv->bar0_mem); - if (dev->mmio) - iounmap(dev->mmio); - if (devpriv->bar2_mem) - iounmap(devpriv->bar2_mem); - - comedi_pci_disable(dev); + if (devpriv) { + if (devpriv->bar0_mem) + iounmap(devpriv->bar0_mem); + if (devpriv->bar2_mem) + iounmap(devpriv->bar2_mem); + } + comedi_pci_detach(dev); } static struct comedi_driver mf6x4_driver = { diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index e841a5a3ec4f..f710c8e81320 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -75,10 +75,6 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3) #define MULTIQ3_TIMEOUT 30 -struct multiq3_private { - unsigned int ao_readback[2]; -}; - static int multiq3_ai_status(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -126,38 +122,25 @@ static int multiq3_ai_insn_read(struct comedi_device *dev, return n; } -static int multiq3_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct multiq3_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; -} - static int multiq3_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct multiq3_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; int i; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) { + val = data[i]; outw(MULTIQ3_CONTROL_MUST | MULTIQ3_DA_LOAD | chan, dev->iobase + MULTIQ3_CONTROL); - outw(data[i], dev->iobase + MULTIQ3_DAC_DATA); + outw(val, dev->iobase + MULTIQ3_DAC_DATA); outw(MULTIQ3_CONTROL_MUST, dev->iobase + MULTIQ3_CONTROL); - - devpriv->ao_readback[chan] = data[i]; } + s->readback[chan] = val; - return i; + return insn->n; } static int multiq3_di_insn_bits(struct comedi_device *dev, @@ -227,7 +210,6 @@ static void encoder_reset(struct comedi_device *dev) static int multiq3_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct multiq3_private *devpriv; struct comedi_subdevice *s; int ret; @@ -239,10 +221,6 @@ static int multiq3_attach(struct comedi_device *dev, if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; @@ -257,10 +235,14 @@ static int multiq3_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 8; - s->insn_read = multiq3_ao_insn_read; - s->insn_write = multiq3_ao_insn_write; s->maxdata = 0xfff; s->range_table = &range_bipolar5; + s->insn_write = multiq3_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* di subdevice */ diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index e84dac2bf3b2..45fb601e4080 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -252,10 +252,9 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: fix up any arguments */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } @@ -472,11 +471,7 @@ static void ni6527_detach(struct comedi_device *dev) { if (dev->mmio) ni6527_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->mmio) - iounmap(dev->mmio); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver ni6527_driver = { diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 873941be56cb..3b642861eb36 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -294,7 +294,7 @@ MODULE_PARM_DESC(legacy_invert_outputs, static unsigned int ni_65xx_num_ports(struct comedi_device *dev) { - const struct ni_65xx_board *board = comedi_board(dev); + const struct ni_65xx_board *board = dev->board_ptr; return board->num_dio_ports + board->num_di_ports + board->num_do_ports; } @@ -548,10 +548,9 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: fix up any arguments */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } @@ -793,13 +792,9 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, static void ni_65xx_detach(struct comedi_device *dev) { - if (dev->mmio) { + if (dev->mmio) writeb(0x00, dev->mmio + NI_65XX_CTRL_REG); - iounmap(dev->mmio); - } - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); + comedi_pci_detach(dev); } static struct comedi_driver ni_65xx_driver = { diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index b0b03d4d6081..5b6794c8232e 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -433,7 +433,7 @@ struct ni_660x_private { static inline unsigned ni_660x_num_counters(struct comedi_device *dev) { - const struct ni_660x_board *board = comedi_board(dev); + const struct ni_660x_board *board = dev->board_ptr; return board->n_chips * counters_per_chip; } @@ -852,7 +852,7 @@ static int ni_660x_allocate_private(struct comedi_device *dev) static int ni_660x_alloc_mite_rings(struct comedi_device *dev) { - const struct ni_660x_board *board = comedi_board(dev); + const struct ni_660x_board *board = dev->board_ptr; struct ni_660x_private *devpriv = dev->private; unsigned i; unsigned j; @@ -870,7 +870,7 @@ static int ni_660x_alloc_mite_rings(struct comedi_device *dev) static void ni_660x_free_mite_rings(struct comedi_device *dev) { - const struct ni_660x_board *board = comedi_board(dev); + const struct ni_660x_board *board = dev->board_ptr; struct ni_660x_private *devpriv = dev->private; unsigned i; unsigned j; @@ -924,7 +924,7 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev, unsigned pfi_channel, unsigned output_select) { - const struct ni_660x_board *board = comedi_board(dev); + const struct ni_660x_board *board = dev->board_ptr; static const unsigned counter_4_7_first_pfi = 8; static const unsigned counter_4_7_last_pfi = 23; unsigned active_chipset = 0; diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index f5caefad0b59..54721deb80cc 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -83,52 +83,38 @@ static const struct ni_670x_board ni_670x_boards[] = { struct ni_670x_private { int boardtype; int dio; - unsigned int ao_readback[32]; }; -static int ni_670x_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int ni_670x_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct ni_670x_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; int i; - int chan = CR_CHAN(insn->chanspec); - - /* Channel number mapping : - - NI 6703/ NI 6704 | NI 6704 Only - ---------------------------------------------------- - vch(0) : 0 | ich(16) : 1 - vch(1) : 2 | ich(17) : 3 - . : . | . . - . : . | . . - . : . | . . - vch(15) : 30 | ich(31) : 31 */ + /* + * Channel number mapping: + * + * NI 6703/ NI 6704 | NI 6704 Only + * ------------------------------- + * vch(0) : 0 | ich(16) : 1 + * vch(1) : 2 | ich(17) : 3 + * ... | ... + * vch(15) : 30 | ich(31) : 31 + */ for (i = 0; i < insn->n; i++) { + val = data[i]; /* First write in channel register which channel to use */ writel(((chan & 15) << 1) | ((chan & 16) >> 4), dev->mmio + AO_CHAN_OFFSET); /* write channel value */ - writel(data[i], dev->mmio + AO_VALUE_OFFSET); - devpriv->ao_readback[chan] = data[i]; + writel(val, dev->mmio + AO_VALUE_OFFSET); } + s->readback[chan] = val; - return i; -} - -static int ni_670x_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct ni_670x_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int ni_670x_dio_insn_bits(struct comedi_device *dev, @@ -241,8 +227,12 @@ static int ni_670x_auto_attach(struct comedi_device *dev, } else { s->range_table = &range_bipolar10; } - s->insn_write = &ni_670x_ao_winsn; - s->insn_read = &ni_670x_ao_rinsn; + s->insn_write = ni_670x_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[1]; /* digital i/o subdevice */ @@ -266,14 +256,12 @@ static void ni_670x_detach(struct comedi_device *dev) { struct comedi_subdevice *s; + comedi_pci_detach(dev); if (dev->n_subdevices) { s = &dev->subdevices[0]; if (s) kfree(s->range_table_list); } - if (dev->mmio) - iounmap(dev->mmio); - comedi_pci_disable(dev); } static struct comedi_driver ni_670x_driver = { diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index de67161f6185..72ec857d073e 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -287,7 +287,7 @@ static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, unsigned int flags) { - const struct a2150_board *thisboard = comedi_board(dev); + const struct a2150_board *thisboard = dev->board_ptr; struct a2150_private *devpriv = dev->private; int lub, glb, temp; int lub_divisor_shift, lub_index, glb_divisor_shift, glb_index; @@ -326,8 +326,8 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, } } } - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: /* if least upper bound is better approximation */ if (lub - *period < *period - glb) @@ -335,10 +335,10 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, else *period = glb; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: *period = lub; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: *period = glb; break; } @@ -436,7 +436,7 @@ static int a2150_ai_check_chanlist(struct comedi_device *dev, static int a2150_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct a2150_board *thisboard = comedi_board(dev); + const struct a2150_board *thisboard = dev->board_ptr; int err = 0; unsigned int arg; @@ -511,9 +511,9 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) unsigned int old_config_bits = devpriv->config_bits; unsigned int trigger_bits; - if (cmd->flags & TRIG_RT) { + if (cmd->flags & CMDF_PRIORITY) { dev_err(dev->class_dev, - "dma incompatible with hard real-time interrupt (TRIG_RT), aborting\n"); + "dma incompatible with hard real-time interrupt (CMDF_PRIORITY), aborting\n"); return -1; } /* clear fifo and reset triggering circuitry */ @@ -705,8 +705,12 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - dev->board_ptr = a2150_boards + a2150_probe(dev); - thisboard = comedi_board(dev); + i = a2150_probe(dev); + if (i >= ARRAY_SIZE(a2150_boards)) + return -ENODEV; + + dev->board_ptr = a2150_boards + i; + thisboard = dev->board_ptr; dev->board_name = thisboard->name; if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) || diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index c93b47bcca51..3e1ce5866147 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -118,9 +118,6 @@ struct atao_private { unsigned short cfg1; unsigned short cfg3; - /* Used for AO readback */ - unsigned int ao_readback[10]; - /* Used for caldac readback */ unsigned char caldac[21]; }; @@ -141,9 +138,8 @@ static int atao_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct atao_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val; + unsigned int val = s->readback[chan]; int i; if (chan == 0) @@ -151,12 +147,12 @@ static int atao_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - devpriv->ao_readback[chan] = val; - /* munge offset binary (unsigned) to two's complement */ - val = comedi_offset_munge(s, val); - outw(val, dev->iobase + ATAO_AO_REG(chan)); + /* the hardware expects two's complement values */ + outw(comedi_offset_munge(s, val), + dev->iobase + ATAO_AO_REG(chan)); } + s->readback[chan] = val; if (chan == 0) atao_select_reg_group(dev, 0); @@ -164,21 +160,6 @@ static int atao_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int atao_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct atao_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; -} - static int atao_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -338,7 +319,7 @@ static void atao_reset(struct comedi_device *dev) static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct atao_board *board = comedi_board(dev); + const struct atao_board *board = dev->board_ptr; struct atao_private *devpriv; struct comedi_subdevice *s; int ret; @@ -363,7 +344,11 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0x0fff; s->range_table = it->options[3] ? &range_unipolar10 : &range_bipolar10; s->insn_write = atao_ao_insn_write; - s->insn_read = atao_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; /* Digital I/O subdevice */ s = &dev->subdevices[1]; diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index 2bd9f692a7ae..0c5ff287dcef 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -336,7 +336,7 @@ static int ni_atmio_attach(struct comedi_device *dev, return -EIO; dev->board_ptr = ni_boards + board; - boardtype = comedi_board(dev); + boardtype = dev->board_ptr; dev->board_name = boardtype->name; /* irq stuff */ diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index 9c08da9508f4..fc3c19de7005 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -138,7 +138,6 @@ struct atmio16d_private { enum { dac_internal, dac_external } dac0_reference, dac1_reference; enum { dac_2comp, dac_straight } dac0_coding, dac1_coding; const struct comedi_lrange *ao_range_type_list[2]; - unsigned int ao_readback[2]; unsigned int com_reg_1_state; /* current state of command register 1 */ unsigned int com_reg_2_state; /* current state of command register 2 */ }; @@ -275,11 +274,10 @@ static int atmio16d_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -496,48 +494,34 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev, return i; } -static int atmio16d_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct atmio16d_private *devpriv = dev->private; - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; - return i; -} - static int atmio16d_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct atmio16d_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int reg = (chan) ? DAC1_REG : DAC0_REG; + bool munge = false; int i; - int chan; - int d; - chan = CR_CHAN(insn->chanspec); + if (chan == 0 && devpriv->dac0_coding == dac_2comp) + munge = true; + if (chan == 1 && devpriv->dac1_coding == dac_2comp) + munge = true; for (i = 0; i < insn->n; i++) { - d = data[i]; - switch (chan) { - case 0: - if (devpriv->dac0_coding == dac_2comp) - d ^= 0x800; - outw(d, dev->iobase + DAC0_REG); - break; - case 1: - if (devpriv->dac1_coding == dac_2comp) - d ^= 0x800; - outw(d, dev->iobase + DAC1_REG); - break; - default: - return -EINVAL; - } - devpriv->ao_readback[chan] = data[i]; + unsigned int val = data[i]; + + s->readback[chan] = val; + + if (munge) + val ^= 0x800; + + outw(val, dev->iobase + reg); } - return i; + + return insn->n; } static int atmio16d_dio_insn_bits(struct comedi_device *dev, @@ -617,7 +601,7 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev, static int atmio16d_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct atmio16_board_t *board = comedi_board(dev); + const struct atmio16_board_t *board = dev->board_ptr; struct atmio16d_private *devpriv; struct comedi_subdevice *s; int ret; @@ -688,8 +672,6 @@ static int atmio16d_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; - s->insn_read = atmio16d_ao_insn_read; - s->insn_write = atmio16d_ao_insn_write; s->maxdata = 0xfff; /* 4095 decimal */ s->range_table_list = devpriv->ao_range_type_list; switch (devpriv->dac0_range) { @@ -708,6 +690,12 @@ static int atmio16d_attach(struct comedi_device *dev, devpriv->ao_range_type_list[1] = &range_unipolar10; break; } + s->insn_write = atmio16d_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; /* Digital I/O */ s = &dev->subdevices[2]; @@ -722,7 +710,7 @@ static int atmio16d_attach(struct comedi_device *dev, /* 8255 subdevice */ s = &dev->subdevices[3]; if (board->has_8255) { - ret = subdev_8255_init(dev, s, NULL, dev->iobase); + ret = subdev_8255_init(dev, s, NULL, 0x00); if (ret) return ret; } else { diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 925e82c65b2d..8cfabdbaa30c 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -59,7 +59,7 @@ static int dio24_auto_attach(struct comedi_device *dev, /* 8255 dio */ s = &dev->subdevices[0]; - ret = subdev_8255_init(dev, s, NULL, dev->iobase); + ret = subdev_8255_init(dev, s, NULL, 0x00); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 126d65cb39f2..1fbfdb4c80c0 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -58,99 +58,12 @@ */ #include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/delay.h> #include "../comedidev.h" -#include "8253.h" -#include "8255.h" -#include "comedi_fc.h" #include "ni_labpc.h" -#include "ni_labpc_regs.h" #include "ni_labpc_isadma.h" -enum scan_mode { - MODE_SINGLE_CHAN, - MODE_SINGLE_CHAN_INTERVAL, - MODE_MULT_CHAN_UP, - MODE_MULT_CHAN_DOWN, -}; - -static const struct comedi_lrange range_labpc_plus_ai = { - 16, { - BIP_RANGE(5), - BIP_RANGE(4), - BIP_RANGE(2.5), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.25), - BIP_RANGE(0.1), - BIP_RANGE(0.05), - UNI_RANGE(10), - UNI_RANGE(8), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE(0.5), - UNI_RANGE(0.2), - UNI_RANGE(0.1) - } -}; - -static const struct comedi_lrange range_labpc_1200_ai = { - 14, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.25), - BIP_RANGE(0.1), - BIP_RANGE(0.05), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE(0.5), - UNI_RANGE(0.2), - UNI_RANGE(0.1) - } -}; - -static const struct comedi_lrange range_labpc_ao = { - 2, { - BIP_RANGE(5), - UNI_RANGE(10) - } -}; - -/* functions that do inb/outb and readb/writeb so we can use - * function pointers to decide which to use */ -static unsigned int labpc_inb(struct comedi_device *dev, unsigned long reg) -{ - return inb(dev->iobase + reg); -} - -static void labpc_outb(struct comedi_device *dev, - unsigned int byte, unsigned long reg) -{ - outb(byte, dev->iobase + reg); -} - -static unsigned int labpc_readb(struct comedi_device *dev, unsigned long reg) -{ - return readb(dev->mmio + reg); -} - -static void labpc_writeb(struct comedi_device *dev, - unsigned int byte, unsigned long reg) -{ - writeb(byte, dev->mmio + reg); -} - -#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA) static const struct labpc_boardinfo labpc_boards[] = { { .name = "lab-pc-1200", @@ -169,1284 +82,7 @@ static const struct labpc_boardinfo labpc_boards[] = { .has_ao = 1, }, }; -#endif - -static void labpc_counter_load(struct comedi_device *dev, - unsigned long reg, - unsigned int counter_number, - unsigned int count, - unsigned int mode) -{ - if (dev->mmio) { - i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode); - i8254_mm_write(dev->mmio + reg, 0, counter_number, count); - } else { - i8254_set_mode(dev->iobase + reg, 0, counter_number, mode); - i8254_write(dev->iobase + reg, 0, counter_number, count); - } -} - -static void labpc_counter_set_mode(struct comedi_device *dev, - unsigned long reg, - unsigned int counter_number, - unsigned int mode) -{ - if (dev->mmio) - i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode); - else - i8254_set_mode(dev->iobase + reg, 0, counter_number, mode); -} - -static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct labpc_private *devpriv = dev->private; - unsigned long flags; - - spin_lock_irqsave(&dev->spinlock, flags); - devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG); - devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - devpriv->cmd3 = 0; - devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG); - - return 0; -} - -static void labpc_ai_set_chan_and_gain(struct comedi_device *dev, - enum scan_mode mode, - unsigned int chan, - unsigned int range, - unsigned int aref) -{ - const struct labpc_boardinfo *board = comedi_board(dev); - struct labpc_private *devpriv = dev->private; - - if (board->is_labpc1200) { - /* - * The LabPC-1200 boards do not have a gain - * of '0x10'. Skip the range values that would - * result in this gain. - */ - range += (range > 0) + (range > 7); - } - - /* munge channel bits for differential/scan disabled mode */ - if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) && - aref == AREF_DIFF) - chan *= 2; - devpriv->cmd1 = CMD1_MA(chan); - devpriv->cmd1 |= CMD1_GAIN(range); - - devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG); -} - -static void labpc_setup_cmd6_reg(struct comedi_device *dev, - struct comedi_subdevice *s, - enum scan_mode mode, - enum transfer_type xfer, - unsigned int range, - unsigned int aref, - bool ena_intr) -{ - const struct labpc_boardinfo *board = comedi_board(dev); - struct labpc_private *devpriv = dev->private; - - if (!board->is_labpc1200) - return; - - /* reference inputs to ground or common? */ - if (aref != AREF_GROUND) - devpriv->cmd6 |= CMD6_NRSE; - else - devpriv->cmd6 &= ~CMD6_NRSE; - - /* bipolar or unipolar range? */ - if (comedi_range_is_unipolar(s, range)) - devpriv->cmd6 |= CMD6_ADCUNI; - else - devpriv->cmd6 &= ~CMD6_ADCUNI; - - /* interrupt on fifo half full? */ - if (xfer == fifo_half_full_transfer) - devpriv->cmd6 |= CMD6_HFINTEN; - else - devpriv->cmd6 &= ~CMD6_HFINTEN; - - /* enable interrupt on counter a1 terminal count? */ - if (ena_intr) - devpriv->cmd6 |= CMD6_DQINTEN; - else - devpriv->cmd6 &= ~CMD6_DQINTEN; - - /* are we scanning up or down through channels? */ - if (mode == MODE_MULT_CHAN_UP) - devpriv->cmd6 |= CMD6_SCANUP; - else - devpriv->cmd6 &= ~CMD6_SCANUP; - - devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG); -} - -static unsigned int labpc_read_adc_fifo(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - unsigned int lsb = devpriv->read_byte(dev, ADC_FIFO_REG); - unsigned int msb = devpriv->read_byte(dev, ADC_FIFO_REG); - - return (msb << 8) | lsb; -} - -static void labpc_clear_adc_fifo(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - - devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); - labpc_read_adc_fifo(dev); -} - -static int labpc_ai_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned long context) -{ - struct labpc_private *devpriv = dev->private; - - devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); - if (devpriv->stat1 & STAT1_DAVAIL) - return 0; - return -EBUSY; -} - -static int labpc_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct labpc_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int range = CR_RANGE(insn->chanspec); - unsigned int aref = CR_AREF(insn->chanspec); - int ret; - int i; - - /* disable timed conversions, interrupt generation and dma */ - labpc_cancel(dev, s); - - labpc_ai_set_chan_and_gain(dev, MODE_SINGLE_CHAN, chan, range, aref); - - labpc_setup_cmd6_reg(dev, s, MODE_SINGLE_CHAN, fifo_not_empty_transfer, - range, aref, false); - - /* setup cmd4 register */ - devpriv->cmd4 = 0; - devpriv->cmd4 |= CMD4_ECLKRCV; - /* single-ended/differential */ - if (aref == AREF_DIFF) - devpriv->cmd4 |= CMD4_SEDIFF; - devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG); - - /* initialize pacer counter to prevent any problems */ - labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2); - - labpc_clear_adc_fifo(dev); - - for (i = 0; i < insn->n; i++) { - /* trigger conversion */ - devpriv->write_byte(dev, 0x1, ADC_START_CONVERT_REG); - - ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0); - if (ret) - return ret; - - data[i] = labpc_read_adc_fifo(dev); - } - - return insn->n; -} - -static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd, - enum scan_mode mode) -{ - if (mode == MODE_SINGLE_CHAN || cmd->scan_begin_src == TRIG_FOLLOW) - return true; - - return false; -} - -static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd, - enum scan_mode mode) -{ - if (cmd->convert_src != TRIG_TIMER) - return 0; - - if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER) - return cmd->scan_begin_arg; - - return cmd->convert_arg; -} - -static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, - enum scan_mode mode, unsigned int ns) -{ - if (cmd->convert_src != TRIG_TIMER) - return; - - if (mode == MODE_SINGLE_CHAN && - cmd->scan_begin_src == TRIG_TIMER) { - cmd->scan_begin_arg = ns; - if (cmd->convert_arg > cmd->scan_begin_arg) - cmd->convert_arg = cmd->scan_begin_arg; - } else - cmd->convert_arg = ns; -} - -static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd, - enum scan_mode mode) -{ - if (cmd->scan_begin_src != TRIG_TIMER) - return 0; - - if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER) - return 0; - - return cmd->scan_begin_arg; -} - -static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, - enum scan_mode mode, unsigned int ns) -{ - if (cmd->scan_begin_src != TRIG_TIMER) - return; - - if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER) - return; - - cmd->scan_begin_arg = ns; -} - -/* figures out what counter values to use based on command */ -static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, - enum scan_mode mode) -{ - struct labpc_private *devpriv = dev->private; - /* max value for 16 bit counter in mode 2 */ - const int max_counter_value = 0x10000; - /* min value for 16 bit counter in mode 2 */ - const int min_counter_value = 2; - unsigned int base_period; - unsigned int scan_period; - unsigned int convert_period; - - /* - * if both convert and scan triggers are TRIG_TIMER, then they - * both rely on counter b0 - */ - convert_period = labpc_ai_convert_period(cmd, mode); - scan_period = labpc_ai_scan_period(cmd, mode); - if (convert_period && scan_period) { - /* - * pick the lowest b0 divisor value we can (for maximum input - * clock speed on convert and scan counters) - */ - devpriv->divisor_b0 = (scan_period - 1) / - (I8254_OSC_BASE_2MHZ * max_counter_value) + 1; - if (devpriv->divisor_b0 < min_counter_value) - devpriv->divisor_b0 = min_counter_value; - if (devpriv->divisor_b0 > max_counter_value) - devpriv->divisor_b0 = max_counter_value; - - base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0; - - /* set a0 for conversion frequency and b1 for scan frequency */ - switch (cmd->flags & TRIG_ROUND_MASK) { - default: - case TRIG_ROUND_NEAREST: - devpriv->divisor_a0 = - (convert_period + (base_period / 2)) / base_period; - devpriv->divisor_b1 = - (scan_period + (base_period / 2)) / base_period; - break; - case TRIG_ROUND_UP: - devpriv->divisor_a0 = - (convert_period + (base_period - 1)) / base_period; - devpriv->divisor_b1 = - (scan_period + (base_period - 1)) / base_period; - break; - case TRIG_ROUND_DOWN: - devpriv->divisor_a0 = convert_period / base_period; - devpriv->divisor_b1 = scan_period / base_period; - break; - } - /* make sure a0 and b1 values are acceptable */ - if (devpriv->divisor_a0 < min_counter_value) - devpriv->divisor_a0 = min_counter_value; - if (devpriv->divisor_a0 > max_counter_value) - devpriv->divisor_a0 = max_counter_value; - if (devpriv->divisor_b1 < min_counter_value) - devpriv->divisor_b1 = min_counter_value; - if (devpriv->divisor_b1 > max_counter_value) - devpriv->divisor_b1 = max_counter_value; - /* write corrected timings to command */ - labpc_set_ai_convert_period(cmd, mode, - base_period * devpriv->divisor_a0); - labpc_set_ai_scan_period(cmd, mode, - base_period * devpriv->divisor_b1); - /* - * if only one TRIG_TIMER is used, we can employ the generic - * cascaded timing functions - */ - } else if (scan_period) { - /* - * calculate cascaded counter values - * that give desired scan timing - */ - i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, - &devpriv->divisor_b1, - &devpriv->divisor_b0, - &scan_period, cmd->flags); - labpc_set_ai_scan_period(cmd, mode, scan_period); - } else if (convert_period) { - /* - * calculate cascaded counter values - * that give desired conversion timing - */ - i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, - &devpriv->divisor_a0, - &devpriv->divisor_b0, - &convert_period, cmd->flags); - labpc_set_ai_convert_period(cmd, mode, convert_period); - } -} - -static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) -{ - unsigned int chan0; - unsigned int chan1; - - if (cmd->chanlist_len == 1) - return MODE_SINGLE_CHAN; - - /* chanlist may be NULL during cmdtest */ - if (cmd->chanlist == NULL) - return MODE_MULT_CHAN_UP; - - chan0 = CR_CHAN(cmd->chanlist[0]); - chan1 = CR_CHAN(cmd->chanlist[1]); - - if (chan0 < chan1) - return MODE_MULT_CHAN_UP; - - if (chan0 > chan1) - return MODE_MULT_CHAN_DOWN; - - return MODE_SINGLE_CHAN_INTERVAL; -} - -static int labpc_ai_check_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - enum scan_mode mode = labpc_ai_scan_mode(cmd); - unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); - unsigned int range0 = CR_RANGE(cmd->chanlist[0]); - unsigned int aref0 = CR_AREF(cmd->chanlist[0]); - int i; - - if (mode == MODE_SINGLE_CHAN) - return 0; - - for (i = 0; i < cmd->chanlist_len; i++) { - unsigned int chan = CR_CHAN(cmd->chanlist[i]); - unsigned int range = CR_RANGE(cmd->chanlist[i]); - unsigned int aref = CR_AREF(cmd->chanlist[i]); - - switch (mode) { - case MODE_SINGLE_CHAN: - break; - case MODE_SINGLE_CHAN_INTERVAL: - if (chan != chan0) { - dev_dbg(dev->class_dev, - "channel scanning order specified in chanlist is not supported by hardware\n"); - return -EINVAL; - } - break; - case MODE_MULT_CHAN_UP: - if (chan != i) { - dev_dbg(dev->class_dev, - "channel scanning order specified in chanlist is not supported by hardware\n"); - return -EINVAL; - } - break; - case MODE_MULT_CHAN_DOWN: - if (chan != (cmd->chanlist_len - i - 1)) { - dev_dbg(dev->class_dev, - "channel scanning order specified in chanlist is not supported by hardware\n"); - return -EINVAL; - } - break; - } - - if (range != range0) { - dev_dbg(dev->class_dev, - "entries in chanlist must all have the same range\n"); - return -EINVAL; - } - - if (aref != aref0) { - dev_dbg(dev->class_dev, - "entries in chanlist must all have the same reference\n"); - return -EINVAL; - } - } - - return 0; -} - -static int labpc_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - const struct labpc_boardinfo *board = comedi_board(dev); - int err = 0; - int tmp, tmp2; - unsigned int stop_mask; - enum scan_mode mode; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - - stop_mask = TRIG_COUNT | TRIG_NONE; - if (board->is_labpc1200) - stop_mask |= TRIG_EXT; - err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->start_src); - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_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++; - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - switch (cmd->start_src) { - case TRIG_NOW: - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - break; - case TRIG_EXT: - /* start_arg value is ignored */ - break; - } - - if (!cmd->chanlist_len) - err |= -EINVAL; - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - if (cmd->convert_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - board->ai_speed); - - /* make sure scan timing is not too fast */ - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->convert_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - cmd->convert_arg * cmd->chanlist_len); - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - board->ai_speed * cmd->chanlist_len); - } - - switch (cmd->stop_src) { - case TRIG_COUNT: - err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); - break; - case TRIG_NONE: - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - /* - * 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 */ - - tmp = cmd->convert_arg; - tmp2 = cmd->scan_begin_arg; - mode = labpc_ai_scan_mode(cmd); - labpc_adc_timing(dev, cmd, mode); - if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg) - err++; - - if (err) - return 4; - - /* Step 5: check channel list if it exists */ - if (cmd->chanlist && cmd->chanlist_len > 0) - err |= labpc_ai_check_chanlist(dev, s, cmd); - - if (err) - return 5; - - return 0; -} - -static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - const struct labpc_boardinfo *board = comedi_board(dev); - struct labpc_private *devpriv = dev->private; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - enum scan_mode mode = labpc_ai_scan_mode(cmd); - unsigned int chanspec = (mode == MODE_MULT_CHAN_UP) - ? cmd->chanlist[cmd->chanlist_len - 1] - : cmd->chanlist[0]; - unsigned int chan = CR_CHAN(chanspec); - unsigned int range = CR_RANGE(chanspec); - unsigned int aref = CR_AREF(chanspec); - enum transfer_type xfer; - unsigned long flags; - - /* make sure board is disabled before setting up acquisition */ - labpc_cancel(dev, s); - - /* initialize software conversion count */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->count = cmd->stop_arg * cmd->chanlist_len; - - /* setup hardware conversion counter */ - if (cmd->stop_src == TRIG_EXT) { - /* - * load counter a1 with count of 3 - * (pc+ manual says this is minimum allowed) using mode 0 - */ - labpc_counter_load(dev, COUNTER_A_BASE_REG, - 1, 3, I8254_MODE0); - } else { - /* just put counter a1 in mode 0 to set its output low */ - labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 1, I8254_MODE0); - } - - /* figure out what method we will use to transfer data */ - if (labpc_have_dma_chan(dev) && - /* dma unsafe at RT priority, - * and too much setup time for TRIG_WAKE_EOS */ - (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0) - xfer = isa_dma_transfer; - else if (/* pc-plus has no fifo-half full interrupt */ - board->is_labpc1200 && - /* wake-end-of-scan should interrupt on fifo not empty */ - (cmd->flags & TRIG_WAKE_EOS) == 0 && - /* make sure we are taking more than just a few points */ - (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) - xfer = fifo_half_full_transfer; - else - xfer = fifo_not_empty_transfer; - devpriv->current_transfer = xfer; - - labpc_ai_set_chan_and_gain(dev, mode, chan, range, aref); - - labpc_setup_cmd6_reg(dev, s, mode, xfer, range, aref, - (cmd->stop_src == TRIG_EXT)); - /* manual says to set scan enable bit on second pass */ - if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) { - devpriv->cmd1 |= CMD1_SCANEN; - /* need a brief delay before enabling scan, or scan - * list will get screwed when you switch - * between scan up to scan down mode - dunno why */ - udelay(1); - devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG); - } - - devpriv->write_byte(dev, cmd->chanlist_len, INTERVAL_COUNT_REG); - /* load count */ - devpriv->write_byte(dev, 0x1, INTERVAL_STROBE_REG); - - if (cmd->convert_src == TRIG_TIMER || - cmd->scan_begin_src == TRIG_TIMER) { - /* set up pacing */ - labpc_adc_timing(dev, cmd, mode); - /* load counter b0 in mode 3 */ - labpc_counter_load(dev, COUNTER_B_BASE_REG, - 0, devpriv->divisor_b0, I8254_MODE3); - } - /* set up conversion pacing */ - if (labpc_ai_convert_period(cmd, mode)) { - /* load counter a0 in mode 2 */ - labpc_counter_load(dev, COUNTER_A_BASE_REG, - 0, devpriv->divisor_a0, I8254_MODE2); - } else { - /* initialize pacer counter to prevent any problems */ - labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2); - } - - /* set up scan pacing */ - if (labpc_ai_scan_period(cmd, mode)) { - /* load counter b1 in mode 2 */ - labpc_counter_load(dev, COUNTER_B_BASE_REG, - 1, devpriv->divisor_b1, I8254_MODE2); - } - - labpc_clear_adc_fifo(dev); - - if (xfer == isa_dma_transfer) - labpc_setup_dma(dev, s); - - /* enable error interrupts */ - devpriv->cmd3 |= CMD3_ERRINTEN; - /* enable fifo not empty interrupt? */ - if (xfer == fifo_not_empty_transfer) - devpriv->cmd3 |= CMD3_FIFOINTEN; - devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG); - - /* setup any external triggering/pacing (cmd4 register) */ - devpriv->cmd4 = 0; - if (cmd->convert_src != TRIG_EXT) - devpriv->cmd4 |= CMD4_ECLKRCV; - /* XXX should discard first scan when using interval scanning - * since manual says it is not synced with scan clock */ - if (!labpc_use_continuous_mode(cmd, mode)) { - devpriv->cmd4 |= CMD4_INTSCAN; - if (cmd->scan_begin_src == TRIG_EXT) - devpriv->cmd4 |= CMD4_EOIRCV; - } - /* single-ended/differential */ - if (aref == AREF_DIFF) - devpriv->cmd4 |= CMD4_SEDIFF; - devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG); - - /* startup acquisition */ - - spin_lock_irqsave(&dev->spinlock, flags); - - /* use 2 cascaded counters for pacing */ - devpriv->cmd2 |= CMD2_TBSEL; - - devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG); - if (cmd->start_src == TRIG_EXT) - devpriv->cmd2 |= CMD2_HWTRIG; - else - devpriv->cmd2 |= CMD2_SWTRIG; - if (cmd->stop_src == TRIG_EXT) - devpriv->cmd2 |= (CMD2_HWTRIG | CMD2_PRETRIG); - - devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); - - spin_unlock_irqrestore(&dev->spinlock, flags); - - return 0; -} - -/* read all available samples from ai fifo */ -static int labpc_drain_fifo(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - struct comedi_async *async = dev->read_subdev->async; - struct comedi_cmd *cmd = &async->cmd; - unsigned short data; - const int timeout = 10000; - unsigned int i; - - devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); - - for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout; - i++) { - /* quit if we have all the data we want */ - if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->count == 0) - break; - devpriv->count--; - } - data = labpc_read_adc_fifo(dev); - cfc_write_to_buffer(dev->read_subdev, data); - devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); - } - if (i == timeout) { - dev_err(dev->class_dev, "ai timeout, fifo never empties\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - return -1; - } - - return 0; -} - -/* makes sure all data acquired by board is transferred to comedi (used - * when acquisition is terminated by stop_src == TRIG_EXT). */ -static void labpc_drain_dregs(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - - if (devpriv->current_transfer == isa_dma_transfer) - labpc_drain_dma(dev); - - labpc_drain_fifo(dev); -} - -/* interrupt service routine */ -static irqreturn_t labpc_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - const struct labpc_boardinfo *board = comedi_board(dev); - struct labpc_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async; - struct comedi_cmd *cmd; - - if (!dev->attached) { - dev_err(dev->class_dev, "premature interrupt\n"); - return IRQ_HANDLED; - } - - async = s->async; - cmd = &async->cmd; - - /* read board status */ - devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); - if (board->is_labpc1200) - devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG); - - if ((devpriv->stat1 & (STAT1_GATA0 | STAT1_CNTINT | STAT1_OVERFLOW | - STAT1_OVERRUN | STAT1_DAVAIL)) == 0 - && (devpriv->stat2 & STAT2_OUTA1) == 0 - && (devpriv->stat2 & STAT2_FIFONHF)) { - return IRQ_NONE; - } - - if (devpriv->stat1 & STAT1_OVERRUN) { - /* clear error interrupt */ - devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); - dev_err(dev->class_dev, "overrun\n"); - return IRQ_HANDLED; - } - - if (devpriv->current_transfer == isa_dma_transfer) - labpc_handle_dma_status(dev); - else - labpc_drain_fifo(dev); - - if (devpriv->stat1 & STAT1_CNTINT) { - dev_err(dev->class_dev, "handled timer interrupt?\n"); - /* clear it */ - devpriv->write_byte(dev, 0x1, TIMER_CLEAR_REG); - } - - if (devpriv->stat1 & STAT1_OVERFLOW) { - /* clear error interrupt */ - devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - cfc_handle_events(dev, s); - dev_err(dev->class_dev, "overflow\n"); - return IRQ_HANDLED; - } - /* handle external stop trigger */ - if (cmd->stop_src == TRIG_EXT) { - if (devpriv->stat2 & STAT2_OUTA1) { - labpc_drain_dregs(dev); - async->events |= COMEDI_CB_EOA; - } - } - - /* TRIG_COUNT end of acquisition */ - if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->count == 0) - async->events |= COMEDI_CB_EOA; - } - - cfc_handle_events(dev, s); - return IRQ_HANDLED; -} - -static int labpc_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct labpc_boardinfo *board = comedi_board(dev); - struct labpc_private *devpriv = dev->private; - int channel, range; - unsigned long flags; - int lsb, msb; - - channel = CR_CHAN(insn->chanspec); - - /* turn off pacing of analog output channel */ - /* note: hardware bug in daqcard-1200 means pacing cannot - * be independently enabled/disabled for its the two channels */ - spin_lock_irqsave(&dev->spinlock, flags); - devpriv->cmd2 &= ~CMD2_LDAC(channel); - devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* set range */ - if (board->is_labpc1200) { - range = CR_RANGE(insn->chanspec); - if (comedi_range_is_unipolar(s, range)) - devpriv->cmd6 |= CMD6_DACUNI(channel); - else - devpriv->cmd6 &= ~CMD6_DACUNI(channel); - /* write to register */ - devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG); - } - /* send data */ - lsb = data[0] & 0xff; - msb = (data[0] >> 8) & 0xff; - devpriv->write_byte(dev, lsb, DAC_LSB_REG(channel)); - devpriv->write_byte(dev, msb, DAC_MSB_REG(channel)); - - /* remember value for readback */ - devpriv->ao_value[channel] = data[0]; - - return 1; -} - -static int labpc_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct labpc_private *devpriv = dev->private; - - data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; - - return 1; -} - -static int labpc_8255_mmio(int dir, int port, int data, unsigned long arg) -{ - struct comedi_device *dev = (struct comedi_device *)arg; - - if (dir) { - writeb(data, dev->mmio + DIO_BASE_REG + port); - return 0; - } - - return readb(dev->mmio + DIO_BASE_REG + port); -} - -/* lowlevel write to eeprom/dac */ -static void labpc_serial_out(struct comedi_device *dev, unsigned int value, - unsigned int value_width) -{ - struct labpc_private *devpriv = dev->private; - int i; - - for (i = 1; i <= value_width; i++) { - /* clear serial clock */ - devpriv->cmd5 &= ~CMD5_SCLK; - /* send bits most significant bit first */ - if (value & (1 << (value_width - i))) - devpriv->cmd5 |= CMD5_SDATA; - else - devpriv->cmd5 &= ~CMD5_SDATA; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - /* set clock to load bit */ - devpriv->cmd5 |= CMD5_SCLK; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - } -} - -/* lowlevel read from eeprom */ -static unsigned int labpc_serial_in(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - unsigned int value = 0; - int i; - const int value_width = 8; /* number of bits wide values are */ - - for (i = 1; i <= value_width; i++) { - /* set serial clock */ - devpriv->cmd5 |= CMD5_SCLK; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - /* clear clock bit */ - devpriv->cmd5 &= ~CMD5_SCLK; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - /* read bits most significant bit first */ - udelay(1); - devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG); - if (devpriv->stat2 & STAT2_PROMOUT) - value |= 1 << (value_width - i); - } - - return value; -} - -static unsigned int labpc_eeprom_read(struct comedi_device *dev, - unsigned int address) -{ - struct labpc_private *devpriv = dev->private; - unsigned int value; - /* bits to tell eeprom to expect a read */ - const int read_instruction = 0x3; - /* 8 bit write lengths to eeprom */ - const int write_length = 8; - - /* enable read/write to eeprom */ - devpriv->cmd5 &= ~CMD5_EEPROMCS; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - /* send read instruction */ - labpc_serial_out(dev, read_instruction, write_length); - /* send 8 bit address to read from */ - labpc_serial_out(dev, address, write_length); - /* read result */ - value = labpc_serial_in(dev); - - /* disable read/write to eeprom */ - devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - return value; -} - -static unsigned int labpc_eeprom_read_status(struct comedi_device *dev) -{ - struct labpc_private *devpriv = dev->private; - unsigned int value; - const int read_status_instruction = 0x5; - const int write_length = 8; /* 8 bit write lengths to eeprom */ - - /* enable read/write to eeprom */ - devpriv->cmd5 &= ~CMD5_EEPROMCS; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - /* send read status instruction */ - labpc_serial_out(dev, read_status_instruction, write_length); - /* read result */ - value = labpc_serial_in(dev); - - /* disable read/write to eeprom */ - devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - return value; -} - -static int labpc_eeprom_write(struct comedi_device *dev, - unsigned int address, unsigned int value) -{ - struct labpc_private *devpriv = dev->private; - const int write_enable_instruction = 0x6; - const int write_instruction = 0x2; - const int write_length = 8; /* 8 bit write lengths to eeprom */ - const int write_in_progress_bit = 0x1; - const int timeout = 10000; - int i; - - /* make sure there isn't already a write in progress */ - for (i = 0; i < timeout; i++) { - if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) == - 0) - break; - } - if (i == timeout) { - dev_err(dev->class_dev, "eeprom write timed out\n"); - return -ETIME; - } - /* update software copy of eeprom */ - devpriv->eeprom_data[address] = value; - - /* enable read/write to eeprom */ - devpriv->cmd5 &= ~CMD5_EEPROMCS; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - /* send write_enable instruction */ - labpc_serial_out(dev, write_enable_instruction, write_length); - devpriv->cmd5 &= ~CMD5_EEPROMCS; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - /* send write instruction */ - devpriv->cmd5 |= CMD5_EEPROMCS; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - labpc_serial_out(dev, write_instruction, write_length); - /* send 8 bit address to write to */ - labpc_serial_out(dev, address, write_length); - /* write value */ - labpc_serial_out(dev, value, write_length); - devpriv->cmd5 &= ~CMD5_EEPROMCS; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - /* disable read/write to eeprom */ - devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - return 0; -} - -/* writes to 8 bit calibration dacs */ -static void write_caldac(struct comedi_device *dev, unsigned int channel, - unsigned int value) -{ - struct labpc_private *devpriv = dev->private; - - if (value == devpriv->caldac[channel]) - return; - devpriv->caldac[channel] = value; - - /* clear caldac load bit and make sure we don't write to eeprom */ - devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT); - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - - /* write 4 bit channel */ - labpc_serial_out(dev, channel, 4); - /* write 8 bit caldac value */ - labpc_serial_out(dev, value, 8); - - /* set and clear caldac bit to load caldac value */ - devpriv->cmd5 |= CMD5_CALDACLD; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - devpriv->cmd5 &= ~CMD5_CALDACLD; - udelay(1); - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); -} - -static int labpc_calib_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned int chan = CR_CHAN(insn->chanspec); - - /* - * Only write the last data value to the caldac. Preceding - * data would be overwritten anyway. - */ - if (insn->n > 0) - write_caldac(dev, chan, data[insn->n - 1]); - - return insn->n; -} - -static int labpc_calib_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct labpc_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->caldac[chan]; - - return insn->n; -} - -static int labpc_eeprom_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned int chan = CR_CHAN(insn->chanspec); - int ret; - - /* only allow writes to user area of eeprom */ - if (chan < 16 || chan > 127) - return -EINVAL; - - /* - * Only write the last data value to the eeprom. Preceding - * data would be overwritten anyway. - */ - if (insn->n > 0) { - ret = labpc_eeprom_write(dev, chan, data[insn->n - 1]); - if (ret) - return ret; - } - - return insn->n; -} - -static int labpc_eeprom_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct labpc_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->eeprom_data[chan]; - - return insn->n; -} - -int labpc_common_attach(struct comedi_device *dev, - unsigned int irq, unsigned long isr_flags) -{ - const struct labpc_boardinfo *board = comedi_board(dev); - struct labpc_private *devpriv = dev->private; - struct comedi_subdevice *s; - int ret; - int i; - - if (dev->mmio) { - devpriv->read_byte = labpc_readb; - devpriv->write_byte = labpc_writeb; - } else { - devpriv->read_byte = labpc_inb; - devpriv->write_byte = labpc_outb; - } - - /* initialize board's command registers */ - devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG); - devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); - devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG); - devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG); - if (board->is_labpc1200) { - devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); - devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG); - } - - if (irq) { - ret = request_irq(irq, labpc_interrupt, isr_flags, - dev->board_name, dev); - if (ret == 0) - dev->irq = irq; - } - - ret = comedi_alloc_subdevices(dev, 5); - if (ret) - return ret; - - /* analog input subdevice */ - s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF; - s->n_chan = 8; - s->len_chanlist = 8; - s->maxdata = 0x0fff; - s->range_table = board->is_labpc1200 - ? &range_labpc_1200_ai : &range_labpc_plus_ai; - s->insn_read = labpc_ai_insn_read; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmd = labpc_ai_cmd; - s->do_cmdtest = labpc_ai_cmdtest; - s->cancel = labpc_cancel; - } - - /* analog output */ - s = &dev->subdevices[1]; - if (board->has_ao) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; - s->n_chan = NUM_AO_CHAN; - s->maxdata = 0x0fff; - s->range_table = &range_labpc_ao; - s->insn_read = labpc_ao_insn_read; - s->insn_write = labpc_ao_insn_write; - - /* initialize analog outputs to a known value */ - for (i = 0; i < s->n_chan; i++) { - short lsb, msb; - - devpriv->ao_value[i] = s->maxdata / 2; - lsb = devpriv->ao_value[i] & 0xff; - msb = (devpriv->ao_value[i] >> 8) & 0xff; - devpriv->write_byte(dev, lsb, DAC_LSB_REG(i)); - devpriv->write_byte(dev, msb, DAC_MSB_REG(i)); - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* 8255 dio */ - s = &dev->subdevices[2]; - if (dev->mmio) { - ret = subdev_8255_init(dev, s, labpc_8255_mmio, - (unsigned long)dev); - } else { - ret = subdev_8255_init(dev, s, NULL, - dev->iobase + DIO_BASE_REG); - } - if (ret) - return ret; - - /* calibration subdevices for boards that have one */ - s = &dev->subdevices[3]; - if (board->is_labpc1200) { - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 16; - s->maxdata = 0xff; - s->insn_read = labpc_calib_insn_read; - s->insn_write = labpc_calib_insn_write; - - for (i = 0; i < s->n_chan; i++) - write_caldac(dev, i, s->maxdata / 2); - } else - s->type = COMEDI_SUBD_UNUSED; - - /* EEPROM */ - s = &dev->subdevices[4]; - if (board->is_labpc1200) { - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = EEPROM_SIZE; - s->maxdata = 0xff; - s->insn_read = labpc_eeprom_insn_read; - s->insn_write = labpc_eeprom_insn_write; - - for (i = 0; i < s->n_chan; i++) - devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); - } else - s->type = COMEDI_SUBD_UNUSED; - - return 0; -} -EXPORT_SYMBOL_GPL(labpc_common_attach); - -#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA) static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct labpc_private *devpriv; @@ -1492,19 +128,7 @@ static struct comedi_driver labpc_driver = { .offset = sizeof(struct labpc_boardinfo), }; module_comedi_driver(labpc_driver); -#else -static int __init labpc_common_init(void) -{ - return 0; -} -module_init(labpc_common_init); - -static void __exit labpc_common_exit(void) -{ -} -module_exit(labpc_common_exit); -#endif MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for NI Lab-PC ISA boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/staging/comedi/drivers/ni_labpc_common.c new file mode 100644 index 000000000000..35bc2c25ddfb --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_common.c @@ -0,0 +1,1387 @@ +/* + * comedi/drivers/ni_labpc_common.c + * + * Common support code for "ni_labpc", "ni_labpc_pci" and "ni_labpc_cs". + * + * Copyright (C) 2001-2003 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/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/delay.h> + +#include "../comedidev.h" + +#include "8253.h" +#include "8255.h" +#include "comedi_fc.h" +#include "ni_labpc.h" +#include "ni_labpc_regs.h" +#include "ni_labpc_isadma.h" + +enum scan_mode { + MODE_SINGLE_CHAN, + MODE_SINGLE_CHAN_INTERVAL, + MODE_MULT_CHAN_UP, + MODE_MULT_CHAN_DOWN, +}; + +static const struct comedi_lrange range_labpc_plus_ai = { + 16, { + BIP_RANGE(5), + BIP_RANGE(4), + BIP_RANGE(2.5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.25), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + UNI_RANGE(10), + UNI_RANGE(8), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } +}; + +static const struct comedi_lrange range_labpc_1200_ai = { + 14, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.25), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } +}; + +static const struct comedi_lrange range_labpc_ao = { + 2, { + BIP_RANGE(5), + UNI_RANGE(10) + } +}; + +/* functions that do inb/outb and readb/writeb so we can use + * function pointers to decide which to use */ +static unsigned int labpc_inb(struct comedi_device *dev, unsigned long reg) +{ + return inb(dev->iobase + reg); +} + +static void labpc_outb(struct comedi_device *dev, + unsigned int byte, unsigned long reg) +{ + outb(byte, dev->iobase + reg); +} + +static unsigned int labpc_readb(struct comedi_device *dev, unsigned long reg) +{ + return readb(dev->mmio + reg); +} + +static void labpc_writeb(struct comedi_device *dev, + unsigned int byte, unsigned long reg) +{ + writeb(byte, dev->mmio + reg); +} + +static void labpc_counter_load(struct comedi_device *dev, + unsigned long reg, + unsigned int counter_number, + unsigned int count, + unsigned int mode) +{ + if (dev->mmio) { + i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode); + i8254_mm_write(dev->mmio + reg, 0, counter_number, count); + } else { + i8254_set_mode(dev->iobase + reg, 0, counter_number, mode); + i8254_write(dev->iobase + reg, 0, counter_number, count); + } +} + +static void labpc_counter_set_mode(struct comedi_device *dev, + unsigned long reg, + unsigned int counter_number, + unsigned int mode) +{ + if (dev->mmio) + i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode); + else + i8254_set_mode(dev->iobase + reg, 0, counter_number, mode); +} + +static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct labpc_private *devpriv = dev->private; + unsigned long flags; + + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG); + devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + + devpriv->cmd3 = 0; + devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG); + + return 0; +} + +static void labpc_ai_set_chan_and_gain(struct comedi_device *dev, + enum scan_mode mode, + unsigned int chan, + unsigned int range, + unsigned int aref) +{ + const struct labpc_boardinfo *board = dev->board_ptr; + struct labpc_private *devpriv = dev->private; + + if (board->is_labpc1200) { + /* + * The LabPC-1200 boards do not have a gain + * of '0x10'. Skip the range values that would + * result in this gain. + */ + range += (range > 0) + (range > 7); + } + + /* munge channel bits for differential/scan disabled mode */ + if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) && + aref == AREF_DIFF) + chan *= 2; + devpriv->cmd1 = CMD1_MA(chan); + devpriv->cmd1 |= CMD1_GAIN(range); + + devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG); +} + +static void labpc_setup_cmd6_reg(struct comedi_device *dev, + struct comedi_subdevice *s, + enum scan_mode mode, + enum transfer_type xfer, + unsigned int range, + unsigned int aref, + bool ena_intr) +{ + const struct labpc_boardinfo *board = dev->board_ptr; + struct labpc_private *devpriv = dev->private; + + if (!board->is_labpc1200) + return; + + /* reference inputs to ground or common? */ + if (aref != AREF_GROUND) + devpriv->cmd6 |= CMD6_NRSE; + else + devpriv->cmd6 &= ~CMD6_NRSE; + + /* bipolar or unipolar range? */ + if (comedi_range_is_unipolar(s, range)) + devpriv->cmd6 |= CMD6_ADCUNI; + else + devpriv->cmd6 &= ~CMD6_ADCUNI; + + /* interrupt on fifo half full? */ + if (xfer == fifo_half_full_transfer) + devpriv->cmd6 |= CMD6_HFINTEN; + else + devpriv->cmd6 &= ~CMD6_HFINTEN; + + /* enable interrupt on counter a1 terminal count? */ + if (ena_intr) + devpriv->cmd6 |= CMD6_DQINTEN; + else + devpriv->cmd6 &= ~CMD6_DQINTEN; + + /* are we scanning up or down through channels? */ + if (mode == MODE_MULT_CHAN_UP) + devpriv->cmd6 |= CMD6_SCANUP; + else + devpriv->cmd6 &= ~CMD6_SCANUP; + + devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG); +} + +static unsigned int labpc_read_adc_fifo(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + unsigned int lsb = devpriv->read_byte(dev, ADC_FIFO_REG); + unsigned int msb = devpriv->read_byte(dev, ADC_FIFO_REG); + + return (msb << 8) | lsb; +} + +static void labpc_clear_adc_fifo(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); + labpc_read_adc_fifo(dev); +} + +static int labpc_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct labpc_private *devpriv = dev->private; + + devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); + if (devpriv->stat1 & STAT1_DAVAIL) + return 0; + return -EBUSY; +} + +static int labpc_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct labpc_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + int ret; + int i; + + /* disable timed conversions, interrupt generation and dma */ + labpc_cancel(dev, s); + + labpc_ai_set_chan_and_gain(dev, MODE_SINGLE_CHAN, chan, range, aref); + + labpc_setup_cmd6_reg(dev, s, MODE_SINGLE_CHAN, fifo_not_empty_transfer, + range, aref, false); + + /* setup cmd4 register */ + devpriv->cmd4 = 0; + devpriv->cmd4 |= CMD4_ECLKRCV; + /* single-ended/differential */ + if (aref == AREF_DIFF) + devpriv->cmd4 |= CMD4_SEDIFF; + devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG); + + /* initialize pacer counter to prevent any problems */ + labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2); + + labpc_clear_adc_fifo(dev); + + for (i = 0; i < insn->n; i++) { + /* trigger conversion */ + devpriv->write_byte(dev, 0x1, ADC_START_CONVERT_REG); + + ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0); + if (ret) + return ret; + + data[i] = labpc_read_adc_fifo(dev); + } + + return insn->n; +} + +static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd, + enum scan_mode mode) +{ + if (mode == MODE_SINGLE_CHAN || cmd->scan_begin_src == TRIG_FOLLOW) + return true; + + return false; +} + +static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd, + enum scan_mode mode) +{ + if (cmd->convert_src != TRIG_TIMER) + return 0; + + if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER) + return cmd->scan_begin_arg; + + return cmd->convert_arg; +} + +static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, + enum scan_mode mode, unsigned int ns) +{ + if (cmd->convert_src != TRIG_TIMER) + return; + + if (mode == MODE_SINGLE_CHAN && + cmd->scan_begin_src == TRIG_TIMER) { + cmd->scan_begin_arg = ns; + if (cmd->convert_arg > cmd->scan_begin_arg) + cmd->convert_arg = cmd->scan_begin_arg; + } else { + cmd->convert_arg = ns; + } +} + +static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd, + enum scan_mode mode) +{ + if (cmd->scan_begin_src != TRIG_TIMER) + return 0; + + if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER) + return 0; + + return cmd->scan_begin_arg; +} + +static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, + enum scan_mode mode, unsigned int ns) +{ + if (cmd->scan_begin_src != TRIG_TIMER) + return; + + if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER) + return; + + cmd->scan_begin_arg = ns; +} + +/* figures out what counter values to use based on command */ +static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, + enum scan_mode mode) +{ + struct labpc_private *devpriv = dev->private; + /* max value for 16 bit counter in mode 2 */ + const int max_counter_value = 0x10000; + /* min value for 16 bit counter in mode 2 */ + const int min_counter_value = 2; + unsigned int base_period; + unsigned int scan_period; + unsigned int convert_period; + + /* + * if both convert and scan triggers are TRIG_TIMER, then they + * both rely on counter b0 + */ + convert_period = labpc_ai_convert_period(cmd, mode); + scan_period = labpc_ai_scan_period(cmd, mode); + if (convert_period && scan_period) { + /* + * pick the lowest b0 divisor value we can (for maximum input + * clock speed on convert and scan counters) + */ + devpriv->divisor_b0 = (scan_period - 1) / + (I8254_OSC_BASE_2MHZ * max_counter_value) + 1; + if (devpriv->divisor_b0 < min_counter_value) + devpriv->divisor_b0 = min_counter_value; + if (devpriv->divisor_b0 > max_counter_value) + devpriv->divisor_b0 = max_counter_value; + + base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0; + + /* set a0 for conversion frequency and b1 for scan frequency */ + switch (cmd->flags & CMDF_ROUND_MASK) { + default: + case CMDF_ROUND_NEAREST: + devpriv->divisor_a0 = + (convert_period + (base_period / 2)) / base_period; + devpriv->divisor_b1 = + (scan_period + (base_period / 2)) / base_period; + break; + case CMDF_ROUND_UP: + devpriv->divisor_a0 = + (convert_period + (base_period - 1)) / base_period; + devpriv->divisor_b1 = + (scan_period + (base_period - 1)) / base_period; + break; + case CMDF_ROUND_DOWN: + devpriv->divisor_a0 = convert_period / base_period; + devpriv->divisor_b1 = scan_period / base_period; + break; + } + /* make sure a0 and b1 values are acceptable */ + if (devpriv->divisor_a0 < min_counter_value) + devpriv->divisor_a0 = min_counter_value; + if (devpriv->divisor_a0 > max_counter_value) + devpriv->divisor_a0 = max_counter_value; + if (devpriv->divisor_b1 < min_counter_value) + devpriv->divisor_b1 = min_counter_value; + if (devpriv->divisor_b1 > max_counter_value) + devpriv->divisor_b1 = max_counter_value; + /* write corrected timings to command */ + labpc_set_ai_convert_period(cmd, mode, + base_period * devpriv->divisor_a0); + labpc_set_ai_scan_period(cmd, mode, + base_period * devpriv->divisor_b1); + /* + * if only one TRIG_TIMER is used, we can employ the generic + * cascaded timing functions + */ + } else if (scan_period) { + /* + * calculate cascaded counter values + * that give desired scan timing + */ + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor_b1, + &devpriv->divisor_b0, + &scan_period, cmd->flags); + labpc_set_ai_scan_period(cmd, mode, scan_period); + } else if (convert_period) { + /* + * calculate cascaded counter values + * that give desired conversion timing + */ + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor_a0, + &devpriv->divisor_b0, + &convert_period, cmd->flags); + labpc_set_ai_convert_period(cmd, mode, convert_period); + } +} + +static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) +{ + unsigned int chan0; + unsigned int chan1; + + if (cmd->chanlist_len == 1) + return MODE_SINGLE_CHAN; + + /* chanlist may be NULL during cmdtest */ + if (cmd->chanlist == NULL) + return MODE_MULT_CHAN_UP; + + chan0 = CR_CHAN(cmd->chanlist[0]); + chan1 = CR_CHAN(cmd->chanlist[1]); + + if (chan0 < chan1) + return MODE_MULT_CHAN_UP; + + if (chan0 > chan1) + return MODE_MULT_CHAN_DOWN; + + return MODE_SINGLE_CHAN_INTERVAL; +} + +static int labpc_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + enum scan_mode mode = labpc_ai_scan_mode(cmd); + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + if (mode == MODE_SINGLE_CHAN) + return 0; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + switch (mode) { + case MODE_SINGLE_CHAN: + break; + case MODE_SINGLE_CHAN_INTERVAL: + if (chan != chan0) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; + } + break; + case MODE_MULT_CHAN_UP: + if (chan != i) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; + } + break; + case MODE_MULT_CHAN_DOWN: + if (chan != (cmd->chanlist_len - i - 1)) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; + } + break; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same range\n"); + return -EINVAL; + } + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same reference\n"); + return -EINVAL; + } + } + + return 0; +} + +static int labpc_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) +{ + const struct labpc_boardinfo *board = dev->board_ptr; + int err = 0; + int tmp, tmp2; + unsigned int stop_mask; + enum scan_mode mode; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + + stop_mask = TRIG_COUNT | TRIG_NONE; + if (board->is_labpc1200) + stop_mask |= TRIG_EXT; + err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_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++; + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* start_arg value is ignored */ + break; + } + + if (!cmd->chanlist_len) + err |= -EINVAL; + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ai_speed); + + /* make sure scan timing is not too fast */ + if (cmd->scan_begin_src == TRIG_TIMER) { + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + cmd->convert_arg * cmd->chanlist_len); + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + board->ai_speed * cmd->chanlist_len); + } + + switch (cmd->stop_src) { + case TRIG_COUNT: + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + break; + case TRIG_NONE: + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + break; + /* + * 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 */ + + tmp = cmd->convert_arg; + tmp2 = cmd->scan_begin_arg; + mode = labpc_ai_scan_mode(cmd); + labpc_adc_timing(dev, cmd, mode); + if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg) + err++; + + if (err) + return 4; + + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= labpc_ai_check_chanlist(dev, s, cmd); + + if (err) + return 5; + + return 0; +} + +static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +{ + const struct labpc_boardinfo *board = dev->board_ptr; + struct labpc_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + enum scan_mode mode = labpc_ai_scan_mode(cmd); + unsigned int chanspec = (mode == MODE_MULT_CHAN_UP) ? + cmd->chanlist[cmd->chanlist_len - 1] : + cmd->chanlist[0]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + enum transfer_type xfer; + unsigned long flags; + + /* make sure board is disabled before setting up acquisition */ + labpc_cancel(dev, s); + + /* initialize software conversion count */ + if (cmd->stop_src == TRIG_COUNT) + devpriv->count = cmd->stop_arg * cmd->chanlist_len; + + /* setup hardware conversion counter */ + if (cmd->stop_src == TRIG_EXT) { + /* + * load counter a1 with count of 3 + * (pc+ manual says this is minimum allowed) using mode 0 + */ + labpc_counter_load(dev, COUNTER_A_BASE_REG, + 1, 3, I8254_MODE0); + } else { + /* just put counter a1 in mode 0 to set its output low */ + labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 1, I8254_MODE0); + } + + /* figure out what method we will use to transfer data */ + if (labpc_have_dma_chan(dev) && + /* dma unsafe at RT priority, + * and too much setup time for CMDF_WAKE_EOS */ + (cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY)) == 0) + xfer = isa_dma_transfer; + else if (/* pc-plus has no fifo-half full interrupt */ + board->is_labpc1200 && + /* wake-end-of-scan should interrupt on fifo not empty */ + (cmd->flags & CMDF_WAKE_EOS) == 0 && + /* make sure we are taking more than just a few points */ + (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) + xfer = fifo_half_full_transfer; + else + xfer = fifo_not_empty_transfer; + devpriv->current_transfer = xfer; + + labpc_ai_set_chan_and_gain(dev, mode, chan, range, aref); + + labpc_setup_cmd6_reg(dev, s, mode, xfer, range, aref, + (cmd->stop_src == TRIG_EXT)); + + /* manual says to set scan enable bit on second pass */ + if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) { + devpriv->cmd1 |= CMD1_SCANEN; + /* need a brief delay before enabling scan, or scan + * list will get screwed when you switch + * between scan up to scan down mode - dunno why */ + udelay(1); + devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG); + } + + devpriv->write_byte(dev, cmd->chanlist_len, INTERVAL_COUNT_REG); + /* load count */ + devpriv->write_byte(dev, 0x1, INTERVAL_STROBE_REG); + + if (cmd->convert_src == TRIG_TIMER || + cmd->scan_begin_src == TRIG_TIMER) { + /* set up pacing */ + labpc_adc_timing(dev, cmd, mode); + /* load counter b0 in mode 3 */ + labpc_counter_load(dev, COUNTER_B_BASE_REG, + 0, devpriv->divisor_b0, I8254_MODE3); + } + /* set up conversion pacing */ + if (labpc_ai_convert_period(cmd, mode)) { + /* load counter a0 in mode 2 */ + labpc_counter_load(dev, COUNTER_A_BASE_REG, + 0, devpriv->divisor_a0, I8254_MODE2); + } else { + /* initialize pacer counter to prevent any problems */ + labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2); + } + + /* set up scan pacing */ + if (labpc_ai_scan_period(cmd, mode)) { + /* load counter b1 in mode 2 */ + labpc_counter_load(dev, COUNTER_B_BASE_REG, + 1, devpriv->divisor_b1, I8254_MODE2); + } + + labpc_clear_adc_fifo(dev); + + if (xfer == isa_dma_transfer) + labpc_setup_dma(dev, s); + + /* enable error interrupts */ + devpriv->cmd3 |= CMD3_ERRINTEN; + /* enable fifo not empty interrupt? */ + if (xfer == fifo_not_empty_transfer) + devpriv->cmd3 |= CMD3_FIFOINTEN; + devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG); + + /* setup any external triggering/pacing (cmd4 register) */ + devpriv->cmd4 = 0; + if (cmd->convert_src != TRIG_EXT) + devpriv->cmd4 |= CMD4_ECLKRCV; + /* XXX should discard first scan when using interval scanning + * since manual says it is not synced with scan clock */ + if (!labpc_use_continuous_mode(cmd, mode)) { + devpriv->cmd4 |= CMD4_INTSCAN; + if (cmd->scan_begin_src == TRIG_EXT) + devpriv->cmd4 |= CMD4_EOIRCV; + } + /* single-ended/differential */ + if (aref == AREF_DIFF) + devpriv->cmd4 |= CMD4_SEDIFF; + devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG); + + /* startup acquisition */ + + spin_lock_irqsave(&dev->spinlock, flags); + + /* use 2 cascaded counters for pacing */ + devpriv->cmd2 |= CMD2_TBSEL; + + devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG); + if (cmd->start_src == TRIG_EXT) + devpriv->cmd2 |= CMD2_HWTRIG; + else + devpriv->cmd2 |= CMD2_SWTRIG; + if (cmd->stop_src == TRIG_EXT) + devpriv->cmd2 |= (CMD2_HWTRIG | CMD2_PRETRIG); + + devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); + + spin_unlock_irqrestore(&dev->spinlock, flags); + + return 0; +} + +/* read all available samples from ai fifo */ +static int labpc_drain_fifo(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + struct comedi_async *async = dev->read_subdev->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned short data; + const int timeout = 10000; + unsigned int i; + + devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); + + for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout; + i++) { + /* quit if we have all the data we want */ + if (cmd->stop_src == TRIG_COUNT) { + if (devpriv->count == 0) + break; + devpriv->count--; + } + data = labpc_read_adc_fifo(dev); + cfc_write_to_buffer(dev->read_subdev, data); + devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); + } + if (i == timeout) { + dev_err(dev->class_dev, "ai timeout, fifo never empties\n"); + async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + return -1; + } + + return 0; +} + +/* makes sure all data acquired by board is transferred to comedi (used + * when acquisition is terminated by stop_src == TRIG_EXT). */ +static void labpc_drain_dregs(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + if (devpriv->current_transfer == isa_dma_transfer) + labpc_drain_dma(dev); + + labpc_drain_fifo(dev); +} + +/* interrupt service routine */ +static irqreturn_t labpc_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + const struct labpc_boardinfo *board = dev->board_ptr; + struct labpc_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async; + struct comedi_cmd *cmd; + + if (!dev->attached) { + dev_err(dev->class_dev, "premature interrupt\n"); + return IRQ_HANDLED; + } + + async = s->async; + cmd = &async->cmd; + + /* read board status */ + devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG); + if (board->is_labpc1200) + devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG); + + if ((devpriv->stat1 & (STAT1_GATA0 | STAT1_CNTINT | STAT1_OVERFLOW | + STAT1_OVERRUN | STAT1_DAVAIL)) == 0 && + (devpriv->stat2 & STAT2_OUTA1) == 0 && + (devpriv->stat2 & STAT2_FIFONHF)) { + return IRQ_NONE; + } + + if (devpriv->stat1 & STAT1_OVERRUN) { + /* clear error interrupt */ + devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); + async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); + dev_err(dev->class_dev, "overrun\n"); + return IRQ_HANDLED; + } + + if (devpriv->current_transfer == isa_dma_transfer) + labpc_handle_dma_status(dev); + else + labpc_drain_fifo(dev); + + if (devpriv->stat1 & STAT1_CNTINT) { + dev_err(dev->class_dev, "handled timer interrupt?\n"); + /* clear it */ + devpriv->write_byte(dev, 0x1, TIMER_CLEAR_REG); + } + + if (devpriv->stat1 & STAT1_OVERFLOW) { + /* clear error interrupt */ + devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG); + async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); + dev_err(dev->class_dev, "overflow\n"); + return IRQ_HANDLED; + } + /* handle external stop trigger */ + if (cmd->stop_src == TRIG_EXT) { + if (devpriv->stat2 & STAT2_OUTA1) { + labpc_drain_dregs(dev); + async->events |= COMEDI_CB_EOA; + } + } + + /* TRIG_COUNT end of acquisition */ + if (cmd->stop_src == TRIG_COUNT) { + if (devpriv->count == 0) + async->events |= COMEDI_CB_EOA; + } + + cfc_handle_events(dev, s); + return IRQ_HANDLED; +} + +static int labpc_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + const struct labpc_boardinfo *board = dev->board_ptr; + struct labpc_private *devpriv = dev->private; + int channel, range; + unsigned long flags; + int lsb, msb; + + channel = CR_CHAN(insn->chanspec); + + /* turn off pacing of analog output channel */ + /* note: hardware bug in daqcard-1200 means pacing cannot + * be independently enabled/disabled for its the two channels */ + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->cmd2 &= ~CMD2_LDAC(channel); + devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* set range */ + if (board->is_labpc1200) { + range = CR_RANGE(insn->chanspec); + if (comedi_range_is_unipolar(s, range)) + devpriv->cmd6 |= CMD6_DACUNI(channel); + else + devpriv->cmd6 &= ~CMD6_DACUNI(channel); + /* write to register */ + devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG); + } + /* send data */ + lsb = data[0] & 0xff; + msb = (data[0] >> 8) & 0xff; + devpriv->write_byte(dev, lsb, DAC_LSB_REG(channel)); + devpriv->write_byte(dev, msb, DAC_MSB_REG(channel)); + + /* remember value for readback */ + devpriv->ao_value[channel] = data[0]; + + return 1; +} + +static int labpc_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct labpc_private *devpriv = dev->private; + + data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; + + return 1; +} + +/* lowlevel write to eeprom/dac */ +static void labpc_serial_out(struct comedi_device *dev, unsigned int value, + unsigned int value_width) +{ + struct labpc_private *devpriv = dev->private; + int i; + + for (i = 1; i <= value_width; i++) { + /* clear serial clock */ + devpriv->cmd5 &= ~CMD5_SCLK; + /* send bits most significant bit first */ + if (value & (1 << (value_width - i))) + devpriv->cmd5 |= CMD5_SDATA; + else + devpriv->cmd5 &= ~CMD5_SDATA; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + /* set clock to load bit */ + devpriv->cmd5 |= CMD5_SCLK; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + } +} + +/* lowlevel read from eeprom */ +static unsigned int labpc_serial_in(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + unsigned int value = 0; + int i; + const int value_width = 8; /* number of bits wide values are */ + + for (i = 1; i <= value_width; i++) { + /* set serial clock */ + devpriv->cmd5 |= CMD5_SCLK; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + /* clear clock bit */ + devpriv->cmd5 &= ~CMD5_SCLK; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + /* read bits most significant bit first */ + udelay(1); + devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG); + if (devpriv->stat2 & STAT2_PROMOUT) + value |= 1 << (value_width - i); + } + + return value; +} + +static unsigned int labpc_eeprom_read(struct comedi_device *dev, + unsigned int address) +{ + struct labpc_private *devpriv = dev->private; + unsigned int value; + /* bits to tell eeprom to expect a read */ + const int read_instruction = 0x3; + /* 8 bit write lengths to eeprom */ + const int write_length = 8; + + /* enable read/write to eeprom */ + devpriv->cmd5 &= ~CMD5_EEPROMCS; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + /* send read instruction */ + labpc_serial_out(dev, read_instruction, write_length); + /* send 8 bit address to read from */ + labpc_serial_out(dev, address, write_length); + /* read result */ + value = labpc_serial_in(dev); + + /* disable read/write to eeprom */ + devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + return value; +} + +static unsigned int labpc_eeprom_read_status(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + unsigned int value; + const int read_status_instruction = 0x5; + const int write_length = 8; /* 8 bit write lengths to eeprom */ + + /* enable read/write to eeprom */ + devpriv->cmd5 &= ~CMD5_EEPROMCS; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + /* send read status instruction */ + labpc_serial_out(dev, read_status_instruction, write_length); + /* read result */ + value = labpc_serial_in(dev); + + /* disable read/write to eeprom */ + devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + return value; +} + +static int labpc_eeprom_write(struct comedi_device *dev, + unsigned int address, unsigned int value) +{ + struct labpc_private *devpriv = dev->private; + const int write_enable_instruction = 0x6; + const int write_instruction = 0x2; + const int write_length = 8; /* 8 bit write lengths to eeprom */ + const int write_in_progress_bit = 0x1; + const int timeout = 10000; + int i; + + /* make sure there isn't already a write in progress */ + for (i = 0; i < timeout; i++) { + if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) == + 0) + break; + } + if (i == timeout) { + dev_err(dev->class_dev, "eeprom write timed out\n"); + return -ETIME; + } + /* update software copy of eeprom */ + devpriv->eeprom_data[address] = value; + + /* enable read/write to eeprom */ + devpriv->cmd5 &= ~CMD5_EEPROMCS; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + /* send write_enable instruction */ + labpc_serial_out(dev, write_enable_instruction, write_length); + devpriv->cmd5 &= ~CMD5_EEPROMCS; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + /* send write instruction */ + devpriv->cmd5 |= CMD5_EEPROMCS; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + labpc_serial_out(dev, write_instruction, write_length); + /* send 8 bit address to write to */ + labpc_serial_out(dev, address, write_length); + /* write value */ + labpc_serial_out(dev, value, write_length); + devpriv->cmd5 &= ~CMD5_EEPROMCS; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + /* disable read/write to eeprom */ + devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + return 0; +} + +/* writes to 8 bit calibration dacs */ +static void write_caldac(struct comedi_device *dev, unsigned int channel, + unsigned int value) +{ + struct labpc_private *devpriv = dev->private; + + if (value == devpriv->caldac[channel]) + return; + devpriv->caldac[channel] = value; + + /* clear caldac load bit and make sure we don't write to eeprom */ + devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + + /* write 4 bit channel */ + labpc_serial_out(dev, channel, 4); + /* write 8 bit caldac value */ + labpc_serial_out(dev, value, 8); + + /* set and clear caldac bit to load caldac value */ + devpriv->cmd5 |= CMD5_CALDACLD; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + devpriv->cmd5 &= ~CMD5_CALDACLD; + udelay(1); + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); +} + +static int labpc_calib_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + + /* + * Only write the last data value to the caldac. Preceding + * data would be overwritten anyway. + */ + if (insn->n > 0) + write_caldac(dev, chan, data[insn->n - 1]); + + return insn->n; +} + +static int labpc_calib_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct labpc_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->caldac[chan]; + + return insn->n; +} + +static int labpc_eeprom_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; + + /* only allow writes to user area of eeprom */ + if (chan < 16 || chan > 127) + return -EINVAL; + + /* + * Only write the last data value to the eeprom. Preceding + * data would be overwritten anyway. + */ + if (insn->n > 0) { + ret = labpc_eeprom_write(dev, chan, data[insn->n - 1]); + if (ret) + return ret; + } + + return insn->n; +} + +static int labpc_eeprom_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct labpc_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->eeprom_data[chan]; + + return insn->n; +} + +int labpc_common_attach(struct comedi_device *dev, + unsigned int irq, unsigned long isr_flags) +{ + const struct labpc_boardinfo *board = dev->board_ptr; + struct labpc_private *devpriv = dev->private; + struct comedi_subdevice *s; + int ret; + int i; + + if (dev->mmio) { + devpriv->read_byte = labpc_readb; + devpriv->write_byte = labpc_writeb; + } else { + devpriv->read_byte = labpc_inb; + devpriv->write_byte = labpc_outb; + } + + /* initialize board's command registers */ + devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG); + devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG); + devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG); + devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG); + if (board->is_labpc1200) { + devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG); + devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG); + } + + if (irq) { + ret = request_irq(irq, labpc_interrupt, isr_flags, + dev->board_name, dev); + if (ret == 0) + dev->irq = irq; + } + + ret = comedi_alloc_subdevices(dev, 5); + if (ret) + return ret; + + /* analog input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF; + s->n_chan = 8; + s->len_chanlist = 8; + s->maxdata = 0x0fff; + s->range_table = board->is_labpc1200 ? + &range_labpc_1200_ai : &range_labpc_plus_ai; + s->insn_read = labpc_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->do_cmd = labpc_ai_cmd; + s->do_cmdtest = labpc_ai_cmdtest; + s->cancel = labpc_cancel; + } + + /* analog output */ + s = &dev->subdevices[1]; + if (board->has_ao) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; + s->n_chan = NUM_AO_CHAN; + s->maxdata = 0x0fff; + s->range_table = &range_labpc_ao; + s->insn_read = labpc_ao_insn_read; + s->insn_write = labpc_ao_insn_write; + + /* initialize analog outputs to a known value */ + for (i = 0; i < s->n_chan; i++) { + short lsb, msb; + + devpriv->ao_value[i] = s->maxdata / 2; + lsb = devpriv->ao_value[i] & 0xff; + msb = (devpriv->ao_value[i] >> 8) & 0xff; + devpriv->write_byte(dev, lsb, DAC_LSB_REG(i)); + devpriv->write_byte(dev, msb, DAC_MSB_REG(i)); + } + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* 8255 dio */ + s = &dev->subdevices[2]; + if (dev->mmio) + ret = subdev_8255_mm_init(dev, s, NULL, DIO_BASE_REG); + else + ret = subdev_8255_init(dev, s, NULL, DIO_BASE_REG); + if (ret) + return ret; + + /* calibration subdevices for boards that have one */ + s = &dev->subdevices[3]; + if (board->is_labpc1200) { + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 16; + s->maxdata = 0xff; + s->insn_read = labpc_calib_insn_read; + s->insn_write = labpc_calib_insn_write; + + for (i = 0; i < s->n_chan; i++) + write_caldac(dev, i, s->maxdata / 2); + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* EEPROM */ + s = &dev->subdevices[4]; + if (board->is_labpc1200) { + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = EEPROM_SIZE; + s->maxdata = 0xff; + s->insn_read = labpc_eeprom_insn_read; + s->insn_write = labpc_eeprom_insn_write; + + for (i = 0; i < s->n_chan; i++) + devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + return 0; +} +EXPORT_SYMBOL_GPL(labpc_common_attach); + +static int __init labpc_common_init(void) +{ + return 0; +} +module_init(labpc_common_init); + +static void __exit labpc_common_exit(void) +{ +} +module_exit(labpc_common_exit); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi helper for ni_labpc, ni_labpc_pci, ni_labpc_cs"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c index cb7d1c952cf2..967202e0635e 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c @@ -152,7 +152,7 @@ static void handle_isa_dma(struct comedi_device *dev) void labpc_handle_dma_status(struct comedi_device *dev) { - const struct labpc_boardinfo *board = comedi_board(dev); + const struct labpc_boardinfo *board = dev->board_ptr; struct labpc_private *devpriv = dev->private; /* diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c index 65984ea0a3ee..3fc420406564 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_pci.c +++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c @@ -108,20 +108,11 @@ static int labpc_pci_auto_attach(struct comedi_device *dev, return labpc_common_attach(dev, pcidev->irq, IRQF_SHARED); } -static void labpc_pci_detach(struct comedi_device *dev) -{ - if (dev->mmio) - iounmap(dev->mmio); - if (dev->irq) - free_irq(dev->irq, dev); - comedi_pci_disable(dev); -} - static struct comedi_driver labpc_pci_comedi_driver = { .driver_name = "labpc_pci", .module = THIS_MODULE, .auto_attach = labpc_pci_auto_attach, - .detach = labpc_pci_detach, + .detach = comedi_pci_detach, }; static const struct pci_device_id labpc_pci_table[] = { diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 297c95d2e0a3..320b080149b6 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1186,7 +1186,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev, static int ni_ao_fifo_half_empty(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; int n; n = comedi_buf_read_n_available(s); @@ -1209,7 +1209,7 @@ static int ni_ao_fifo_half_empty(struct comedi_device *dev, static int ni_ao_prep_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; int n; @@ -1296,7 +1296,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev, static void ni_handle_fifo_half_full(struct comedi_device *dev) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct comedi_subdevice *s = dev->read_subdev; int n; @@ -1881,7 +1881,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev, unsigned int n_chan, unsigned int *list) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; unsigned int chan, range, aref; unsigned int i; @@ -1988,7 +1988,7 @@ static void ni_load_channelgain_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int n_chan, unsigned int *list) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; unsigned int offset = (s->maxdata + 1) >> 1; unsigned int chan, range, aref; @@ -2108,7 +2108,7 @@ static int ni_ai_insn_read(struct comedi_device *dev, unsigned int mask = (s->maxdata + 1) >> 1; int i, n; unsigned signbits; - unsigned short d; + unsigned int d; unsigned long dl; ni_load_channelgain_list(dev, s, 1, &insn->chanspec); @@ -2206,15 +2206,15 @@ static int ni_ns_to_timer(const struct comedi_device *dev, unsigned nanosec, struct ni_private *devpriv = dev->private; int divider; - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: divider = (nanosec + devpriv->clock_ns / 2) / devpriv->clock_ns; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: divider = (nanosec) / devpriv->clock_ns; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: divider = (nanosec + devpriv->clock_ns - 1) / devpriv->clock_ns; break; } @@ -2231,7 +2231,7 @@ static unsigned ni_timer_to_ns(const struct comedi_device *dev, int timer) static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev, unsigned num_channels) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; /* simultaneously-sampled inputs */ @@ -2245,7 +2245,7 @@ static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev, static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; int err = 0; unsigned int tmp; @@ -2541,7 +2541,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* load SI */ timer = ni_ns_to_timer(dev, cmd->scan_begin_arg, - TRIG_ROUND_NEAREST); + CMDF_ROUND_NEAREST); ni_stc_writel(dev, timer, AI_SI_Load_A_Registers); ni_stc_writew(dev, AI_SI_Load, AI_Command_1_Register); break; @@ -2569,7 +2569,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) timer = 1; else timer = ni_ns_to_timer(dev, cmd->convert_arg, - TRIG_ROUND_NEAREST); + CMDF_ROUND_NEAREST); /* 0,0 does not work */ ni_stc_writew(dev, 1, AI_SI2_Load_A_Register); ni_stc_writew(dev, timer, AI_SI2_Load_B_Register); @@ -2610,7 +2610,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) interrupt_a_enable |= AI_FIFO_Interrupt_Enable; #endif - if (cmd->flags & TRIG_WAKE_EOS + if (cmd->flags & CMDF_WAKE_EOS || (devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) { /* wake on end-of-scan */ devpriv->aimode = AIMODE_SCAN; @@ -2732,9 +2732,6 @@ static int ni_ai_insn_config(struct comedi_device *dev, calib_source = data[1] & 0xf; - if (calib_source > 0xF) - return -EINVAL; - devpriv->ai_calib_source = calib_source; ni_writew(dev, calib_source, Calibration_Channel_6143); } else { @@ -2921,21 +2918,6 @@ static int ni_ao_config_chanlist(struct comedi_device *dev, return ni_old_ao_config_chanlist(dev, s, chanspec, n_chans); } -static int ni_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct ni_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao[chan]; - - return insn->n; -} - static int ni_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -2962,7 +2944,7 @@ static int ni_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { unsigned int val = data[i]; - devpriv->ao[chan] = val; + s->readback[chan] = val; if (devpriv->is_6xxx) { /* @@ -2997,7 +2979,7 @@ static int ni_ao_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; switch (data[0]) { @@ -3098,7 +3080,7 @@ static int ni_ao_inttrig(struct comedi_device *dev, static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; const struct comedi_cmd *cmd = &s->async->cmd; int bits; @@ -3208,7 +3190,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ao_cmd2 &= ~AO_BC_Gate_Enable; trigvar = ni_ns_to_timer(dev, cmd->scan_begin_arg, - TRIG_ROUND_NEAREST); + CMDF_ROUND_NEAREST); ni_stc_writel(dev, 1, AO_UI_Load_A_Register); ni_stc_writew(dev, AO_UI_Load, AO_Command_1_Register); ni_stc_writel(dev, trigvar, AO_UI_Load_A_Register); @@ -3299,7 +3281,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; int err = 0; unsigned int tmp; @@ -3552,12 +3534,10 @@ static int ni_cdio_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: fix up any arguments */ - - if (err) - return 4; + /* Step 4: fix up any arguments */ /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) err |= ni_cdio_check_chanlist(dev, s, cmd); @@ -4176,16 +4156,15 @@ static int ni_freq_out_insn_config(struct comedi_device *dev, return insn->n; } -static int ni_8255_callback(int dir, int port, int data, unsigned long arg) +static int ni_8255_callback(struct comedi_device *dev, + int dir, int port, int data, unsigned long iobase) { - struct comedi_device *dev = (struct comedi_device *)arg; - if (dir) { - ni_writeb(dev, data, Port_A + 2 * port); + ni_writeb(dev, data, iobase + 2 * port); return 0; } - return ni_readb(dev, Port_A + 2 * port); + return ni_readb(dev, iobase + 2 * port); } static int ni_get_pwm_config(struct comedi_device *dev, unsigned int *data) @@ -4208,15 +4187,15 @@ static int ni_m_series_pwm_config(struct comedi_device *dev, switch (data[0]) { case INSN_CONFIG_PWM_OUTPUT: switch (data[1]) { - case TRIG_ROUND_NEAREST: + case CMDF_ROUND_NEAREST: up_count = (data[2] + devpriv->clock_ns / 2) / devpriv->clock_ns; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: up_count = data[2] / devpriv->clock_ns; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: up_count = (data[2] + devpriv->clock_ns - 1) / devpriv->clock_ns; @@ -4225,15 +4204,15 @@ static int ni_m_series_pwm_config(struct comedi_device *dev, return -EINVAL; } switch (data[3]) { - case TRIG_ROUND_NEAREST: + case CMDF_ROUND_NEAREST: down_count = (data[4] + devpriv->clock_ns / 2) / devpriv->clock_ns; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: down_count = data[4] / devpriv->clock_ns; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: down_count = (data[4] + devpriv->clock_ns - 1) / devpriv->clock_ns; @@ -4272,15 +4251,15 @@ static int ni_6143_pwm_config(struct comedi_device *dev, switch (data[0]) { case INSN_CONFIG_PWM_OUTPUT: switch (data[1]) { - case TRIG_ROUND_NEAREST: + case CMDF_ROUND_NEAREST: up_count = (data[2] + devpriv->clock_ns / 2) / devpriv->clock_ns; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: up_count = data[2] / devpriv->clock_ns; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: up_count = (data[2] + devpriv->clock_ns - 1) / devpriv->clock_ns; @@ -4289,15 +4268,15 @@ static int ni_6143_pwm_config(struct comedi_device *dev, return -EINVAL; } switch (data[3]) { - case TRIG_ROUND_NEAREST: + case CMDF_ROUND_NEAREST: down_count = (data[4] + devpriv->clock_ns / 2) / devpriv->clock_ns; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: down_count = data[4] / devpriv->clock_ns; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: down_count = (data[4] + devpriv->clock_ns - 1) / devpriv->clock_ns; @@ -4390,7 +4369,7 @@ static struct caldac_struct caldacs[] = { static void ni_write_caldac(struct comedi_device *dev, int addr, int val) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; unsigned int loadbit = 0, bits = 0, bit, bitstring = 0; int i; @@ -4448,7 +4427,7 @@ static int ni_calib_insn_read(struct comedi_device *dev, static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; int i, j; int n_dacs; @@ -5418,7 +5397,7 @@ static int ni_alloc_private(struct comedi_device *dev) static int ni_E_init(struct comedi_device *dev, unsigned interrupt_pin, unsigned irq_polarity) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; struct comedi_subdevice *s; int ret; @@ -5491,9 +5470,13 @@ static int ni_E_init(struct comedi_device *dev, s->n_chan = board->n_aochan; s->maxdata = board->ao_maxdata; s->range_table = board->ao_range_table; - s->insn_read = ni_ao_insn_read; - s->insn_write = ni_ao_insn_write; s->insn_config = ni_ao_insn_config; + s->insn_write = ni_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; /* * Along with the IRQ we need either a FIFO or DMA for @@ -5560,8 +5543,7 @@ static int ni_E_init(struct comedi_device *dev, /* 8255 device */ s = &dev->subdevices[NI_8255_DIO_SUBDEV]; if (board->has_8255) { - ret = subdev_8255_init(dev, s, ni_8255_callback, - (unsigned long)dev); + ret = subdev_8255_init(dev, s, ni_8255_callback, Port_A); if (ret) return ret; } else { diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index b5b36af80205..5252cba82e5e 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -530,15 +530,15 @@ static int ni_pcidio_ns_to_timer(int *nanosec, unsigned int flags) base = TIMER_BASE; - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: divider = (*nanosec + base / 2) / base; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: divider = (*nanosec) / base; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: divider = (*nanosec + base - 1) / base; break; } @@ -598,11 +598,10 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* no limit */ - } else { /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -669,7 +668,7 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) writeb(3, dev->mmio + LinePolarities); writeb(0xc0, dev->mmio + AckSer); writel(ni_pcidio_ns_to_timer(&cmd->scan_begin_arg, - TRIG_ROUND_NEAREST), + CMDF_ROUND_NEAREST), dev->mmio + StartDelay); writeb(1, dev->mmio + ReqDelay); writeb(1, dev->mmio + ReqNotDelay); diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index da61fa70decf..3b2bdebbca59 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1082,7 +1082,7 @@ static void m_series_init_eeprom_buffer(struct comedi_device *dev) static void init_6143(struct comedi_device *dev) { - const struct ni_board_struct *board = comedi_board(dev); + const struct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; /* Disable interrupts */ diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index a2841292ddd4..29efce30eb7f 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -1423,7 +1423,6 @@ struct ni_private { unsigned int changain_spec; unsigned int caldac_maxdata_list[MAX_N_CALDACS]; - unsigned short ao[MAX_N_AO_CHAN]; unsigned short caldacs[MAX_N_CALDACS]; unsigned short ai_cmd2; diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 299ceddfb233..26e7291c4a51 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -185,7 +185,7 @@ static int ni_tio_cmd_setup(struct comedi_subdevice *s) } if (set_gate_source) retval = ni_tio_set_gate_src(counter, 0, gate_source); - if (cmd->flags & TRIG_WAKE_EOS) { + if (cmd->flags & CMDF_WAKE_EOS) { ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), GI_GATE_INTERRUPT_ENABLE(cidx), GI_GATE_INTERRUPT_ENABLE(cidx)); @@ -286,10 +286,9 @@ int ni_tio_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: fix up any arguments */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c new file mode 100644 index 000000000000..df7ada8611f4 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_usb6501.c @@ -0,0 +1,621 @@ +/* + * comedi/drivers/ni_usb6501.c + * Comedi driver for National Instruments USB-6501 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2014 Luca Ellero <luca.ellero@brickedbrain.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Driver: ni_usb6501 + * Description: National Instruments USB-6501 module + * Devices: [National Instruments] USB-6501 (ni_usb6501) + * Author: Luca Ellero <luca.ellero@brickedbrain.com> + * Updated: 8 Sep 2014 + * Status: works + * + * + * Configuration Options: + * none + */ + +/* + * NI-6501 - USB PROTOCOL DESCRIPTION + * + * Every command is composed by two USB packets: + * - request (out) + * - response (in) + * + * Every packet is at least 12 bytes long, here is the meaning of + * every field (all values are hex): + * + * byte 0 is always 00 + * byte 1 is always 01 + * byte 2 is always 00 + * byte 3 is the total packet length + * + * byte 4 is always 00 + * byte 5 is is the total packet length - 4 + * byte 6 is always 01 + * byte 7 is the command + * + * byte 8 is 02 (request) or 00 (response) + * byte 9 is 00 (response) or 10 (port request) or 20 (counter request) + * byte 10 is always 00 + * byte 11 is 00 (request) or 02 (response) + * + * PORT PACKETS + * + * CMD: 0xE READ_PORT + * REQ: 00 01 00 10 00 0C 01 0E 02 10 00 00 00 03 <PORT> 00 + * RES: 00 01 00 10 00 0C 01 00 00 00 00 02 00 03 <BMAP> 00 + * + * CMD: 0xF WRITE_PORT + * REQ: 00 01 00 14 00 10 01 0F 02 10 00 00 00 03 <PORT> 00 03 <BMAP> 00 00 + * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 + * + * CMD: 0x12 SET_PORT_DIR (0 = input, 1 = output) + * REQ: 00 01 00 18 00 14 01 12 02 10 00 00 + * 00 05 <PORT 0> <PORT 1> <PORT 2> 00 05 00 00 00 00 00 + * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 + * + * COUNTER PACKETS + * + * CMD 0x9: START_COUNTER + * REQ: 00 01 00 0C 00 08 01 09 02 20 00 00 + * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 + * + * CMD 0xC: STOP_COUNTER + * REQ: 00 01 00 0C 00 08 01 0C 02 20 00 00 + * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 + * + * CMD 0xE: READ_COUNTER + * REQ: 00 01 00 0C 00 08 01 0E 02 20 00 00 + * RES: 00 01 00 10 00 0C 01 00 00 00 00 02 <u32 counter value, Big Endian> + * + * CMD 0xF: WRITE_COUNTER + * REQ: 00 01 00 10 00 0C 01 0F 02 20 00 00 <u32 counter value, Big Endian> + * RES: 00 01 00 0C 00 08 01 00 00 00 00 02 + * + * + * Please visit http://www.brickedbrain.com if you need + * additional information or have any questions. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include "../comedidev.h" + +#define NI6501_TIMEOUT 1000 + +/* Port request packets */ +static const u8 READ_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x10, + 0x00, 0x0C, 0x01, 0x0E, + 0x02, 0x10, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00}; + +static const u8 WRITE_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x14, + 0x00, 0x10, 0x01, 0x0F, + 0x02, 0x10, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00}; + +static const u8 SET_PORT_DIR_REQUEST[] = {0x00, 0x01, 0x00, 0x18, + 0x00, 0x14, 0x01, 0x12, + 0x02, 0x10, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +/* Counter request packets */ +static const u8 START_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C, + 0x00, 0x08, 0x01, 0x09, + 0x02, 0x20, 0x00, 0x00}; + +static const u8 STOP_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C, + 0x00, 0x08, 0x01, 0x0C, + 0x02, 0x20, 0x00, 0x00}; + +static const u8 READ_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C, + 0x00, 0x08, 0x01, 0x0E, + 0x02, 0x20, 0x00, 0x00}; + +static const u8 WRITE_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x10, + 0x00, 0x0C, 0x01, 0x0F, + 0x02, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +/* Response packets */ +static const u8 GENERIC_RESPONSE[] = {0x00, 0x01, 0x00, 0x0C, + 0x00, 0x08, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x02}; + +static const u8 READ_PORT_RESPONSE[] = {0x00, 0x01, 0x00, 0x10, + 0x00, 0x0C, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x03, 0x00, 0x00}; + +static const u8 READ_COUNTER_RESPONSE[] = {0x00, 0x01, 0x00, 0x10, + 0x00, 0x0C, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00}; + +enum commands { + READ_PORT, + WRITE_PORT, + SET_PORT_DIR, + START_COUNTER, + STOP_COUNTER, + READ_COUNTER, + WRITE_COUNTER +}; + +struct ni6501_private { + struct usb_endpoint_descriptor *ep_rx; + struct usb_endpoint_descriptor *ep_tx; + struct semaphore sem; + u8 *usb_rx_buf; + u8 *usb_tx_buf; +}; + +static int ni6501_port_command(struct comedi_device *dev, int command, + const u8 *port, u8 *bitmap) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct ni6501_private *devpriv = dev->private; + int request_size, response_size; + u8 *tx = devpriv->usb_tx_buf; + int ret; + + if (command != SET_PORT_DIR && !bitmap) + return -EINVAL; + + down(&devpriv->sem); + + switch (command) { + case READ_PORT: + request_size = sizeof(READ_PORT_REQUEST); + response_size = sizeof(READ_PORT_RESPONSE); + memcpy(tx, READ_PORT_REQUEST, request_size); + tx[14] = port[0]; + break; + case WRITE_PORT: + request_size = sizeof(WRITE_PORT_REQUEST); + response_size = sizeof(GENERIC_RESPONSE); + memcpy(tx, WRITE_PORT_REQUEST, request_size); + tx[14] = port[0]; + tx[17] = bitmap[0]; + break; + case SET_PORT_DIR: + request_size = sizeof(SET_PORT_DIR_REQUEST); + response_size = sizeof(GENERIC_RESPONSE); + memcpy(tx, SET_PORT_DIR_REQUEST, request_size); + tx[14] = port[0]; + tx[15] = port[1]; + tx[16] = port[2]; + break; + default: + ret = -EINVAL; + goto end; + } + + ret = usb_bulk_msg(usb, + usb_sndbulkpipe(usb, + devpriv->ep_tx->bEndpointAddress), + devpriv->usb_tx_buf, + request_size, + NULL, + NI6501_TIMEOUT); + if (ret) + goto end; + + ret = usb_bulk_msg(usb, + usb_rcvbulkpipe(usb, + devpriv->ep_rx->bEndpointAddress), + devpriv->usb_rx_buf, + response_size, + NULL, + NI6501_TIMEOUT); + if (ret) + goto end; + + /* Check if results are valid */ + + if (command == READ_PORT) { + bitmap[0] = devpriv->usb_rx_buf[14]; + /* mask bitmap for comparing */ + devpriv->usb_rx_buf[14] = 0x00; + + if (memcmp(devpriv->usb_rx_buf, READ_PORT_RESPONSE, + sizeof(READ_PORT_RESPONSE))) { + ret = -EINVAL; + } + } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE, + sizeof(GENERIC_RESPONSE))) { + ret = -EINVAL; + } +end: + up(&devpriv->sem); + + return ret; +} + +static int ni6501_counter_command(struct comedi_device *dev, int command, + u32 *val) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct ni6501_private *devpriv = dev->private; + int request_size, response_size; + u8 *tx = devpriv->usb_tx_buf; + int ret; + + if ((command == READ_COUNTER || command == WRITE_COUNTER) && !val) + return -EINVAL; + + down(&devpriv->sem); + + switch (command) { + case START_COUNTER: + request_size = sizeof(START_COUNTER_REQUEST); + response_size = sizeof(GENERIC_RESPONSE); + memcpy(tx, START_COUNTER_REQUEST, request_size); + break; + case STOP_COUNTER: + request_size = sizeof(STOP_COUNTER_REQUEST); + response_size = sizeof(GENERIC_RESPONSE); + memcpy(tx, STOP_COUNTER_REQUEST, request_size); + break; + case READ_COUNTER: + request_size = sizeof(READ_COUNTER_REQUEST); + response_size = sizeof(READ_COUNTER_RESPONSE); + memcpy(tx, READ_COUNTER_REQUEST, request_size); + break; + case WRITE_COUNTER: + request_size = sizeof(WRITE_COUNTER_REQUEST); + response_size = sizeof(GENERIC_RESPONSE); + memcpy(tx, WRITE_COUNTER_REQUEST, request_size); + /* Setup tx packet: bytes 12,13,14,15 hold the */ + /* u32 counter value (Big Endian) */ + *((__be32 *)&tx[12]) = cpu_to_be32(*val); + break; + default: + ret = -EINVAL; + goto end; + } + + ret = usb_bulk_msg(usb, + usb_sndbulkpipe(usb, + devpriv->ep_tx->bEndpointAddress), + devpriv->usb_tx_buf, + request_size, + NULL, + NI6501_TIMEOUT); + if (ret) + goto end; + + ret = usb_bulk_msg(usb, + usb_rcvbulkpipe(usb, + devpriv->ep_rx->bEndpointAddress), + devpriv->usb_rx_buf, + response_size, + NULL, + NI6501_TIMEOUT); + if (ret) + goto end; + + /* Check if results are valid */ + + if (command == READ_COUNTER) { + int i; + + /* Read counter value: bytes 12,13,14,15 of rx packet */ + /* hold the u32 counter value (Big Endian) */ + *val = be32_to_cpu(*((__be32 *)&devpriv->usb_rx_buf[12])); + + /* mask counter value for comparing */ + for (i = 12; i < sizeof(READ_COUNTER_RESPONSE); ++i) + devpriv->usb_rx_buf[i] = 0x00; + + if (memcmp(devpriv->usb_rx_buf, READ_COUNTER_RESPONSE, + sizeof(READ_COUNTER_RESPONSE))) { + ret = -EINVAL; + } + } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE, + sizeof(GENERIC_RESPONSE))) { + ret = -EINVAL; + } +end: + up(&devpriv->sem); + + return ret; +} + +static int ni6501_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + u8 port[3]; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + + port[0] = (s->io_bits) & 0xff; + port[1] = (s->io_bits >> 8) & 0xff; + port[2] = (s->io_bits >> 16) & 0xff; + + ret = ni6501_port_command(dev, SET_PORT_DIR, port, NULL); + if (ret) + return ret; + + return insn->n; +} + +static int ni6501_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask; + int ret; + u8 port; + u8 bitmap; + + mask = comedi_dio_update_state(s, data); + + for (port = 0; port < 3; port++) { + if (mask & (0xFF << port * 8)) { + bitmap = (s->state >> port * 8) & 0xFF; + ret = ni6501_port_command(dev, WRITE_PORT, + &port, &bitmap); + if (ret) + return ret; + } + } + + data[1] = 0; + + for (port = 0; port < 3; port++) { + ret = ni6501_port_command(dev, READ_PORT, &port, &bitmap); + if (ret) + return ret; + data[1] |= bitmap << port * 8; + } + + return insn->n; +} + +static int ni6501_cnt_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + u32 val = 0; + + switch (data[0]) { + case INSN_CONFIG_ARM: + ret = ni6501_counter_command(dev, START_COUNTER, NULL); + break; + case INSN_CONFIG_DISARM: + ret = ni6501_counter_command(dev, STOP_COUNTER, NULL); + break; + case INSN_CONFIG_RESET: + ret = ni6501_counter_command(dev, STOP_COUNTER, NULL); + if (ret) + break; + ret = ni6501_counter_command(dev, WRITE_COUNTER, &val); + break; + default: + return -EINVAL; + } + + return ret ? ret : insn->n; +} + +static int ni6501_cnt_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + u32 val; + unsigned int i; + + for (i = 0; i < insn->n; i++) { + ret = ni6501_counter_command(dev, READ_COUNTER, &val); + if (ret) + return ret; + data[i] = val; + } + + return insn->n; +} + +static int ni6501_cnt_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + + if (insn->n) { + u32 val = data[insn->n - 1]; + + ret = ni6501_counter_command(dev, WRITE_COUNTER, &val); + if (ret) + return ret; + } + + return insn->n; +} + +static int ni6501_alloc_usb_buffers(struct comedi_device *dev) +{ + struct ni6501_private *devpriv = dev->private; + size_t size; + + size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize); + devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL); + if (!devpriv->usb_rx_buf) + return -ENOMEM; + + size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize); + devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL); + if (!devpriv->usb_tx_buf) { + kfree(devpriv->usb_rx_buf); + return -ENOMEM; + } + + return 0; +} + +static int ni6501_find_endpoints(struct comedi_device *dev) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct ni6501_private *devpriv = dev->private; + struct usb_host_interface *iface_desc = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_desc; + int i; + + if (iface_desc->desc.bNumEndpoints != 2) { + dev_err(dev->class_dev, "Wrong number of endpoints\n"); + return -ENODEV; + } + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + ep_desc = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep_desc)) { + if (!devpriv->ep_rx) + devpriv->ep_rx = ep_desc; + continue; + } + + if (usb_endpoint_is_bulk_out(ep_desc)) { + if (!devpriv->ep_tx) + devpriv->ep_tx = ep_desc; + continue; + } + } + + if (!devpriv->ep_rx || !devpriv->ep_tx) + return -ENODEV; + + return 0; +} + +static int ni6501_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct ni6501_private *devpriv; + struct comedi_subdevice *s; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = ni6501_find_endpoints(dev); + if (ret) + return ret; + + ret = ni6501_alloc_usb_buffers(dev); + if (ret) + return ret; + + sema_init(&devpriv->sem, 1); + usb_set_intfdata(intf, devpriv); + + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + /* Digital Input/Output subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ni6501_dio_insn_bits; + s->insn_config = ni6501_dio_insn_config; + + /* Counter subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL; + s->n_chan = 1; + s->maxdata = 0xffffffff; + s->insn_read = ni6501_cnt_insn_read; + s->insn_write = ni6501_cnt_insn_write; + s->insn_config = ni6501_cnt_insn_config; + + return 0; +} + +static void ni6501_detach(struct comedi_device *dev) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct ni6501_private *devpriv = dev->private; + + if (!devpriv) + return; + + down(&devpriv->sem); + + usb_set_intfdata(intf, NULL); + + kfree(devpriv->usb_rx_buf); + kfree(devpriv->usb_tx_buf); + + up(&devpriv->sem); +} + +static struct comedi_driver ni6501_driver = { + .module = THIS_MODULE, + .driver_name = "ni6501", + .auto_attach = ni6501_auto_attach, + .detach = ni6501_detach, +}; + +static int ni6501_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &ni6501_driver, id->driver_info); +} + +static const struct usb_device_id ni6501_usb_table[] = { + { USB_DEVICE(0x3923, 0x718a) }, + { } +}; +MODULE_DEVICE_TABLE(usb, ni6501_usb_table); + +static struct usb_driver ni6501_usb_driver = { + .name = "ni6501", + .id_table = ni6501_usb_table, + .probe = ni6501_usb_probe, + .disconnect = comedi_usb_auto_unconfig, +}; +module_comedi_usb_driver(ni6501_driver, ni6501_usb_driver); + +MODULE_AUTHOR("Luca Ellero"); +MODULE_DESCRIPTION("Comedi driver for National Instruments USB-6501"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index 40f9136f0bb6..47f4887108a7 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -157,7 +157,6 @@ static const struct pcl711_board boardtypes[] = { struct pcl711_private { unsigned int ntrig; - unsigned int ao_readback[2]; unsigned int divisor1; unsigned int divisor2; }; @@ -335,7 +334,9 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -377,15 +378,8 @@ static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) pcl711_set_changain(dev, s, cmd->chanlist[0]); - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg == 0) { - /* an empty acquisition */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return 0; - } + if (cmd->stop_src == TRIG_COUNT) devpriv->ntrig = cmd->stop_arg; - } if (cmd->scan_begin_src == TRIG_TIMER) { pcl711_ai_load_counters(dev); @@ -410,31 +404,15 @@ static int pcl711_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct pcl711_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val = devpriv->ao_readback[chan]; + unsigned int val = s->readback[chan]; int i; for (i = 0; i < insn->n; i++) { val = data[i]; pcl711_ao_write(dev, chan, val); } - devpriv->ao_readback[chan] = val; - - return insn->n; -} - -static int pcl711_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct pcl711_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + s->readback[chan] = val; return insn->n; } @@ -476,7 +454,7 @@ static int pcl711_do_insn_bits(struct comedi_device *dev, static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcl711_board *board = comedi_board(dev); + const struct pcl711_board *board = dev->board_ptr; struct pcl711_private *devpriv; struct comedi_subdevice *s; int ret; @@ -527,7 +505,11 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xfff; s->range_table = &range_bipolar5; s->insn_write = pcl711_ao_insn_write; - s->insn_read = pcl711_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; /* Digital Input subdevice */ s = &dev->subdevices[2]; diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c index c7f8eb1cf8de..fcc440855e66 100644 --- a/drivers/staging/comedi/drivers/pcl724.c +++ b/drivers/staging/comedi/drivers/pcl724.c @@ -32,8 +32,6 @@ #include "8255.h" -#define SIZE_8255 4 - struct pcl724_board { const char *name; unsigned int io_range; @@ -81,10 +79,11 @@ static const struct pcl724_board boardtypes[] = { }, }; -static int pcl724_8255mapped_io(int dir, int port, int data, +static int pcl724_8255mapped_io(struct comedi_device *dev, + int dir, int port, int data, unsigned long iobase) { - int movport = SIZE_8255 * (iobase >> 12); + int movport = I8255_SIZE * (iobase >> 12); iobase &= 0x0fff; @@ -99,7 +98,7 @@ static int pcl724_8255mapped_io(int dir, int port, int data, static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcl724_board *board = comedi_board(dev); + const struct pcl724_board *board = dev->board_ptr; struct comedi_subdevice *s; unsigned long iobase; unsigned int iorange; @@ -132,8 +131,7 @@ static int pcl724_attach(struct comedi_device *dev, ret = subdev_8255_init(dev, s, pcl724_8255mapped_io, iobase); } else { - iobase = dev->iobase + (i * SIZE_8255); - ret = subdev_8255_init(dev, s, NULL, iobase); + ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); } if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index 74f6489bd124..dc179bd02dfd 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -156,7 +156,6 @@ static const struct pcl726_board pcl726_boards[] = { struct pcl726_private { const struct comedi_lrange *rangelist[12]; - unsigned int ao_readback[12]; unsigned int cmd_running:1; }; @@ -189,9 +188,6 @@ static int pcl726_intr_cmdtest(struct comedi_device *dev, /* Step 2a : make sure trigger sources are unique */ /* Step 2b : and mutually compatible */ - if (err) - return 2; - /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); @@ -203,10 +199,9 @@ static int pcl726_intr_cmdtest(struct comedi_device *dev, if (err) return 3; - /* step 4: ignored */ + /* Step 4: fix up any arguments */ - if (err) - return 4; + /* Step 5: check channel list if it exists */ return 0; } @@ -253,15 +248,14 @@ static int pcl726_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct pcl726_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val; int i; for (i = 0; i < insn->n; i++) { - val = data[i]; - devpriv->ao_readback[chan] = val; + unsigned int val = data[i]; + + s->readback[chan] = val; /* bipolar data to the DAC is two's complement */ if (comedi_chan_range_is_bipolar(s, chan, range)) @@ -275,27 +269,12 @@ static int pcl726_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int pcl726_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct pcl726_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; -} - static int pcl726_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - const struct pcl726_board *board = comedi_board(dev); + const struct pcl726_board *board = dev->board_ptr; unsigned int val; if (board->is_pcl727) { @@ -316,7 +295,7 @@ static int pcl726_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - const struct pcl726_board *board = comedi_board(dev); + const struct pcl726_board *board = dev->board_ptr; unsigned long io = dev->iobase; unsigned int mask; @@ -343,7 +322,7 @@ static int pcl726_do_insn_bits(struct comedi_device *dev, static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcl726_board *board = comedi_board(dev); + const struct pcl726_board *board = dev->board_ptr; struct pcl726_private *devpriv; struct comedi_subdevice *s; int subdev; @@ -398,7 +377,11 @@ static int pcl726_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table_list = devpriv->rangelist; s->insn_write = pcl726_ao_insn_write; - s->insn_read = pcl726_ao_insn_read; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; if (board->have_dio) { /* Digital Input subdevice */ diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index bdce24c42940..a6c5770b2808 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -270,7 +270,7 @@ static int pcl730_di_insn_bits(struct comedi_device *dev, static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcl730_board *board = comedi_board(dev); + const struct pcl730_board *board = dev->board_ptr; struct comedi_subdevice *s; int subdev; int ret; diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 803e7790538c..fd5ea6e01619 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -522,7 +522,6 @@ struct pcl812_private { unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ - unsigned int ao_readback[2]; /* data for AO readback */ unsigned int divisor1; unsigned int divisor2; unsigned int use_diff:1; @@ -714,7 +713,7 @@ static int pcl812_ai_eoc(struct comedi_device *dev, static int pcl812_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcl812_board *board = comedi_board(dev); + const struct pcl812_board *board = dev->board_ptr; struct pcl812_private *devpriv = dev->private; int err = 0; unsigned int flags; @@ -813,7 +812,7 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->cur_chan = 0; /* don't we want wake up every scan? */ - if (cmd->flags & TRIG_WAKE_EOS) { + if (cmd->flags & CMDF_WAKE_EOS) { devpriv->ai_eos = 1; /* DMA is useless for this situation */ @@ -1039,32 +1038,16 @@ static int pcl812_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct pcl812_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; int i; for (i = 0; i < insn->n; i++) { - outb((data[i] & 0xff), - dev->iobase + PCL812_AO_LSB_REG(chan)); - outb((data[i] >> 8) & 0x0f, - dev->iobase + PCL812_AO_MSB_REG(chan)); - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + outb(val & 0xff, dev->iobase + PCL812_AO_LSB_REG(chan)); + outb((val >> 8) & 0x0f, dev->iobase + PCL812_AO_MSB_REG(chan)); } - - return insn->n; -} - -static int pcl812_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct pcl812_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + s->readback[chan] = val; return insn->n; } @@ -1097,7 +1080,7 @@ static int pcl812_do_insn_bits(struct comedi_device *dev, static void pcl812_reset(struct comedi_device *dev) { - const struct pcl812_board *board = comedi_board(dev); + const struct pcl812_board *board = dev->board_ptr; struct pcl812_private *devpriv = dev->private; unsigned int chan; @@ -1134,7 +1117,7 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_devconfig *it) { - const struct pcl812_board *board = comedi_board(dev); + const struct pcl812_board *board = dev->board_ptr; struct pcl812_private *devpriv = dev->private; /* default to the range table from the boardinfo */ @@ -1222,7 +1205,7 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev, static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcl812_board *board = comedi_board(dev); + const struct pcl812_board *board = dev->board_ptr; struct pcl812_private *devpriv; struct comedi_subdevice *s; int n_subdevices; @@ -1336,8 +1319,6 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->n_chan = board->n_aochan; s->maxdata = 0xfff; s->range_table = &range_unipolar5; - s->insn_read = pcl812_ao_insn_read; - s->insn_write = pcl812_ao_insn_write; switch (board->board_type) { case boardA821: if (it->options[3] == 1) @@ -1353,6 +1334,13 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_unknown; break; } + s->insn_write = pcl812_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + subdev++; } diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index 54732c5cab97..aa6487132017 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -671,7 +671,7 @@ static void pcl816_reset(struct comedi_device *dev) static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcl816_board *board = comedi_board(dev); + const struct pcl816_board *board = dev->board_ptr; struct pcl816_private *devpriv; struct comedi_subdevice *s; int ret; diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index 000dbf841e45..ac19e83ce62a 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -319,7 +319,6 @@ struct pcl818_private { unsigned int act_chanlist_len; /* how long is actual MUX list */ unsigned int act_chanlist_pos; /* actual position in MUX list */ unsigned int ai_data_len; /* len of data buffer */ - unsigned int ao_readback[2]; unsigned int divisor1; unsigned int divisor2; unsigned int usefifo:1; @@ -739,7 +738,7 @@ static int check_single_ended(unsigned int port) static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcl818_board *board = comedi_board(dev); + const struct pcl818_board *board = dev->board_ptr; struct pcl818_private *devpriv = dev->private; int err = 0; unsigned int arg; @@ -937,32 +936,18 @@ static int pcl818_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct pcl818_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = s->readback[chan]; int i; for (i = 0; i < insn->n; i++) { - devpriv->ao_readback[chan] = data[i]; - outb((data[i] & 0x000f) << 4, + val = data[i]; + outb((val & 0x000f) << 4, dev->iobase + PCL818_AO_LSB_REG(chan)); - outb((data[i] & 0x0ff0) >> 4, + outb((val & 0x0ff0) >> 4, dev->iobase + PCL818_AO_MSB_REG(chan)); } - - return insn->n; -} - -static int pcl818_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct pcl818_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + s->readback[chan] = val; return insn->n; } @@ -995,7 +980,7 @@ static int pcl818_do_insn_bits(struct comedi_device *dev, static void pcl818_reset(struct comedi_device *dev) { - const struct pcl818_board *board = comedi_board(dev); + const struct pcl818_board *board = dev->board_ptr; unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; unsigned int chan; @@ -1033,7 +1018,7 @@ static void pcl818_set_ai_range_table(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_devconfig *it) { - const struct pcl818_board *board = comedi_board(dev); + const struct pcl818_board *board = dev->board_ptr; /* default to the range table from the boardinfo */ s->range_table = board->ai_range_type; @@ -1082,7 +1067,7 @@ static void pcl818_set_ai_range_table(struct comedi_device *dev, static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcl818_board *board = comedi_board(dev); + const struct pcl818_board *board = dev->board_ptr; struct pcl818_private *devpriv; struct comedi_subdevice *s; int ret; @@ -1172,8 +1157,6 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->n_chan = board->n_aochan; s->maxdata = 0x0fff; s->range_table = &range_unipolar5; - s->insn_read = pcl818_ao_insn_read; - s->insn_write = pcl818_ao_insn_write; if (board->is_818) { if ((it->options[4] == 1) || (it->options[4] == 10)) s->range_table = &range_unipolar10; @@ -1185,6 +1168,12 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (it->options[5] == 2) s->range_table = &range_unknown; } + s->insn_write = pcl818_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index 6e0d78f6095b..6176dfa24801 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -33,8 +33,6 @@ Copy/pasted/hacked from pcm724.c #include "8255.h" -#define SIZE_8255 4 - #define BUF_C0 0x1 #define BUF_B0 0x2 #define BUF_A0 0x4 @@ -49,16 +47,6 @@ Copy/pasted/hacked from pcm724.c #define GATE_B1 0x10 #define GATE_C1 0x8 -/* from 8255.c */ -#define CR_CW 0x80 -#define _8255_CR 3 -#define CR_B_IO 0x02 -#define CR_B_MODE 0x04 -#define CR_C_IO 0x09 -#define CR_A_IO 0x10 -#define CR_A_MODE(a) ((a)<<5) -#define CR_CW 0x80 - /* used to track configured dios */ struct priv_pcm3724 { int dio_1; @@ -98,26 +86,26 @@ static void do_3724_config(struct comedi_device *dev, int buffer_config; unsigned long port_8255_cfg; - config = CR_CW; + config = I8255_CTRL_CW; buffer_config = 0; /* 1 in io_bits indicates output, 1 in config indicates input */ if (!(s->io_bits & 0x0000ff)) - config |= CR_A_IO; + config |= I8255_CTRL_A_IO; if (!(s->io_bits & 0x00ff00)) - config |= CR_B_IO; + config |= I8255_CTRL_B_IO; if (!(s->io_bits & 0xff0000)) - config |= CR_C_IO; + config |= I8255_CTRL_C_HI_IO | I8255_CTRL_C_LO_IO; buffer_config = compute_buffer(0, 0, s_dio1); buffer_config = compute_buffer(buffer_config, 1, s_dio2); if (s == s_dio1) - port_8255_cfg = dev->iobase + _8255_CR; + port_8255_cfg = dev->iobase + I8255_CTRL_REG; else - port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR; + port_8255_cfg = dev->iobase + I8255_SIZE + I8255_CTRL_REG; outb(buffer_config, dev->iobase + 8); /* update buffer register */ @@ -211,8 +199,7 @@ static int pcm3724_attach(struct comedi_device *dev, for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; - ret = subdev_8255_init(dev, s, NULL, - dev->iobase + SIZE_8255 * i); + ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); if (ret) return ret; s->insn_config = subdev_3724_insn_config; diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index 87c61d9b11da..e3ac8ac6190e 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -112,7 +112,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev, static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcmad_board_struct *board = comedi_board(dev); + const struct pcmad_board_struct *board = dev->board_ptr; struct comedi_subdevice *s; int ret; diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 1c7a135c91d6..59108c06cedc 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -61,7 +61,6 @@ static const struct comedi_lrange pcmda12_ranges = { }; struct pcmda12_private { - unsigned int ao_readback[8]; int simultaneous_xfer_mode; }; @@ -72,7 +71,7 @@ static int pcmda12_ao_insn_write(struct comedi_device *dev, { struct pcmda12_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val = devpriv->ao_readback[chan]; + unsigned int val = s->readback[chan]; unsigned long ioreg = dev->iobase + (chan * 2); int i; @@ -88,7 +87,7 @@ static int pcmda12_ao_insn_write(struct comedi_device *dev, if (!devpriv->simultaneous_xfer_mode) inb(ioreg); } - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; return insn->n; } @@ -99,8 +98,6 @@ static int pcmda12_ao_insn_read(struct comedi_device *dev, unsigned int *data) { struct pcmda12_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; /* * Initiate simultaneaous xfer mode by reading one of the @@ -109,10 +106,7 @@ static int pcmda12_ao_insn_read(struct comedi_device *dev, if (devpriv->simultaneous_xfer_mode) inb(dev->iobase); - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; + return comedi_readback_insn_read(dev, s, insn, data); } static void pcmda12_ao_reset(struct comedi_device *dev, @@ -158,6 +152,10 @@ static int pcmda12_attach(struct comedi_device *dev, s->insn_write = pcmda12_ao_insn_write; s->insn_read = pcmda12_ao_insn_read; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + pcmda12_ao_reset(dev, s); return 0; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index fed7e77e0305..fc40ee2b34e9 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -192,8 +192,6 @@ struct pcmmio_private { unsigned int enabled_mask; unsigned int stop_count; unsigned int active:1; - - unsigned int ao_readback[8]; }; static void pcmmio_dio_write(struct comedi_device *dev, unsigned int val, @@ -408,8 +406,8 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d) } /* devpriv->spinlock is already locked */ -static int pcmmio_start_intr(struct comedi_device *dev, - struct comedi_subdevice *s) +static void pcmmio_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcmmio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -417,13 +415,6 @@ static int pcmmio_start_intr(struct comedi_device *dev, unsigned int pol_bits = 0; int i; - if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count == 0) { - /* An empty acquisition! */ - s->async->events |= COMEDI_CB_EOA; - devpriv->active = 0; - return 1; - } - devpriv->enabled_mask = 0; devpriv->active = 1; if (cmd->chanlist) { @@ -443,8 +434,6 @@ static int pcmmio_start_intr(struct comedi_device *dev, /* set polarity and enable interrupts */ pcmmio_dio_write(dev, pol_bits, PCMMIO_PAGE_POL, 0); pcmmio_dio_write(dev, bits, PCMMIO_PAGE_ENAB, 0); - - return 0; } static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) @@ -467,7 +456,6 @@ static int pcmmio_inttrig_start_intr(struct comedi_device *dev, struct pcmmio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; - int event = 0; if (trig_num != cmd->start_arg) return -EINVAL; @@ -475,12 +463,9 @@ static int pcmmio_inttrig_start_intr(struct comedi_device *dev, spin_lock_irqsave(&devpriv->spinlock, flags); s->async->inttrig = NULL; if (devpriv->active) - event = pcmmio_start_intr(dev, s); + pcmmio_start_intr(dev, s); spin_unlock_irqrestore(&devpriv->spinlock, flags); - if (event) - comedi_event(dev, s); - return 1; } @@ -492,28 +477,20 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct pcmmio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; - int event = 0; spin_lock_irqsave(&devpriv->spinlock, flags); devpriv->active = 1; - /* Set up end of acquisition. */ - if (cmd->stop_src == TRIG_COUNT) - devpriv->stop_count = cmd->stop_arg; - else /* TRIG_NONE */ - devpriv->stop_count = 0; + devpriv->stop_count = cmd->stop_arg; /* Set up start of acquisition. */ if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmmio_inttrig_start_intr; else /* TRIG_NOW */ - event = pcmmio_start_intr(dev, s); + pcmmio_start_intr(dev, s); spin_unlock_irqrestore(&devpriv->spinlock, flags); - if (event) - comedi_event(dev, s); - return 0; } @@ -551,16 +528,10 @@ static int pcmmio_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } if (err) return 3; @@ -655,21 +626,6 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev, return insn->n; } -static int pcmmio_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct pcmmio_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; -} - static int pcmmio_ao_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -688,11 +644,9 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct pcmmio_private *devpriv = dev->private; unsigned long iobase = dev->iobase; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val = devpriv->ao_readback[chan]; unsigned char cmd = 0; int ret; int i; @@ -719,7 +673,7 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, return ret; for (i = 0; i < insn->n; i++) { - val = data[i]; + unsigned int val = data[i]; /* write the data to the channel */ outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG); @@ -731,7 +685,7 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, if (ret) return ret; - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; } return insn->n; @@ -796,8 +750,12 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->n_chan = 8; s->maxdata = 0xffff; s->range_table = &pcmmio_ao_ranges; - s->insn_read = pcmmio_ao_insn_read; s->insn_write = pcmmio_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; /* initialize the resource enable register by clearing it */ outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG); diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 1bca3fba0950..d4fe2ec25ecf 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -132,7 +132,6 @@ struct pcmuio_asic { unsigned int enabled_mask; unsigned int stop_count; unsigned int active:1; - unsigned int continuous:1; }; struct pcmuio_private { @@ -279,7 +278,7 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev, static void pcmuio_reset(struct comedi_device *dev) { - const struct pcmuio_board *board = comedi_board(dev); + const struct pcmuio_board *board = dev->board_ptr; int asic; for (asic = 0; asic < board->num_asics; ++asic) { @@ -349,8 +348,7 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, } /* Check for end of acquisition. */ - if (!chip->continuous) { - /* stop_src == TRIG_COUNT */ + if (cmd->stop_src == TRIG_COUNT) { if (chip->stop_count > 0) { chip->stop_count--; if (chip->stop_count == 0) { @@ -405,8 +403,8 @@ static irqreturn_t pcmuio_interrupt(int irq, void *d) } /* chip->spinlock is already locked */ -static int pcmuio_start_intr(struct comedi_device *dev, - struct comedi_subdevice *s) +static void pcmuio_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcmuio_private *devpriv = dev->private; int asic = pcmuio_subdevice_to_asic(s); @@ -416,13 +414,6 @@ static int pcmuio_start_intr(struct comedi_device *dev, unsigned int pol_bits = 0; int i; - if (!chip->continuous && chip->stop_count == 0) { - /* An empty acquisition! */ - s->async->events |= COMEDI_CB_EOA; - chip->active = 0; - return 1; - } - chip->enabled_mask = 0; chip->active = 1; if (cmd->chanlist) { @@ -442,8 +433,6 @@ static int pcmuio_start_intr(struct comedi_device *dev, /* set pol and enab intrs for this subdev.. */ pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0); pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0); - - return 0; } static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) @@ -470,7 +459,6 @@ static int pcmuio_inttrig_start_intr(struct comedi_device *dev, int asic = pcmuio_subdevice_to_asic(s); struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; - int event = 0; if (trig_num != cmd->start_arg) return -EINVAL; @@ -478,13 +466,10 @@ static int pcmuio_inttrig_start_intr(struct comedi_device *dev, spin_lock_irqsave(&chip->spinlock, flags); s->async->inttrig = NULL; if (chip->active) - event = pcmuio_start_intr(dev, s); + pcmuio_start_intr(dev, s); spin_unlock_irqrestore(&chip->spinlock, flags); - if (event) - comedi_event(dev, s); - return 1; } @@ -498,35 +483,20 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) int asic = pcmuio_subdevice_to_asic(s); struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; - int event = 0; spin_lock_irqsave(&chip->spinlock, flags); chip->active = 1; - /* Set up end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - chip->continuous = 0; - chip->stop_count = cmd->stop_arg; - break; - default: - /* TRIG_NONE */ - chip->continuous = 1; - chip->stop_count = 0; - break; - } + chip->stop_count = cmd->stop_arg; /* Set up start of acquisition. */ if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmuio_inttrig_start_intr; else /* TRIG_NOW */ - event = pcmuio_start_intr(dev, s); + pcmuio_start_intr(dev, s); spin_unlock_irqrestore(&chip->spinlock, flags); - if (event) - comedi_event(dev, s); - return 0; } @@ -564,16 +534,10 @@ static int pcmuio_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } if (err) return 3; @@ -587,7 +551,7 @@ static int pcmuio_cmdtest(struct comedi_device *dev, static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct pcmuio_board *board = comedi_board(dev); + const struct pcmuio_board *board = dev->board_ptr; struct comedi_subdevice *s; struct pcmuio_private *devpriv; int ret; diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index b1db61d9d834..6407df0404f0 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -638,7 +638,6 @@ static int daqp_ao_insn_write(struct comedi_device *dev, { struct daqp_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val; int i; if (devpriv->stop) @@ -648,7 +647,10 @@ static int daqp_ao_insn_write(struct comedi_device *dev, outb(0, dev->iobase + DAQP_AUX); for (i = 0; i > insn->n; i++) { - val = data[0]; + unsigned val = data[i]; + + s->readback[chan] = val; + val &= 0x0fff; val ^= 0x0800; /* Flip the sign */ val |= (chan << 12); @@ -739,6 +741,11 @@ static int daqp_auto_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table = &range_bipolar5; s->insn_write = daqp_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 6fc4ed33f66c..7d4cb140959c 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -380,7 +380,6 @@ struct rtd_private { int xfer_count; /* # to transfer data. 0->1/2FIFO */ int flags; /* flag event modes */ DECLARE_BITMAP(chan_is_bipolar, RTD_MAX_CHANLIST); - unsigned int ao_readback[2]; unsigned fifosz; }; @@ -400,15 +399,15 @@ static int rtd_ns_to_timer_base(unsigned int *nanosec, { int divider; - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: divider = (*nanosec + base / 2) / base; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: divider = (*nanosec) / base; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: divider = (*nanosec + base - 1) / base; break; } @@ -438,7 +437,7 @@ static int rtd_ns_to_timer(unsigned int *ns, unsigned int flags) static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, unsigned int chanspec, int index) { - const struct rtd_boardinfo *board = comedi_board(dev); + const struct rtd_boardinfo *board = dev->board_ptr; struct rtd_private *devpriv = dev->private; unsigned int chan = CR_CHAN(chanspec); unsigned int range = CR_RANGE(chanspec); @@ -809,26 +808,26 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, if (cfc_check_trigger_arg_min(&cmd->scan_begin_arg, RTD_MAX_SPEED_1)) { rtd_ns_to_timer(&cmd->scan_begin_arg, - TRIG_ROUND_UP); + CMDF_ROUND_UP); err |= -EINVAL; } if (cfc_check_trigger_arg_max(&cmd->scan_begin_arg, RTD_MIN_SPEED_1)) { rtd_ns_to_timer(&cmd->scan_begin_arg, - TRIG_ROUND_DOWN); + CMDF_ROUND_DOWN); err |= -EINVAL; } } else { if (cfc_check_trigger_arg_min(&cmd->scan_begin_arg, RTD_MAX_SPEED)) { rtd_ns_to_timer(&cmd->scan_begin_arg, - TRIG_ROUND_UP); + CMDF_ROUND_UP); err |= -EINVAL; } if (cfc_check_trigger_arg_max(&cmd->scan_begin_arg, RTD_MIN_SPEED)) { rtd_ns_to_timer(&cmd->scan_begin_arg, - TRIG_ROUND_DOWN); + CMDF_ROUND_DOWN); err |= -EINVAL; } } @@ -844,26 +843,26 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, if (cfc_check_trigger_arg_min(&cmd->convert_arg, RTD_MAX_SPEED_1)) { rtd_ns_to_timer(&cmd->convert_arg, - TRIG_ROUND_UP); + CMDF_ROUND_UP); err |= -EINVAL; } if (cfc_check_trigger_arg_max(&cmd->convert_arg, RTD_MIN_SPEED_1)) { rtd_ns_to_timer(&cmd->convert_arg, - TRIG_ROUND_DOWN); + CMDF_ROUND_DOWN); err |= -EINVAL; } } else { if (cfc_check_trigger_arg_min(&cmd->convert_arg, RTD_MAX_SPEED)) { rtd_ns_to_timer(&cmd->convert_arg, - TRIG_ROUND_UP); + CMDF_ROUND_UP); err |= -EINVAL; } if (cfc_check_trigger_arg_max(&cmd->convert_arg, RTD_MIN_SPEED)) { rtd_ns_to_timer(&cmd->convert_arg, - TRIG_ROUND_DOWN); + CMDF_ROUND_DOWN); err |= -EINVAL; } } @@ -875,12 +874,10 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* TODO check for rounding error due to counter wrap */ - } else { - /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -956,7 +953,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (TRIG_TIMER == cmd->scan_begin_src) { /* scan_begin_arg is in nanoseconds */ /* find out how many samples to wait before transferring */ - if (cmd->flags & TRIG_WAKE_EOS) { + if (cmd->flags & CMDF_WAKE_EOS) { /* * this may generate un-sustainable interrupt rates * the application is responsible for doing the @@ -1020,7 +1017,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) switch (cmd->scan_begin_src) { case TRIG_TIMER: /* periodic scanning */ timer = rtd_ns_to_timer(&cmd->scan_begin_arg, - TRIG_ROUND_NEAREST); + CMDF_ROUND_NEAREST); /* set PACER clock */ writel(timer & 0xffffff, dev->mmio + LAS0_PCLK); @@ -1038,7 +1035,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->chanlist_len > 1) { /* only needed for multi-channel */ timer = rtd_ns_to_timer(&cmd->convert_arg, - TRIG_ROUND_NEAREST); + CMDF_ROUND_NEAREST); /* setup BURST clock */ writel(timer & 0x3ff, dev->mmio + LAS0_BCLK); } @@ -1138,7 +1135,7 @@ static int rtd_ao_winsn(struct comedi_device *dev, ((chan == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO)); writew(0, dev->mmio + ((chan == 0) ? LAS0_DAC1 : LAS0_DAC2)); - devpriv->ao_readback[chan] = data[i]; + s->readback[chan] = data[i]; ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0); if (ret) @@ -1149,23 +1146,6 @@ static int rtd_ao_winsn(struct comedi_device *dev, return i; } -/* AO subdevices should have a read insn as well as a write insn. - * Usually this means copying a value stored in devpriv. */ -static int rtd_ao_rinsn(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); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - - return i; -} - static int rtd_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -1323,7 +1303,11 @@ static int rtd_auto_attach(struct comedi_device *dev, s->maxdata = 0x0fff; s->range_table = &rtd_ao_range; s->insn_write = rtd_ao_winsn; - s->insn_read = rtd_ao_rinsn; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* digital i/o subdevice */ diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index 2b1db9783bd6..e3d9f44cefb9 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -137,7 +137,6 @@ struct rti800_private { bool adc_2comp; bool dac_2comp[2]; const struct comedi_lrange *ao_range_type_list[2]; - unsigned int ao_readback[2]; unsigned char muxgain_bits; }; @@ -207,21 +206,6 @@ static int rti800_ai_insn_read(struct comedi_device *dev, return insn->n; } -static int rti800_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct rti800_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; -} - static int rti800_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -231,11 +215,13 @@ static int rti800_ao_insn_write(struct comedi_device *dev, unsigned int chan = CR_CHAN(insn->chanspec); int reg_lo = chan ? RTI800_DAC1LO : RTI800_DAC0LO; int reg_hi = chan ? RTI800_DAC1HI : RTI800_DAC0HI; - int val = devpriv->ao_readback[chan]; int i; for (i = 0; i < insn->n; i++) { - val = data[i]; + unsigned int val = data[i]; + + s->readback[chan] = val; + if (devpriv->dac_2comp[chan]) val ^= 0x800; @@ -243,8 +229,6 @@ static int rti800_ao_insn_write(struct comedi_device *dev, outb((val >> 8) & 0xff, dev->iobase + reg_hi); } - devpriv->ao_readback[chan] = val; - return insn->n; } @@ -274,7 +258,7 @@ static int rti800_do_insn_bits(struct comedi_device *dev, static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct rti800_board *board = comedi_board(dev); + const struct rti800_board *board = dev->board_ptr; struct rti800_private *devpriv; struct comedi_subdevice *s; int ret; @@ -318,8 +302,6 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; - s->insn_read = rti800_ao_insn_read; - s->insn_write = rti800_ao_insn_write; s->maxdata = 0x0fff; s->range_table_list = devpriv->ao_range_type_list; devpriv->ao_range_type_list[0] = @@ -330,6 +312,12 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) (it->options[7] < ARRAY_SIZE(rti800_ao_ranges)) ? rti800_ao_ranges[it->options[7]] : &range_unknown; + s->insn_write = rti800_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index 605a31d702e0..c81b01c40f12 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -45,24 +45,8 @@ struct rti802_private { dac_2comp, dac_straight } dac_coding[8]; const struct comedi_lrange *range_type_list[8]; - unsigned int ao_readback[8]; }; -static int rti802_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct rti802_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return insn->n; -} - static int rti802_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -70,15 +54,14 @@ static int rti802_ao_insn_write(struct comedi_device *dev, { struct rti802_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val; int i; outb(chan, dev->iobase + RTI802_SELECT); for (i = 0; i < insn->n; i++) { - val = data[i]; + unsigned int val = data[i]; - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; /* munge offset binary to two's complement if needed */ if (devpriv->dac_coding[chan] == dac_2comp) @@ -116,10 +99,14 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->subdev_flags = SDF_WRITABLE; s->maxdata = 0xfff; s->n_chan = 8; - s->insn_read = rti802_ao_insn_read; s->insn_write = rti802_ao_insn_write; - s->range_table_list = devpriv->range_type_list; + s->insn_read = comedi_readback_insn_read; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + + s->range_table_list = devpriv->range_type_list; for (i = 0; i < 8; i++) { devpriv->dac_coding[i] = (it->options[3 + 2 * i]) ? (dac_straight) : (dac_2comp); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 83f7433c2452..75872c6aec2a 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -111,7 +111,6 @@ union cmReg { }; struct s526_private { - unsigned int ao_readback[2]; unsigned int gpct_config[4]; unsigned short ai_config; }; @@ -467,38 +466,26 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } -static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int s526_ao_insn_write(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); - unsigned short val; + unsigned int val = s->readback[chan]; int i; - val = chan << 1; - outw(val, dev->iobase + REG_DAC); + outw(chan << 1, dev->iobase + REG_DAC); for (i = 0; i < insn->n; i++) { - outw(data[i], dev->iobase + REG_ADD); - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + outw(val, dev->iobase + REG_ADD); /* starts the D/A conversion */ - outw(val + 1, dev->iobase + REG_DAC); + outw((chan << 1) | 1, dev->iobase + REG_DAC); } + s->readback[chan] = val; - return i; -} - -static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct s526_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; + return insn->n; } static int s526_dio_insn_bits(struct comedi_device *dev, @@ -595,8 +582,12 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->n_chan = 4; s->maxdata = 0xffff; s->range_table = &range_bipolar10; - s->insn_write = s526_ao_winsn; - s->insn_read = s526_ao_rinsn; + s->insn_write = s526_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[3]; /* digital i/o subdevice */ diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 080608a840ac..0e7621e890c3 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -78,7 +78,6 @@ struct s626_buffer_dma { struct s626_private { uint8_t ai_cmd_running; /* ai_cmd is running */ - uint8_t ai_continuous; /* continuous acquisition */ int ai_sample_count; /* number of samples to acquire */ unsigned int ai_sample_timer; /* time between samples in * units of the timer */ @@ -98,7 +97,6 @@ struct s626_private { uint8_t trim_setpoint[12]; /* images of TrimDAC setpoints */ uint32_t i2c_adrs; /* I2C device address for onboard EEPROM * (board rev dependent) */ - unsigned int ao_readback[S626_DAC_CHANNELS]; }; /* Counter overflow/index event flag masks for RDMISC2. */ @@ -1399,7 +1397,6 @@ static void s626_check_dio_interrupts(struct comedi_device *dev) uint8_t group; for (group = 0; group < S626_DIO_BANKS; group++) { - irqbit = 0; /* read interrupt type */ irqbit = s626_debi_read(dev, S626_LP_RDCAPFLG(group)); @@ -1504,19 +1501,20 @@ static bool s626_handle_eos_interrupt(struct comedi_device *dev) /* end of scan occurs */ async->events |= COMEDI_CB_EOS; - if (!devpriv->ai_continuous) + if (cmd->stop_src == TRIG_COUNT) { devpriv->ai_sample_count--; - if (devpriv->ai_sample_count <= 0) { - devpriv->ai_cmd_running = 0; + if (devpriv->ai_sample_count <= 0) { + devpriv->ai_cmd_running = 0; - /* Stop RPS program */ - s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); + /* Stop RPS program */ + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); - /* send end of acquisition */ - async->events |= COMEDI_CB_EOA; + /* send end of acquisition */ + async->events |= COMEDI_CB_EOA; - /* disable master interrupt */ - finished = true; + /* disable master interrupt */ + finished = true; + } } if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT) @@ -1969,15 +1967,15 @@ static int s626_ns_to_timer(unsigned int *nanosec, unsigned int flags) base = 500; /* 2MHz internal clock */ - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_NEAREST: + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: default: divider = (*nanosec + base / 2) / base; break; - case TRIG_ROUND_DOWN: + case CMDF_ROUND_DOWN: divider = (*nanosec) / base; break; - case TRIG_ROUND_UP: + case CMDF_ROUND_UP: divider = (*nanosec + base - 1) / base; break; } @@ -2104,18 +2102,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) break; } - switch (cmd->stop_src) { - case TRIG_COUNT: - /* data arrives as one packet */ - devpriv->ai_sample_count = cmd->stop_arg; - devpriv->ai_continuous = 0; - break; - case TRIG_NONE: - /* continuous acquisition */ - devpriv->ai_continuous = 1; - devpriv->ai_sample_count = 1; - break; - } + devpriv->ai_sample_count = cmd->stop_arg; s626_reset_adc(dev, ppl); @@ -2221,7 +2208,7 @@ static int s626_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) - err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); @@ -2269,38 +2256,28 @@ static int s626_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int s626_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct s626_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int ret; - uint16_t chan = CR_CHAN(insn->chanspec); - int16_t dacdata; for (i = 0; i < insn->n; i++) { - dacdata = (int16_t) data[i]; - devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i]; + int16_t dacdata = (int16_t)data[i]; + int ret; + dacdata -= (0x1fff); ret = s626_set_dac(dev, chan, dacdata); if (ret) return ret; - } - - return i; -} -static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct s626_private *devpriv = dev->private; - int i; - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; + s->readback[chan] = data[i]; + } - return i; + return insn->n; } /* *************** DIGITAL I/O FUNCTIONS *************** */ @@ -2457,26 +2434,6 @@ static void s626_write_misc2(struct comedi_device *dev, uint16_t new_image) s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WDISABLE); } -static void s626_close_dma_b(struct comedi_device *dev, - struct s626_buffer_dma *pdma, size_t bsize) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - void *vbptr; - dma_addr_t vpptr; - - if (pdma == NULL) - return; - - /* find the matching allocation from the board struct */ - vbptr = pdma->logical_base; - vpptr = pdma->physical_base; - if (vbptr) { - pci_free_consistent(pcidev, bsize, vbptr, vpptr); - pdma->logical_base = NULL; - pdma->physical_base = 0; - } -} - static void s626_counters_init(struct comedi_device *dev) { int chan; @@ -2527,6 +2484,24 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev) return 0; } +static void s626_free_dma_buffers(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct s626_private *devpriv = dev->private; + + if (!devpriv) + return; + + if (devpriv->rps_buf.logical_base) + pci_free_consistent(pcidev, S626_DMABUF_SIZE, + devpriv->rps_buf.logical_base, + devpriv->rps_buf.physical_base); + if (devpriv->ana_buf.logical_base) + pci_free_consistent(pcidev, S626_DMABUF_SIZE, + devpriv->ana_buf.logical_base, + devpriv->ana_buf.physical_base); +} + static int s626_initialize(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; @@ -2844,8 +2819,12 @@ static int s626_auto_attach(struct comedi_device *dev, s->n_chan = S626_DAC_CHANNELS; s->maxdata = 0x3fff; s->range_table = &range_bipolar10; - s->insn_write = s626_ao_winsn; - s->insn_read = s626_ao_rinsn; + s->insn_write = s626_ao_insn_write; + s->insn_read = comedi_readback_insn_read; + + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; s = &dev->subdevices[2]; /* digital I/O subdevice */ @@ -2923,19 +2902,10 @@ static void s626_detach(struct comedi_device *dev) /* Close all interfaces on 7146 device */ writel(S626_MC1_SHUTDOWN, dev->mmio + S626_P_MC1); writel(S626_ACON1_BASE, dev->mmio + S626_P_ACON1); - - s626_close_dma_b(dev, &devpriv->rps_buf, - S626_DMABUF_SIZE); - s626_close_dma_b(dev, &devpriv->ana_buf, - S626_DMABUF_SIZE); } - - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->mmio) - iounmap(dev->mmio); } - comedi_pci_disable(dev); + comedi_pci_detach(dev); + s626_free_dma_buffers(dev); } static struct comedi_driver s626_driver = { diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c deleted file mode 100644 index a118678c24a1..000000000000 --- a/drivers/staging/comedi/drivers/skel.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - comedi/drivers/skel.c - Skeleton code for a Comedi driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: skel -Description: Skeleton driver, an example for driver writers -Devices: -Author: ds -Updated: Mon, 18 Mar 2002 15:34:01 -0800 -Status: works - -This driver is a documented example on how Comedi drivers are -written. - -Configuration Options: - none -*/ - -/* - * The previous block comment is used to automatically generate - * documentation in Comedi and Comedilib. The fields: - * - * Driver: the name of the driver - * Description: a short phrase describing the driver. Don't list boards. - * Devices: a full list of the boards that attempt to be supported by - * the driver. Format is "(manufacturer) board name [comedi name]", - * where comedi_name is the name that is used to configure the board. - * See the comment near board_name: in the struct comedi_driver structure - * below. If (manufacturer) or [comedi name] is missing, the previous - * value is used. - * Author: you - * Updated: date when the _documentation_ was last updated. Use 'date -R' - * to get a value for this. - * Status: a one-word description of the status. Valid values are: - * works - driver works correctly on most boards supported, and - * passes comedi_test. - * unknown - unknown. Usually put there by ds. - * experimental - may not work in any particular release. Author - * probably wants assistance testing it. - * bitrotten - driver has not been update in a long time, probably - * doesn't work, and probably is missing support for significant - * Comedi interface features. - * untested - author probably wrote it "blind", and is believed to - * work, but no confirmation. - * - * These headers should be followed by a blank line, and any comments - * you wish to say about the driver. The comment area is the place - * to put any known bugs, limitations, unsupported features, supported - * command triggers, whether or not commands are supported on particular - * subdevices, etc. - * - * Somewhere in the comment should be information about configuration - * options that are used with comedi_config. - */ - -#include <linux/module.h> -#include <linux/pci.h> - -#include "../comedidev.h" - -#include "comedi_fc.h" - -/* Imaginary registers for the imaginary board */ -#define SKEL_START_AI_CONV 0 -#define SKEL_AI_READ 0 - -/* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. - */ -enum skel_boardid { - BOARD_SKEL100, - BOARD_SKEL200, -}; - -struct skel_board { - const char *name; - int ai_chans; - int ai_bits; - int have_dio; -}; - -static const struct skel_board skel_boards[] = { - [BOARD_SKEL100] = { - .name = "skel-100", - .ai_chans = 16, - .ai_bits = 12, - .have_dio = 1, - }, - [BOARD_SKEL200] = { - .name = "skel-200", - .ai_chans = 8, - .ai_bits = 16, - }, -}; - -/* 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 struct comedi_device struct. - */ -struct skel_private { - - int data; - - /* Used for AO readback */ - unsigned int ao_readback[2]; -}; - -/* This function doesn't require a particular form, this is just - * what happens to be used in some of the drivers. It should - * convert ns nanoseconds to a counter value suitable for programming - * the device. Also, it should adjust ns so that it cooresponds to - * the actual time that the device will use. */ -static int skel_ns_to_timer(unsigned int *ns, unsigned int flags) -{ - /* trivial timer */ - /* if your timing is done through two cascaded timers, the - * i8253_cascade_ns_to_timer() function in 8253.h can be - * very helpful. There are also i8254_load() and i8254_mm_load() - * which can be used to load values into the ubiquitous 8254 counters - */ - - return *ns; -} - -/* - * This function doesn't require a particular form, this is just - * what happens to be used in some of the drivers. The comedi_timeout() - * helper uses this callback to check for the end-of-conversion while - * waiting for up to 1 second. This function should return 0 when the - * conversion is finished and -EBUSY to keep waiting. Any other errno - * will terminate comedi_timeout() and return that errno to the caller. - * If the timeout occurs, comedi_timeout() will return -ETIMEDOUT. - */ -static int skel_ai_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned long context) -{ - unsigned int status; - - /* status = inb(dev->iobase + SKEL_STATUS); */ - status = 1; - if (status) - return 0; - return -EBUSY; -} - -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ -static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - const struct skel_board *thisboard = comedi_board(dev); - int n; - unsigned int d; - int ret; - - /* a typical programming sequence */ - - /* write channel to multiplexer */ - /* outw(chan,dev->iobase + SKEL_MUX); */ - - /* don't wait for mux to settle */ - - /* convert n samples */ - for (n = 0; n < insn->n; n++) { - /* trigger conversion */ - /* outw(0,dev->iobase + SKEL_CONVERT); */ - - /* wait for conversion to end */ - ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0); - if (ret) - return ret; - - /* read data */ - /* d = inw(dev->iobase + SKEL_AI_DATA); */ - d = 0; - - /* mangle the data as necessary */ - d ^= 1 << (thisboard->ai_bits - 1); - - data[n] = d; - } - - /* return the number of samples read/written */ - return n; -} - -/* - * 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 executes by the cmd ioctl. - * - * cmdtest returns 1,2,3,4 or 0, depending on which tests - * the command passes. - */ -static int skel_ai_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 |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - -#define MAX_SPEED 10000 /* in nanoseconds */ -#define MIN_SPEED 1000000000 /* in nanoseconds */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); - } - - if (cmd->convert_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, MIN_SPEED); - } else { - /* external trigger */ - /* see above */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); - } - - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - if (cmd->stop_src == TRIG_COUNT) - err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); - else /* TRIG_NONE */ - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - arg = cmd->scan_begin_arg; - skel_ns_to_timer(&arg, cmd->flags); - err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); - } - if (cmd->convert_src == TRIG_TIMER) { - arg = cmd->convert_arg; - skel_ns_to_timer(&arg, cmd->flags); - err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); - - if (cmd->scan_begin_src == TRIG_TIMER) { - arg = cmd->convert_arg * cmd->scan_end_arg; - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - arg); - } - } - - if (err) - return 4; - - return 0; -} - -static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct skel_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - /* 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++) { - /* a typical programming sequence */ - /* outw(data[i],dev->iobase + SKEL_DA0 + chan); */ - devpriv->ao_readback[chan] = data[i]; - } - - /* return the number of samples read/written */ - return i; -} - -/* AO subdevices should have a read insn as well as a write insn. - * Usually this means copying a value stored in devpriv. */ -static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct skel_private *devpriv = dev->private; - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; -} - -/* - * DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write. - */ -static int skel_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - /* - * The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. - * - * The core provided comedi_dio_update_state() function can - * be used to handle the internal state update to DIO subdevices - * with <= 32 channels. This function will return '0' if the - * state does not change or the mask of the channels that need - * to be updated. - */ - if (comedi_dio_update_state(s, data)) { - /* Write out the new digital output lines */ - /* outw(s->state, dev->iobase + SKEL_DIO); */ - } - - /* - * On return, data[1] contains the value of the digital - * input and output lines. - */ - /* data[1] = inw(dev->iobase + SKEL_DIO); */ - - /* - * Or we could just return the software copy of the output - * values if it was a purely digital output subdevice. - */ - /* data[1] = s->state; */ - - return insn->n; -} - -static int skel_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int ret; - - /* - * The input or output configuration of each digital line is - * configured by special insn_config instructions. - * - * chanspec contains the channel to be changed - * data[0] contains the instruction to perform on the channel - * - * Normally the core provided comedi_dio_insn_config() function - * can be used to handle the boilerplpate. - */ - ret = comedi_dio_insn_config(dev, s, insn, data, 0); - if (ret) - return ret; - - /* Update the hardware to the new configuration */ - /* outw(s->io_bits, dev->iobase + SKEL_DIO_CONFIG); */ - - return insn->n; -} - -/* - * Handle common part of skel_attach() and skel_auto_attach(). - */ -static int skel_common_attach(struct comedi_device *dev) -{ - const struct skel_board *thisboard = comedi_board(dev); - struct comedi_subdevice *s; - int ret; - - ret = comedi_alloc_subdevices(dev, 3); - if (ret) - return ret; - - s = &dev->subdevices[0]; - /* dev->read_subdev=s; */ - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - /* we support single-ended (ground) and differential */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = thisboard->ai_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &range_bipolar10; - s->len_chanlist = 16; /* This is the maximum chanlist length that - the board can handle */ - s->insn_read = skel_ai_rinsn; -/* -* s->subdev_flags |= SDF_CMD_READ; -* s->do_cmd = skel_ai_cmd; -*/ - s->do_cmdtest = skel_ai_cmdtest; - - s = &dev->subdevices[1]; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 1; - s->maxdata = 0xffff; - s->range_table = &range_bipolar5; - s->insn_write = skel_ao_winsn; - s->insn_read = skel_ao_rinsn; - - s = &dev->subdevices[2]; - /* digital i/o subdevice */ - if (thisboard->have_dio) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = skel_dio_insn_bits; - s->insn_config = skel_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - return 0; -} - -/* - * _attach is called by the Comedi core to configure the driver - * for a particular board in response to the COMEDI_DEVCONFIG ioctl for - * a matching board or driver name. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that address. - * - * Drivers that handle only PCI or USB devices do not usually support - * manual attachment of those devices via the COMEDI_DEVCONFIG ioctl, so - * those drivers do not have an _attach function; they just have an - * _auto_attach function instead. (See skel_auto_attach() for an example - * of such a function.) - */ -static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct skel_board *thisboard; - struct skel_private *devpriv; - -/* - * If you can probe the device to determine what device in a series - * it is, this is the place to do it. Otherwise, dev->board_ptr - * should already be initialized. - */ - /* dev->board_ptr = skel_probe(dev, it); */ - - thisboard = comedi_board(dev); - - /* - * The dev->board_name is initialized by the comedi core before - * calling the (*attach) function. It can be optionally set by - * the driver if additional probing has been done. - */ - /* dev->board_name = thisboard->name; */ - - /* Allocate the private data */ - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - -/* - * Supported boards are usually either auto-attached via the - * Comedi driver's _auto_attach routine, or manually attached via the - * Comedi driver's _attach routine. In most cases, attempts to - * manual attach boards that are usually auto-attached should be - * rejected by this function. - */ -/* - * if (thisboard->bustype == pci_bustype) { - * dev_err(dev->class_dev, - * "Manual attachment of PCI board '%s' not supported\n", - * thisboard->name); - * } - */ - -/* - * For ISA boards, get the i/o base address from it->options[], - * request the i/o region and set dev->iobase * from it->options[]. - * If using interrupts, get the IRQ number from it->options[]. - */ - - /* - * Call a common function to handle the remaining things to do for - * attaching ISA or PCI boards. (Extra parameters could be added - * to pass additional information such as IRQ number.) - */ - return skel_common_attach(dev); -} - -/* - * _auto_attach is called via comedi_pci_auto_config() (or - * comedi_usb_auto_config(), etc.) to handle devices that can be attached - * to the Comedi core automatically without the COMEDI_DEVCONFIG ioctl. - * - * The context parameter is driver dependent. - */ -static int skel_auto_attach(struct comedi_device *dev, - unsigned long context) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - const struct skel_board *thisboard = NULL; - struct skel_private *devpriv; - int ret; - - /* Hack to allow unused code to be optimized out. */ - if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS)) - return -EINVAL; - - /* - * In this example, the _auto_attach is for a PCI device. - * - * The 'context' passed to this function is the id->driver_data - * associated with the PCI device found in the id_table during - * the modprobe. This 'context' is the index of the entry in - * skel_boards[i] that contains the boardinfo for the PCI device. - */ - if (context < ARRAY_SIZE(skel_boards)) - thisboard = &skel_boards[context]; - if (!thisboard) - return -ENODEV; - - /* - * Point the struct comedi_device to the matching board info - * and set the board name. - */ - dev->board_ptr = thisboard; - dev->board_name = thisboard->name; - - /* Allocate the private data */ - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - /* Enable the PCI device. */ - ret = comedi_pci_enable(dev); - if (ret) - return ret; - - /* - * Record the fact that the PCI device is enabled so that it can - * be disabled during _detach(). - * - * For this example driver, we assume PCI BAR 0 is the main I/O - * region for the board registers and use dev->iobase to hold the - * I/O base address and to indicate that the PCI device has been - * enabled. - * - * (For boards with memory-mapped registers, dev->iobase is not - * usually needed for register access, so can just be set to 1 - * to indicate that the PCI device has been enabled.) - */ - dev->iobase = pci_resource_start(pcidev, 0); - - /* - * Call a common function to handle the remaining things to do for - * attaching ISA or PCI boards. (Extra parameters could be added - * to pass additional information such as IRQ number.) - */ - return skel_common_attach(dev); -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static void skel_detach(struct comedi_device *dev) -{ - const struct skel_board *thisboard = comedi_board(dev); - struct skel_private *devpriv = dev->private; - - if (!thisboard || !devpriv) - return; - -/* - * Do common stuff such as freeing IRQ, unmapping remapped memory - * regions, etc., being careful to check that the stuff is valid given - * that _detach() is called even when _attach() or _auto_attach() return - * an error. - */ - - if (IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS) /* && - thisboard->bustype == pci_bustype */) { - /* - * PCI board - * - * If PCI device enabled by _auto_attach() (or _attach()), - * disable it here. - */ - comedi_pci_disable(dev); - } else { - /* - * ISA board - * - * Release the first I/O region requested during the - * _attach(). This is safe to call even if the request - * failed. If any additional I/O regions are requested - * they need to be released by the driver. - */ - comedi_legacy_detach(dev); - } -} - -/* - * The struct 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 struct comedi_driver skel_driver = { - .driver_name = "dummy", - .module = THIS_MODULE, - .attach = skel_attach, - .auto_attach = skel_auto_attach, - .detach = skel_detach, -/* It is not necessary to implement the following members if you are - * writing a driver for a ISA PnP or PCI card */ - /* Most drivers will support multiple types of boards by - * having an array of board structures. These were defined - * in skel_boards[] above. Note that the element 'name' - * was first in the structure -- Comedi uses this fact to - * extract the name of the board without knowing any details - * about the structure except for its length. - * When a device is attached (by comedi_config), the name - * of the device is given to Comedi, and Comedi tries to - * match it by going through the list of board names. If - * there is a match, the address of the pointer is put - * into dev->board_ptr and driver->attach() is called. - * - * Note that these are not necessary if you can determine - * the type of board in software. ISA PnP, PCI, and PCMCIA - * devices are such boards. - */ - .board_name = &skel_boards[0].name, - .offset = sizeof(struct skel_board), - .num_names = ARRAY_SIZE(skel_boards), -}; - -#ifdef CONFIG_COMEDI_PCI_DRIVERS - -static int skel_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return comedi_pci_auto_config(dev, &skel_driver, id->driver_data); -} - -/* - * Please add your PCI vendor ID to comedidev.h, and it will - * be forwarded upstream. - */ -#define PCI_VENDOR_ID_SKEL 0xdafe - -/* - * This is used by modprobe to translate PCI IDs to drivers. - * Should only be used for PCI and ISA-PnP devices - */ -static const struct pci_device_id skel_pci_table[] = { - { PCI_VDEVICE(SKEL, 0x0100), BOARD_SKEL100 }, - { PCI_VDEVICE(SKEL, 0x0200), BOARD_SKEL200 }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, skel_pci_table); - -static struct pci_driver skel_pci_driver = { - .name = "dummy", - .id_table = skel_pci_table, - .probe = skel_pci_probe, - .remove = comedi_pci_auto_unconfig, -}; -module_comedi_pci_driver(skel_driver, skel_pci_driver); -#else -module_comedi_driver(skel_driver); -#endif - -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 053bc5090530..5adbfedf780f 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -109,8 +109,6 @@ sampling rate. If you sample two channels you get 4kHz and so on. #define USBDUX_CMD_PWM_ON 7 #define USBDUX_CMD_PWM_OFF 8 -#define USBDUX_NUM_AO_CHAN 4 - /* timeout for the USB-transfer in ms */ #define BULK_TIMEOUT 1000 @@ -198,11 +196,9 @@ struct usbdux_private { /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */ - uint16_t *in_buf; + __le16 *in_buf; /* input buffer for single insn */ - uint16_t *insn_buf; - - unsigned int ao_readback[USBDUX_NUM_AO_CHAN]; + __le16 *insn_buf; unsigned int high_speed:1; unsigned int ai_cmd_running:1; @@ -490,7 +486,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) *datap++ = val & 0xff; *datap++ = (val >> 8) & 0xff; *datap++ = chan << 6; - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; s->async->events |= COMEDI_CB_BLOCK; comedi_event(dev, s); @@ -513,7 +509,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) dev_err(dev->class_dev, "ao urb resubm failed in int-cont. ret=%d", ret); - if (ret == EL2NSYNC) + if (ret == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handling!\n"); @@ -627,12 +623,10 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { - /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -855,15 +849,13 @@ static int usbdux_ao_insn_read(struct comedi_device *dev, unsigned int *data) { struct usbdux_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; + int ret; down(&devpriv->sem); - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + ret = comedi_readback_insn_read(dev, s, insn, data); up(&devpriv->sem); - return insn->n; + return ret; } static int usbdux_ao_insn_write(struct comedi_device *dev, @@ -873,8 +865,8 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, { struct usbdux_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val = devpriv->ao_readback[chan]; - uint16_t *p = (uint16_t *)&devpriv->dux_commands[2]; + unsigned int val = s->readback[chan]; + __le16 *p = (__le16 *)&devpriv->dux_commands[2]; int ret = -EBUSY; int i; @@ -897,8 +889,9 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, ret = send_dux_commands(dev, USBDUX_CMD_AO); if (ret < 0) goto ao_write_exit; + + s->readback[chan] = val; } - devpriv->ao_readback[chan] = val; ao_write_exit: up(&devpriv->sem); @@ -1008,12 +1001,10 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { - /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -1185,7 +1176,7 @@ static int usbdux_counter_write(struct comedi_device *dev, { struct usbdux_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - uint16_t *p = (uint16_t *)&devpriv->dux_commands[2]; + __le16 *p = (__le16 *)&devpriv->dux_commands[2]; int ret = 0; int i; @@ -1294,7 +1285,7 @@ static void usbduxsub_pwm_irq(struct urb *urb) dev_err(dev->class_dev, "pwm urb resubm failed in int-cont. ret=%d", ret); - if (ret == EL2NSYNC) + if (ret == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handling!\n"); @@ -1720,7 +1711,7 @@ static int usbdux_auto_attach(struct comedi_device *dev, dev->write_subdev = s; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; - s->n_chan = USBDUX_NUM_AO_CHAN; + s->n_chan = 4; s->maxdata = 0x0fff; s->len_chanlist = s->n_chan; s->range_table = &range_usbdux_ao_range; @@ -1730,6 +1721,10 @@ static int usbdux_auto_attach(struct comedi_device *dev, s->insn_read = usbdux_ao_insn_read; s->insn_write = usbdux_ao_insn_write; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + /* Digital I/O subdevice */ s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DIO; diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 94a09c16de8b..ebd68e365bac 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -75,8 +75,6 @@ /* Number of channels (16 AD and offset)*/ #define NUMCHANNELS 16 -#define USBDUXSIGMA_NUM_AO_CHAN 4 - /* Size of one A/D value */ #define SIZEADIN ((sizeof(uint32_t))) @@ -157,12 +155,10 @@ struct usbduxsigma_private { /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */ - uint32_t *in_buf; + __be32 *in_buf; /* input buffer for single insn */ uint8_t *insn_buf; - unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN]; - unsigned high_speed:1; unsigned ai_cmd_running:1; unsigned ao_cmd_running:1; @@ -428,7 +424,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb) } *datap++ = val; *datap++ = chan; - devpriv->ao_readback[chan] = val; + s->readback[chan] = val; s->async->events |= COMEDI_CB_BLOCK; comedi_event(dev, s); @@ -451,7 +447,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb) dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", __func__, ret); - if (ret == EL2NSYNC) + if (ret == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handler\n"); usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ @@ -562,12 +558,10 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { - /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -788,7 +782,7 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, } /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(get_unaligned((uint32_t + val = be32_to_cpu(get_unaligned((__be32 *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ @@ -806,15 +800,13 @@ static int usbduxsigma_ao_insn_read(struct comedi_device *dev, unsigned int *data) { struct usbduxsigma_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - int i; + int ret; down(&devpriv->sem); - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + ret = comedi_readback_insn_read(dev, s, insn, data); up(&devpriv->sem); - return insn->n; + return ret; } static int usbduxsigma_ao_insn_write(struct comedi_device *dev, @@ -842,7 +834,7 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev, up(&devpriv->sem); return ret; } - devpriv->ao_readback[chan] = data[i]; + s->readback[chan] = data[i]; } up(&devpriv->sem); @@ -941,12 +933,10 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_COUNT) { - /* any count is allowed */ - } else { - /* TRIG_NONE */ + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } if (err) return 3; @@ -1148,7 +1138,7 @@ static void usbduxsigma_pwm_urb_complete(struct urb *urb) if (ret < 0) { dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", __func__, ret); - if (ret == EL2NSYNC) + if (ret == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handler\n"); usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */ @@ -1349,7 +1339,7 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) return ret; /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1))); + val = be32_to_cpu(get_unaligned((__be32 *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ @@ -1437,10 +1427,8 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL); devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL); - devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(*urb), - GFP_KERNEL); - devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(*urb), - GFP_KERNEL); + devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(urb), GFP_KERNEL); + devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(urb), GFP_KERNEL); if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf || !devpriv->ai_urbs || !devpriv->ao_urbs) return -ENOMEM; @@ -1613,7 +1601,7 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev, dev->write_subdev = s; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; - s->n_chan = USBDUXSIGMA_NUM_AO_CHAN; + s->n_chan = 4; s->len_chanlist = s->n_chan; s->maxdata = 0x00ff; s->range_table = &range_unipolar2_5; @@ -1623,6 +1611,10 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev, s->do_cmd = usbduxsigma_ao_cmd; s->cancel = usbduxsigma_ao_cancel; + ret = comedi_alloc_subdev_readback(s); + if (ret) + return ret; + /* Digital I/O subdevice */ s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DIO; diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 831c3b702899..71003416edcf 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -767,7 +767,7 @@ static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev) static int vmk80xx_init_subdevices(struct comedi_device *dev) { - const struct vmk80xx_board *boardinfo = comedi_board(dev); + const struct vmk80xx_board *boardinfo = dev->board_ptr; struct vmk80xx_private *devpriv = dev->private; struct comedi_subdevice *s; int n_subd; |