diff options
author | J. Ali Harlow <ali@avrc.city.ac.uk> | 2011-05-18 18:18:55 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-18 21:32:06 (GMT) |
commit | c647ed568af52cc75ece267ff02937d9263d1d27 (patch) | |
tree | 69b41daee8e30384e7f45fe2a130b2dd0acfef22 | |
parent | 510b9be374a4b589e7f6182d306b3c8ec9575e05 (diff) | |
download | linux-fsl-qoriq-c647ed568af52cc75ece267ff02937d9263d1d27.tar.xz |
comedi vmk80xx: support bits instruction
Calling comedi_dio_bifield2() returns EBUSY permanently. Implementing
the insn_bits call fixes the problem and is good in its own right since
one can then read and write to all the digitial lines at the same time.
Tested on a K8055, but not on a K8061.
Signed-off-by: J. Ali Harlow <ali@avrc.city.ac.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/staging/comedi/drivers/vmk80xx.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 669ebf85..04c085f 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -709,6 +709,50 @@ static int vmk80xx_ao_rinsn(struct comedi_device *cdev, return n; } +static int vmk80xx_di_bits(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + unsigned char *rx_buf; + int reg; + int retval; + + dbgvm("vmk80xx: %s\n", __func__); + + retval = rudimentary_check(dev, DIR_IN); + if (retval) + return retval; + + down(&dev->limit_sem); + + rx_buf = dev->usb_rx_buf; + + if (dev->board.model == VMK8061_MODEL) { + reg = VMK8061_DI_REG; + dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; + } else { + reg = VMK8055_DI_REG; + } + + retval = vmk80xx_read_packet(dev); + + if (!retval) { + if (dev->board.model == VMK8055_MODEL) + data[1] = (((rx_buf[reg] >> 4) & 0x03) | + ((rx_buf[reg] << 2) & 0x04) | + ((rx_buf[reg] >> 3) & 0x18)); + else + data[1] = rx_buf[reg]; + + retval = 2; + } + + up(&dev->limit_sem); + + return retval; +} + static int vmk80xx_di_rinsn(struct comedi_device *cdev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -840,6 +884,73 @@ static int vmk80xx_do_rinsn(struct comedi_device *cdev, return n; } +static int vmk80xx_do_bits(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + unsigned char *rx_buf, *tx_buf; + int dir, reg, cmd; + int retval; + + dbgvm("vmk80xx: %s\n", __func__); + + dir = 0; + + if (data[0]) + dir |= DIR_OUT; + + if (dev->board.model == VMK8061_MODEL) + dir |= DIR_IN; + + retval = rudimentary_check(dev, dir); + if (retval) + return retval; + + down(&dev->limit_sem); + + rx_buf = dev->usb_rx_buf; + tx_buf = dev->usb_tx_buf; + + if (data[0]) { + if (dev->board.model == VMK8055_MODEL) { + reg = VMK8055_DO_REG; + cmd = VMK8055_CMD_WRT_AD; + } else { /* VMK8061_MODEL */ + reg = VMK8061_DO_REG; + cmd = VMK8061_CMD_DO; + } + + tx_buf[reg] &= ~data[0]; + tx_buf[reg] |= (data[0] & data[1]); + + retval = vmk80xx_write_packet(dev, cmd); + + if (retval) + goto out; + } + + if (dev->board.model == VMK8061_MODEL) { + reg = VMK8061_DO_REG; + tx_buf[0] = VMK8061_CMD_RD_DO; + + retval = vmk80xx_read_packet(dev); + + if (!retval) { + data[1] = rx_buf[reg]; + retval = 2; + } + } else { + data[1] = tx_buf[reg]; + retval = 2; + } + +out: + up(&dev->limit_sem); + + return retval; +} + static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1139,6 +1250,7 @@ static int vmk80xx_attach(struct comedi_device *cdev, s->n_chan = dev->board.di_chans; s->maxdata = 1; s->insn_read = vmk80xx_di_rinsn; + s->insn_bits = vmk80xx_di_bits; /* Digital output subdevice */ s = cdev->subdevices + VMK80XX_SUBD_DO; @@ -1147,6 +1259,7 @@ static int vmk80xx_attach(struct comedi_device *cdev, s->n_chan = dev->board.do_chans; s->maxdata = 1; s->insn_write = vmk80xx_do_winsn; + s->insn_bits = vmk80xx_do_bits; if (dev->board.model == VMK8061_MODEL) { s->subdev_flags |= SDF_READABLE; |