diff options
author | Ian Abbott <abbotti@mev.co.uk> | 2012-11-14 06:22:56 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-11-14 19:25:08 -0500 |
commit | 33cdce6293dcc0b10dcaa8bb5e6fdc8e56b5968f (patch) | |
tree | 87273aa7b3730503f8ff662ce5843b71d7e04a1e /drivers/staging/comedi | |
parent | c3be5c7f1e124a415453c45508c95bff3a6b2308 (diff) |
staging: comedi: addi_apci_1032: conform to new INSN_CONFIG_DIGITAL_TRIG
Conform to the new definition of the `INSN_CONFIG_DIGITAL_TRIG`
configuration instruction.
Return an error if the 'trigger number' in `data[1]` is non-zero or if
the configuration operation in `data[2]` is not supported. Deal with
the 'left-shift' amount in `data[3]`.
The trigger's input channels can only be configured as a set of rising
and falling edges ('OR' mode) or as a set of high and low levels ('AND'
mode). Preserve the old input channels to the right of the 'left-shift'
value except when switching modes.
(The 'left-shift' support is a bit of an overkill for this driver since
the trigger only has 16 input channels.)
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r-- | drivers/staging/comedi/drivers/addi_apci_1032.c | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index eb31375e72e..0f47113ee0b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c | |||
@@ -86,10 +86,14 @@ static int apci1032_reset(struct comedi_device *dev) | |||
86 | * The COS interrupt must be configured before it can be enabled. | 86 | * The COS interrupt must be configured before it can be enabled. |
87 | * | 87 | * |
88 | * data[0] : INSN_CONFIG_DIGITAL_TRIG | 88 | * data[0] : INSN_CONFIG_DIGITAL_TRIG |
89 | * data[1] : 0 = OR (edge) interrupts | 89 | * data[1] : trigger number (= 0) |
90 | * 1 = AND (level) interrupts | 90 | * data[2] : configuration operation: |
91 | * data[2] : rising-edge/high level channels | 91 | * COMEDI_DIGITAL_TRIG_DISABLE = no interrupts |
92 | * data[3] : falling-edge/low level channels | 92 | * COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts |
93 | * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts | ||
94 | * data[3] : left-shift for data[4] and data[5] | ||
95 | * data[4] : rising-edge/high level channels | ||
96 | * data[5] : falling-edge/low level channels | ||
93 | */ | 97 | */ |
94 | static int apci1032_cos_insn_config(struct comedi_device *dev, | 98 | static int apci1032_cos_insn_config(struct comedi_device *dev, |
95 | struct comedi_subdevice *s, | 99 | struct comedi_subdevice *s, |
@@ -97,21 +101,59 @@ static int apci1032_cos_insn_config(struct comedi_device *dev, | |||
97 | unsigned int *data) | 101 | unsigned int *data) |
98 | { | 102 | { |
99 | struct apci1032_private *devpriv = dev->private; | 103 | struct apci1032_private *devpriv = dev->private; |
104 | unsigned int shift, oldmask; | ||
100 | 105 | ||
101 | switch (data[0]) { | 106 | switch (data[0]) { |
102 | case INSN_CONFIG_DIGITAL_TRIG: | 107 | case INSN_CONFIG_DIGITAL_TRIG: |
103 | devpriv->mode1 = data[2]; | 108 | if (data[1] != 0) |
104 | devpriv->mode2 = data[3]; | 109 | return -EINVAL; |
105 | 110 | shift = data[3]; | |
106 | if (devpriv->mode1 || devpriv->mode2) { | 111 | oldmask = (1U << shift) - 1; |
107 | devpriv->ctrl = APCI1032_CTRL_INT_ENA; | 112 | switch (data[2]) { |
108 | if (data[1] == 1) | 113 | case COMEDI_DIGITAL_TRIG_DISABLE: |
109 | devpriv->ctrl = APCI1032_CTRL_INT_AND; | ||
110 | else | ||
111 | devpriv->ctrl = APCI1032_CTRL_INT_OR; | ||
112 | } else { | ||
113 | devpriv->ctrl = 0; | 114 | devpriv->ctrl = 0; |
115 | devpriv->mode1 = 0; | ||
116 | devpriv->mode2 = 0; | ||
114 | apci1032_reset(dev); | 117 | apci1032_reset(dev); |
118 | break; | ||
119 | case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: | ||
120 | if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | | ||
121 | APCI1032_CTRL_INT_OR)) { | ||
122 | /* switching to 'OR' mode */ | ||
123 | devpriv->ctrl = APCI1032_CTRL_INT_ENA | | ||
124 | APCI1032_CTRL_INT_OR; | ||
125 | /* wipe old channels */ | ||
126 | devpriv->mode1 = 0; | ||
127 | devpriv->mode2 = 0; | ||
128 | } else { | ||
129 | /* preserve unspecified channels */ | ||
130 | devpriv->mode1 &= oldmask; | ||
131 | devpriv->mode2 &= oldmask; | ||
132 | } | ||
133 | /* configure specified channels */ | ||
134 | devpriv->mode1 |= data[4] << shift; | ||
135 | devpriv->mode2 |= data[5] << shift; | ||
136 | break; | ||
137 | case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS: | ||
138 | if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | | ||
139 | APCI1032_CTRL_INT_AND)) { | ||
140 | /* switching to 'AND' mode */ | ||
141 | devpriv->ctrl = APCI1032_CTRL_INT_ENA | | ||
142 | APCI1032_CTRL_INT_AND; | ||
143 | /* wipe old channels */ | ||
144 | devpriv->mode1 = 0; | ||
145 | devpriv->mode2 = 0; | ||
146 | } else { | ||
147 | /* preserve unspecified channels */ | ||
148 | devpriv->mode1 &= oldmask; | ||
149 | devpriv->mode2 &= oldmask; | ||
150 | } | ||
151 | /* configure specified channels */ | ||
152 | devpriv->mode1 |= data[4] << shift; | ||
153 | devpriv->mode2 |= data[5] << shift; | ||
154 | break; | ||
155 | default: | ||
156 | return -EINVAL; | ||
115 | } | 157 | } |
116 | break; | 158 | break; |
117 | default: | 159 | default: |