root/drivers/staging/comedi/drivers/amplc_pc236_common.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pc236_intr_update
  2. pc236_intr_check
  3. pc236_intr_insn
  4. pc236_intr_cmdtest
  5. pc236_intr_cmd
  6. pc236_intr_cancel
  7. pc236_interrupt
  8. amplc_pc236_common_attach
  9. amplc_pc236_common_init
  10. amplc_pc236_common_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * comedi/drivers/amplc_pc236_common.c
   4  * Common support code for "amplc_pc236" and "amplc_pci236".
   5  *
   6  * Copyright (C) 2002-2014 MEV Ltd. <http://www.mev.co.uk/>
   7  *
   8  * COMEDI - Linux Control and Measurement Device Interface
   9  * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
  10  */
  11 
  12 #include <linux/module.h>
  13 #include <linux/interrupt.h>
  14 
  15 #include "../comedidev.h"
  16 
  17 #include "amplc_pc236.h"
  18 #include "8255.h"
  19 
  20 static void pc236_intr_update(struct comedi_device *dev, bool enable)
  21 {
  22         const struct pc236_board *board = dev->board_ptr;
  23         struct pc236_private *devpriv = dev->private;
  24         unsigned long flags;
  25 
  26         spin_lock_irqsave(&dev->spinlock, flags);
  27         devpriv->enable_irq = enable;
  28         if (board->intr_update_cb)
  29                 board->intr_update_cb(dev, enable);
  30         spin_unlock_irqrestore(&dev->spinlock, flags);
  31 }
  32 
  33 /*
  34  * This function is called when an interrupt occurs to check whether
  35  * the interrupt has been marked as enabled and was generated by the
  36  * board.  If so, the function prepares the hardware for the next
  37  * interrupt.
  38  * Returns false if the interrupt should be ignored.
  39  */
  40 static bool pc236_intr_check(struct comedi_device *dev)
  41 {
  42         const struct pc236_board *board = dev->board_ptr;
  43         struct pc236_private *devpriv = dev->private;
  44         bool retval = false;
  45         unsigned long flags;
  46 
  47         spin_lock_irqsave(&dev->spinlock, flags);
  48         if (devpriv->enable_irq) {
  49                 if (board->intr_chk_clr_cb)
  50                         retval = board->intr_chk_clr_cb(dev);
  51                 else
  52                         retval = true;
  53         }
  54         spin_unlock_irqrestore(&dev->spinlock, flags);
  55 
  56         return retval;
  57 }
  58 
  59 static int pc236_intr_insn(struct comedi_device *dev,
  60                            struct comedi_subdevice *s, struct comedi_insn *insn,
  61                            unsigned int *data)
  62 {
  63         data[1] = 0;
  64         return insn->n;
  65 }
  66 
  67 static int pc236_intr_cmdtest(struct comedi_device *dev,
  68                               struct comedi_subdevice *s,
  69                               struct comedi_cmd *cmd)
  70 {
  71         int err = 0;
  72 
  73         /* Step 1 : check if triggers are trivially valid */
  74 
  75         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
  76         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
  77         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
  78         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
  79         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
  80 
  81         if (err)
  82                 return 1;
  83 
  84         /* Step 2a : make sure trigger sources are unique */
  85         /* Step 2b : and mutually compatible */
  86 
  87         /* Step 3: check it arguments are trivially valid */
  88 
  89         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
  90         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
  91         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
  92         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
  93                                            cmd->chanlist_len);
  94         err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
  95 
  96         if (err)
  97                 return 3;
  98 
  99         /* Step 4: fix up any arguments */
 100 
 101         /* Step 5: check channel list if it exists */
 102 
 103         return 0;
 104 }
 105 
 106 static int pc236_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 107 {
 108         pc236_intr_update(dev, true);
 109 
 110         return 0;
 111 }
 112 
 113 static int pc236_intr_cancel(struct comedi_device *dev,
 114                              struct comedi_subdevice *s)
 115 {
 116         pc236_intr_update(dev, false);
 117 
 118         return 0;
 119 }
 120 
 121 static irqreturn_t pc236_interrupt(int irq, void *d)
 122 {
 123         struct comedi_device *dev = d;
 124         struct comedi_subdevice *s = dev->read_subdev;
 125         bool handled;
 126 
 127         handled = pc236_intr_check(dev);
 128         if (dev->attached && handled) {
 129                 comedi_buf_write_samples(s, &s->state, 1);
 130                 comedi_handle_events(dev, s);
 131         }
 132         return IRQ_RETVAL(handled);
 133 }
 134 
 135 int amplc_pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
 136                               unsigned int irq, unsigned long req_irq_flags)
 137 {
 138         struct comedi_subdevice *s;
 139         int ret;
 140 
 141         dev->iobase = iobase;
 142 
 143         ret = comedi_alloc_subdevices(dev, 2);
 144         if (ret)
 145                 return ret;
 146 
 147         s = &dev->subdevices[0];
 148         /* digital i/o subdevice (8255) */
 149         ret = subdev_8255_init(dev, s, NULL, 0x00);
 150         if (ret)
 151                 return ret;
 152 
 153         s = &dev->subdevices[1];
 154         dev->read_subdev = s;
 155         s->type = COMEDI_SUBD_UNUSED;
 156         pc236_intr_update(dev, false);
 157         if (irq) {
 158                 if (request_irq(irq, pc236_interrupt, req_irq_flags,
 159                                 dev->board_name, dev) >= 0) {
 160                         dev->irq = irq;
 161                         s->type = COMEDI_SUBD_DI;
 162                         s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
 163                         s->n_chan = 1;
 164                         s->maxdata = 1;
 165                         s->range_table = &range_digital;
 166                         s->insn_bits = pc236_intr_insn;
 167                         s->len_chanlist = 1;
 168                         s->do_cmdtest = pc236_intr_cmdtest;
 169                         s->do_cmd = pc236_intr_cmd;
 170                         s->cancel = pc236_intr_cancel;
 171                 }
 172         }
 173 
 174         return 0;
 175 }
 176 EXPORT_SYMBOL_GPL(amplc_pc236_common_attach);
 177 
 178 static int __init amplc_pc236_common_init(void)
 179 {
 180         return 0;
 181 }
 182 module_init(amplc_pc236_common_init);
 183 
 184 static void __exit amplc_pc236_common_exit(void)
 185 {
 186 }
 187 module_exit(amplc_pc236_common_exit);
 188 
 189 MODULE_AUTHOR("Comedi http://www.comedi.org");
 190 MODULE_DESCRIPTION("Comedi helper for amplc_pc236 and amplc_pci236");
 191 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */