Revert "staging: comedi: drivers: use comedi_dio_insn_config() for complex cases"
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / me4000.c
index 8f4afadab76a617a526da821d3ac029562eadf3c..1eda40a9332ee04ba801e86670f310c333bdccb4 100644 (file)
@@ -1358,57 +1358,98 @@ static int me4000_dio_insn_bits(struct comedi_device *dev,
 
 static int me4000_dio_insn_config(struct comedi_device *dev,
                                  struct comedi_subdevice *s,
-                                 struct comedi_insn *insn,
-                                 unsigned int *data)
+                                 struct comedi_insn *insn, unsigned int *data)
 {
-       unsigned int chan = CR_CHAN(insn->chanspec);
-       unsigned int mask;
-       unsigned int tmp;
-       int ret;
+       unsigned long tmp;
+       int chan = CR_CHAN(insn->chanspec);
 
-       if (chan < 8)
-               mask = 0x000000ff;
-       else if (chan < 16)
-               mask = 0x0000ff00;
-       else if (chan < 24)
-               mask = 0x00ff0000;
-       else
-               mask = 0xff000000;
+       switch (data[0]) {
+       default:
+               return -EINVAL;
+       case INSN_CONFIG_DIO_QUERY:
+               data[1] =
+                   (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
+               return insn->n;
+       case INSN_CONFIG_DIO_INPUT:
+       case INSN_CONFIG_DIO_OUTPUT:
+               break;
+       }
 
-       ret = comedi_dio_insn_config(dev, s, insn, data, mask);
-       if (ret)
-               return ret;
+       /*
+        * The input or output configuration of each digital line is
+        * configured by a special insn_config instruction.  chanspec
+        * contains the channel to be changed, and data[0] contains the
+        * value INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT.
+        * On the ME-4000 it is only possible to switch port wise (8 bit)
+        */
 
        tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
-       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | ME4000_DIO_CTRL_BIT_MODE_1 |
-                ME4000_DIO_CTRL_BIT_MODE_2 | ME4000_DIO_CTRL_BIT_MODE_3 |
-                ME4000_DIO_CTRL_BIT_MODE_4 | ME4000_DIO_CTRL_BIT_MODE_5 |
-                ME4000_DIO_CTRL_BIT_MODE_6 | ME4000_DIO_CTRL_BIT_MODE_7);
-       if (s->io_bits & 0x000000ff)
-               tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
-       if (s->io_bits & 0x0000ff00)
-               tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
-       if (s->io_bits & 0x00ff0000)
-               tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
-       if (s->io_bits & 0xff000000)
-               tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
 
-       /*
-        * Check for optoisolated ME-4000 version.
-        * If one the first port is a fixed output
-        * port and the second is a fixed input port.
-        */
-       if (inl(dev->iobase + ME4000_DIO_DIR_REG)) {
-               s->io_bits |= 0x000000ff;
-               s->io_bits &= ~0x0000ff00;
-               tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
-               tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
-                        ME4000_DIO_CTRL_BIT_MODE_3);
+       if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
+               if (chan < 8) {
+                       s->io_bits |= 0xFF;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
+                                ME4000_DIO_CTRL_BIT_MODE_1);
+                       tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
+               } else if (chan < 16) {
+                       /*
+                        * Chech for optoisolated ME-4000 version.
+                        * If one the first port is a fixed output
+                        * port and the second is a fixed input port.
+                        */
+                       if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
+                               return -ENODEV;
+
+                       s->io_bits |= 0xFF00;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
+                                ME4000_DIO_CTRL_BIT_MODE_3);
+                       tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
+               } else if (chan < 24) {
+                       s->io_bits |= 0xFF0000;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
+                                ME4000_DIO_CTRL_BIT_MODE_5);
+                       tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
+               } else if (chan < 32) {
+                       s->io_bits |= 0xFF000000;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
+                                ME4000_DIO_CTRL_BIT_MODE_7);
+                       tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
+               } else {
+                       return -EINVAL;
+               }
+       } else {
+               if (chan < 8) {
+                       /*
+                        * Chech for optoisolated ME-4000 version.
+                        * If one the first port is a fixed output
+                        * port and the second is a fixed input port.
+                        */
+                       if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
+                               return -ENODEV;
+
+                       s->io_bits &= ~0xFF;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
+                                ME4000_DIO_CTRL_BIT_MODE_1);
+               } else if (chan < 16) {
+                       s->io_bits &= ~0xFF00;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
+                                ME4000_DIO_CTRL_BIT_MODE_3);
+               } else if (chan < 24) {
+                       s->io_bits &= ~0xFF0000;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
+                                ME4000_DIO_CTRL_BIT_MODE_5);
+               } else if (chan < 32) {
+                       s->io_bits &= ~0xFF000000;
+                       tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
+                                ME4000_DIO_CTRL_BIT_MODE_7);
+               } else {
+                       return -EINVAL;
+               }
        }
 
        outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
 
-       return insn->n;
+       return 1;
 }
 
 /*=============================================================================