Skip to content

Commit 33cdce6

Browse files
ian-abbottgregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c3be5c7 commit 33cdce6

File tree

1 file changed

+56
-14
lines changed

1 file changed

+56
-14
lines changed

drivers/staging/comedi/drivers/addi_apci_1032.c

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,32 +86,74 @@ static int apci1032_reset(struct comedi_device *dev)
8686
* The COS interrupt must be configured before it can be enabled.
8787
*
8888
* data[0] : INSN_CONFIG_DIGITAL_TRIG
89-
* data[1] : 0 = OR (edge) interrupts
90-
* 1 = AND (level) interrupts
91-
* data[2] : rising-edge/high level channels
92-
* data[3] : falling-edge/low level channels
89+
* data[1] : trigger number (= 0)
90+
* data[2] : configuration operation:
91+
* COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
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
9397
*/
9498
static int apci1032_cos_insn_config(struct comedi_device *dev,
9599
struct comedi_subdevice *s,
96100
struct comedi_insn *insn,
97101
unsigned int *data)
98102
{
99103
struct apci1032_private *devpriv = dev->private;
104+
unsigned int shift, oldmask;
100105

101106
switch (data[0]) {
102107
case INSN_CONFIG_DIGITAL_TRIG:
103-
devpriv->mode1 = data[2];
104-
devpriv->mode2 = data[3];
105-
106-
if (devpriv->mode1 || devpriv->mode2) {
107-
devpriv->ctrl = APCI1032_CTRL_INT_ENA;
108-
if (data[1] == 1)
109-
devpriv->ctrl = APCI1032_CTRL_INT_AND;
110-
else
111-
devpriv->ctrl = APCI1032_CTRL_INT_OR;
112-
} else {
108+
if (data[1] != 0)
109+
return -EINVAL;
110+
shift = data[3];
111+
oldmask = (1U << shift) - 1;
112+
switch (data[2]) {
113+
case COMEDI_DIGITAL_TRIG_DISABLE:
113114
devpriv->ctrl = 0;
115+
devpriv->mode1 = 0;
116+
devpriv->mode2 = 0;
114117
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;
115157
}
116158
break;
117159
default:

0 commit comments

Comments
 (0)