From 57054dcaec4848d5f6ce2fddaebfd0fc110e0c53 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 24 Oct 2012 16:47:57 +0100 Subject: [PATCH] staging: comedi: amplc_dio200: internalize 8255 DIO implementation Implement the '8255' DIO subdevice internally to this module instead of using the external "8255" module. I plan to add support for additional cards to this driver that would require the I/O callback functionality of the 8255 module, but the existing callback functions do not have much context to handle this elegantly. The additional cards also have extra DIO features which cannot be handled by the existing "8255" module and that I'd like to support some time in the future. The bottom line is I _could_ continue using the "8255" module for a while with a callback function, but it would turn out to be a very ugly callback function and I'd have to ditch the use of the "8255" module as soon as I added an extra feature to the DIO subdevice. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/amplc_dio200.c | 147 +++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 4 deletions(-) diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index d874bdf..0c824a9 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -207,7 +207,6 @@ #include "../comedidev.h" #include "comedi_fc.h" -#include "8255.h" #include "8253.h" #define DIO200_DRIVER_NAME "amplc_dio200" @@ -221,6 +220,15 @@ #define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b #define PCI_DEVICE_ID_INVALID 0xffff +/* 8255 control register bits */ +#define CR_C_LO_IO 0x01 +#define CR_B_IO 0x02 +#define CR_B_MODE 0x04 +#define CR_C_HI_IO 0x08 +#define CR_A_IO 0x10 +#define CR_A_MODE(a) ((a)<<5) +#define CR_CW 0x80 + /* 200 series registers */ #define DIO200_IO_SIZE 0x20 #define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */ @@ -430,6 +438,10 @@ struct dio200_subdev_8254 { spinlock_t spinlock; }; +struct dio200_subdev_8255 { + unsigned int ofs; /* DIO base offset */ +}; + struct dio200_subdev_intr { unsigned int ofs; spinlock_t spinlock; @@ -1245,6 +1257,133 @@ dio200_subdev_8254_cleanup(struct comedi_device *dev, kfree(subpriv); } +/* + * This function sets I/O directions for an '8255' DIO subdevice. + */ +static void dio200_subdev_8255_set_dir(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct dio200_subdev_8255 *subpriv = s->private; + int config; + + config = CR_CW; + /* 1 in io_bits indicates output, 1 in config indicates input */ + if (!(s->io_bits & 0x0000ff)) + config |= CR_A_IO; + if (!(s->io_bits & 0x00ff00)) + config |= CR_B_IO; + if (!(s->io_bits & 0x0f0000)) + config |= CR_C_LO_IO; + if (!(s->io_bits & 0xf00000)) + config |= CR_C_HI_IO; + outb(config, dev->iobase + subpriv->ofs + 3); +} + +/* + * Handle 'insn_bits' for an '8255' DIO subdevice. + */ +static int dio200_subdev_8255_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct dio200_subdev_8255 *subpriv = s->private; + + if (data[0]) { + s->state &= ~data[0]; + s->state |= (data[0] & data[1]); + if (data[0] & 0xff) + outb(s->state & 0xff, dev->iobase + subpriv->ofs); + if (data[0] & 0xff00) + outb((s->state >> 8) & 0xff, + dev->iobase + subpriv->ofs + 1); + if (data[0] & 0xff0000) + outb((s->state >> 16) & 0xff, + dev->iobase + subpriv->ofs + 2); + } + data[1] = inb(dev->iobase + subpriv->ofs); + data[1] |= inb(dev->iobase + subpriv->ofs + 1) << 8; + data[1] |= inb(dev->iobase + subpriv->ofs + 2) << 16; + return 2; +} + +/* + * Handle 'insn_config' for an '8255' DIO subdevice. + */ +static int dio200_subdev_8255_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask; + unsigned int bits; + + mask = 1 << CR_CHAN(insn->chanspec); + if (mask & 0x0000ff) + bits = 0x0000ff; + else if (mask & 0x00ff00) + bits = 0x00ff00; + else if (mask & 0x0f0000) + bits = 0x0f0000; + else + bits = 0xf00000; + switch (data[0]) { + case INSN_CONFIG_DIO_INPUT: + s->io_bits &= ~bits; + break; + case INSN_CONFIG_DIO_OUTPUT: + s->io_bits |= bits; + break; + case INSN_CONFIG_DIO_QUERY: + data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; + return insn->n; + break; + default: + return -EINVAL; + } + dio200_subdev_8255_set_dir(dev, s); + return 1; +} + +/* + * This function initializes an '8255' DIO subdevice. + * + * offset is the offset to the 8255 chip. + */ +static int dio200_subdev_8255_init(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int offset) +{ + struct dio200_subdev_8255 *subpriv; + + subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); + if (!subpriv) + return -ENOMEM; + subpriv->ofs = offset; + s->private = subpriv; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->range_table = &range_digital; + s->maxdata = 1; + s->insn_bits = dio200_subdev_8255_bits; + s->insn_config = dio200_subdev_8255_config; + s->state = 0; + s->io_bits = 0; + dio200_subdev_8255_set_dir(dev, s); + return 0; +} + +/* + * This function cleans up an '8255' DIO subdevice. + */ +static void dio200_subdev_8255_cleanup(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct dio200_subdev_8255 *subpriv = s->private; + + kfree(subpriv); +} + static void dio200_report_attach(struct comedi_device *dev, unsigned int irq) { const struct dio200_board *thisboard = comedi_board(dev); @@ -1301,8 +1440,8 @@ static int dio200_common_attach(struct comedi_device *dev, unsigned long iobase, break; case sd_8255: /* digital i/o subdevice (8255) */ - ret = subdev_8255_init(dev, s, NULL, - iobase + layout->sdinfo[n]); + ret = dio200_subdev_8255_init(dev, s, + layout->sdinfo[n]); if (ret < 0) return ret; break; @@ -1438,7 +1577,7 @@ static void dio200_detach(struct comedi_device *dev) dio200_subdev_8254_cleanup(dev, s); break; case sd_8255: - subdev_8255_cleanup(dev, s); + dio200_subdev_8255_cleanup(dev, s); break; case sd_intr: dio200_subdev_intr_cleanup(dev, s); -- 2.7.4