Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9abeb196 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman
Browse files

staging: comedi: ii_pci20kc.c: cleanup the dio subdevice



For asethetics, redefine the register map for the carrier board.
The 'PCI*' names lead one to think this is a PCI board not a
legacy ISA board.

Remove the #if 0'd out pci20xxx_{do,di}() functions. They are not
needed.

Rename, and fix, the pci20xxx_dio_config() function. The control
and direction registers are not readable. Use the new register map
defines instead of the crazy bit shifts.

Rename, and fix, the pci20xxx_dio_insn_config() function. This
function should treat data[0] as the 'instruction' to handle not
just use it to determine if the port is an input or output.

Rename, and tix, the pci20xxx_dio_insn_bits() function. The 'state'
only needs to be updated if the 'mask' indicates.

For aesthetics, abosrb the pci20xxx_dio_init() into the (*attach)
function.

Fix the carrier board id detect in the (*attach). There are two carrier
board types, one with 32 dio channels and one without. Use this info
when setting up the dio subdevice.

Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6d305f89
Loading
Loading
Loading
Loading
+169 −168
Original line number Original line Diff line number Diff line
@@ -80,33 +80,47 @@ options for PCI-20341M:
#include <linux/module.h>
#include <linux/module.h>
#include "../comedidev.h"
#include "../comedidev.h"


#define PCI20000_ID			0x1d
/*
 * Register I/O map
 */
#define II20K_ID_REG			0x00
#define II20K_ID_MOD1_EMPTY		(1 << 7)
#define II20K_ID_MOD2_EMPTY		(1 << 6)
#define II20K_ID_MOD3_EMPTY		(1 << 5)
#define II20K_ID_MASK			0x1f
#define II20K_ID_PCI20001C_1A		0x1b	/* no on-board DIO */
#define II20K_ID_PCI20001C_2A		0x1d	/* on-board DIO */
#define II20K_MOD_STATUS_REG		0x40
#define II20K_MOD_STATUS_IRQ_MOD1	(1 << 7)
#define II20K_MOD_STATUS_IRQ_MOD2	(1 << 6)
#define II20K_MOD_STATUS_IRQ_MOD3	(1 << 5)
#define II20K_DIO0_REG			0x80
#define II20K_DIO1_REG			0x81
#define II20K_DIR_ENA_REG		0x82
#define II20K_DIR_DIO3_OUT		(1 << 7)
#define II20K_DIR_DIO2_OUT		(1 << 6)
#define II20K_BUF_DISAB_DIO3		(1 << 5)
#define II20K_BUF_DISAB_DIO2		(1 << 4)
#define II20K_DIR_DIO1_OUT		(1 << 3)
#define II20K_DIR_DIO0_OUT		(1 << 2)
#define II20K_BUF_DISAB_DIO1		(1 << 1)
#define II20K_BUF_DISAB_DIO0		(1 << 0)
#define II20K_CTRL01_REG		0x83
#define II20K_CTRL01_SET		(1 << 7)
#define II20K_CTRL01_DIO0_IN		(1 << 4)
#define II20K_CTRL01_DIO1_IN		(1 << 1)
#define II20K_DIO2_REG			0xc0
#define II20K_DIO3_REG			0xc1
#define II20K_CTRL23_REG		0xc3
#define II20K_CTRL23_SET		(1 << 7)
#define II20K_CTRL23_DIO2_IN		(1 << 4)
#define II20K_CTRL23_DIO3_IN		(1 << 1)

#define PCI20341_ID			0x77
#define PCI20341_ID			0x77
#define PCI20006_ID			0xe3
#define PCI20006_ID			0xe3
#define PCI20xxx_EMPTY_ID		0xff
#define PCI20xxx_EMPTY_ID		0xff


#define PCI20000_OFFSET			0x100
#define PCI20000_OFFSET			0x100
#define PCI20000_MODULES		3

#define PCI20000_DIO_0			0x80
#define PCI20000_DIO_1			0x81
#define PCI20000_DIO_2			0xc0
#define PCI20000_DIO_3			0xc1
#define PCI20000_DIO_CONTROL_01		0x83	/* port 0, 1 control */
#define PCI20000_DIO_CONTROL_23		0xc3	/* port 2, 3 control */
#define PCI20000_DIO_BUFFER		0x82	/* buffer direction & enable */
#define PCI20000_DIO_EOC		0xef	/* even port, control output */
#define PCI20000_DIO_OOC		0xfd	/* odd port, control output */
#define PCI20000_DIO_EIC		0x90	/* even port, control input */
#define PCI20000_DIO_OIC		0x82	/* odd port, control input */
#define DIO_CAND			0x12	/* and bit 1 & 4 of control */
#define DIO_BE				0x01	/* buffer: port enable */
#define DIO_BO				0x04	/* buffer: output */
#define DIO_BI				0x05	/* buffer: input */
#define DIO_PS_0			0x00	/* buffer: port shift 0 */
#define DIO_PS_1			0x01	/* buffer: port shift 1 */
#define DIO_PS_2			0x04	/* buffer: port shift 2 */
#define DIO_PS_3			0x05	/* buffer: port shift 3 */


#define PCI20006_LCHAN0			0x0d
#define PCI20006_LCHAN0			0x0d
#define PCI20006_STROBE0		0x0b
#define PCI20006_STROBE0		0x0b
@@ -351,103 +365,79 @@ static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
	return 0;
	return 0;
}
}


#if 0
static void ii20k_dio_config(struct comedi_device *dev,
static void pci20xxx_do(struct comedi_device *dev, struct comedi_subdevice *s)
{
	struct pci20xxx_private *devpriv = dev->private;

	/* XXX if the channel is configured for input, does this
	   do bad things? */
	/* XXX it would be a good idea to only update the registers
	   that _need_ to be updated.  This requires changes to
	   comedi, however. */
	writeb((s->state >> 0) & 0xff, devpriv->ioaddr + PCI20000_DIO_0);
	writeb((s->state >> 8) & 0xff, devpriv->ioaddr + PCI20000_DIO_1);
	writeb((s->state >> 16) & 0xff, devpriv->ioaddr + PCI20000_DIO_2);
	writeb((s->state >> 24) & 0xff, devpriv->ioaddr + PCI20000_DIO_3);
}

static unsigned int pci20xxx_di(struct comedi_device *dev,
			     struct comedi_subdevice *s)
			     struct comedi_subdevice *s)
{
{
	struct pci20xxx_private *devpriv = dev->private;
	struct pci20xxx_private *devpriv = dev->private;
	unsigned int bits;
	unsigned char ctrl01 = 0;

	unsigned char ctrl23 = 0;
	/* XXX same note as above */
	unsigned char dir_ena = 0;
	bits = readb(devpriv->ioaddr + PCI20000_DIO_0);
	bits |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
	bits |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
	bits |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;

	return bits;
}
#endif

static void pci20xxx_dio_config(struct comedi_device *dev,
				struct comedi_subdevice *s)
{
	struct pci20xxx_private *devpriv = dev->private;
	unsigned char control_01;
	unsigned char control_23;
	unsigned char buffer;

	control_01 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_01);
	control_23 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
	buffer = readb(devpriv->ioaddr + PCI20000_DIO_BUFFER);


	/* port 0 - channels 0-7 */
	if (s->io_bits & 0x000000ff) {
	if (s->io_bits & 0x000000ff) {
		/* output port 0 */
		/* output port */
		control_01 &= PCI20000_DIO_EOC;
		ctrl01 &= ~II20K_CTRL01_DIO0_IN;
		buffer = (buffer & (~(DIO_BE << DIO_PS_0))) | (DIO_BO <<
		dir_ena &= ~II20K_BUF_DISAB_DIO0;
							       DIO_PS_0);
		dir_ena |= II20K_DIR_DIO0_OUT;
	} else {
	} else {
		/* input port 0 */
		/* input port */
		control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_EIC;
		ctrl01 |= II20K_CTRL01_DIO0_IN;
		buffer = (buffer & (~(DIO_BI << DIO_PS_0)));
		dir_ena &= ~II20K_DIR_DIO0_OUT;
	}
	}

	/* port 1 - channels 8-15 */
	if (s->io_bits & 0x0000ff00) {
	if (s->io_bits & 0x0000ff00) {
		/* output port 1 */
		/* output port */
		control_01 &= PCI20000_DIO_OOC;
		ctrl01 &= ~II20K_CTRL01_DIO1_IN;
		buffer = (buffer & (~(DIO_BE << DIO_PS_1))) | (DIO_BO <<
		dir_ena &= ~II20K_BUF_DISAB_DIO1;
							       DIO_PS_1);
		dir_ena |= II20K_DIR_DIO1_OUT;
	} else {
	} else {
		/* input port 1 */
		/* input port */
		control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_OIC;
		ctrl01 |= II20K_CTRL01_DIO1_IN;
		buffer = (buffer & (~(DIO_BI << DIO_PS_1)));
		dir_ena &= ~II20K_DIR_DIO1_OUT;
	}
	}

	/* port 2 - channels 16-23 */
	if (s->io_bits & 0x00ff0000) {
	if (s->io_bits & 0x00ff0000) {
		/* output port 2 */
		/* output port */
		control_23 &= PCI20000_DIO_EOC;
		ctrl23 &= ~II20K_CTRL23_DIO2_IN;
		buffer = (buffer & (~(DIO_BE << DIO_PS_2))) | (DIO_BO <<
		dir_ena &= ~II20K_BUF_DISAB_DIO2;
							       DIO_PS_2);
		dir_ena |= II20K_DIR_DIO2_OUT;
	} else {
	} else {
		/* input port 2 */
		/* input port */
		control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_EIC;
		ctrl23 |= II20K_CTRL23_DIO2_IN;
		buffer = (buffer & (~(DIO_BI << DIO_PS_2)));
		dir_ena &= ~II20K_DIR_DIO2_OUT;
	}
	}

	/* port 3 - channels 24-31 */
	if (s->io_bits & 0xff000000) {
	if (s->io_bits & 0xff000000) {
		/* output port 3 */
		/* output port */
		control_23 &= PCI20000_DIO_OOC;
		ctrl23 &= ~II20K_CTRL23_DIO3_IN;
		buffer = (buffer & (~(DIO_BE << DIO_PS_3))) | (DIO_BO <<
		dir_ena &= ~II20K_BUF_DISAB_DIO3;
							       DIO_PS_3);
		dir_ena |= II20K_DIR_DIO3_OUT;
	} else {
	} else {
		/* input port 3 */
		/* input port */
		control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_OIC;
		ctrl23 |= II20K_CTRL23_DIO3_IN;
		buffer = (buffer & (~(DIO_BI << DIO_PS_3)));
		dir_ena &= ~II20K_DIR_DIO3_OUT;
	}
	}
	writeb(control_01, devpriv->ioaddr + PCI20000_DIO_CONTROL_01);

	writeb(control_23, devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
	ctrl23 |= II20K_CTRL01_SET;
	writeb(buffer, devpriv->ioaddr + PCI20000_DIO_BUFFER);
	ctrl23 |= II20K_CTRL23_SET;

	/* order is important */
	writeb(ctrl01, devpriv->ioaddr + II20K_CTRL01_REG);
	writeb(ctrl23, devpriv->ioaddr + II20K_CTRL23_REG);
	writeb(dir_ena, devpriv->ioaddr + II20K_DIR_ENA_REG);
}
}


static int pci20xxx_dio_insn_config(struct comedi_device *dev,
static int ii20k_dio_insn_config(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 struct comedi_subdevice *s,
				 struct comedi_insn *insn,
				 struct comedi_insn *insn,
				 unsigned int *data)
				 unsigned int *data)
{
{
	int mask, bits;
	unsigned int mask = 1 << CR_CHAN(insn->chanspec);
	unsigned int bits;


	mask = 1 << CR_CHAN(insn->chanspec);
	if (mask & 0x000000ff)
	if (mask & 0x000000ff)
		bits = 0x000000ff;
		bits = 0x000000ff;
	else if (mask & 0x0000ff00)
	else if (mask & 0x0000ff00)
@@ -456,79 +446,71 @@ static int pci20xxx_dio_insn_config(struct comedi_device *dev,
		bits = 0x00ff0000;
		bits = 0x00ff0000;
	else
	else
		bits = 0xff000000;
		bits = 0xff000000;
	if (data[0])

		s->io_bits |= bits;
	switch (data[0]) {
	else
	case INSN_CONFIG_DIO_INPUT:
		s->io_bits &= ~bits;
		s->io_bits &= ~bits;
	pci20xxx_dio_config(dev, s);
		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;
	default:
		return -EINVAL;
	}


	return 1;
	ii20k_dio_config(dev, s);

	return insn->n;
}
}


static int pci20xxx_dio_insn_bits(struct comedi_device *dev,
static int ii20k_dio_insn_bits(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       struct comedi_subdevice *s,
				  struct comedi_insn *insn, unsigned int *data)
			       struct comedi_insn *insn,
			       unsigned int *data)
{
{
	struct pci20xxx_private *devpriv = dev->private;
	struct pci20xxx_private *devpriv = dev->private;
	unsigned int mask = data[0];
	unsigned int mask = data[0] & s->io_bits;	/* outputs only */
	unsigned int bits = data[1];


	if (mask) {
		s->state &= ~mask;
		s->state &= ~mask;
	s->state |= (mask & data[1]);
		s->state |= (bits & mask);


	mask &= s->io_bits;
		if (mask & 0x000000ff)
		if (mask & 0x000000ff)
			writeb((s->state >> 0) & 0xff,
			writeb((s->state >> 0) & 0xff,
		       devpriv->ioaddr + PCI20000_DIO_0);
			       devpriv->ioaddr + II20K_DIO0_REG);
		if (mask & 0x0000ff00)
		if (mask & 0x0000ff00)
			writeb((s->state >> 8) & 0xff,
			writeb((s->state >> 8) & 0xff,
		       devpriv->ioaddr + PCI20000_DIO_1);
			       devpriv->ioaddr + II20K_DIO1_REG);
		if (mask & 0x00ff0000)
		if (mask & 0x00ff0000)
			writeb((s->state >> 16) & 0xff,
			writeb((s->state >> 16) & 0xff,
		       devpriv->ioaddr + PCI20000_DIO_2);
			       devpriv->ioaddr + II20K_DIO2_REG);
		if (mask & 0xff000000)
		if (mask & 0xff000000)
			writeb((s->state >> 24) & 0xff,
			writeb((s->state >> 24) & 0xff,
		       devpriv->ioaddr + PCI20000_DIO_3);
			       devpriv->ioaddr + II20K_DIO3_REG);

	data[1] = readb(devpriv->ioaddr + PCI20000_DIO_0);
	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;

	return insn->n;
	}
	}


static int pci20xxx_dio_init(struct comedi_device *dev,
	data[1] = readb(devpriv->ioaddr + II20K_DIO0_REG);
			     struct comedi_subdevice *s)
	data[1] |= readb(devpriv->ioaddr + II20K_DIO1_REG) << 8;
{
	data[1] |= readb(devpriv->ioaddr + II20K_DIO2_REG) << 16;
	s->type = COMEDI_SUBD_DIO;
	data[1] |= readb(devpriv->ioaddr + II20K_DIO3_REG) << 24;
	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
	s->n_chan = 32;
	s->insn_bits = pci20xxx_dio_insn_bits;
	s->insn_config = pci20xxx_dio_insn_config;
	s->maxdata = 1;
	s->len_chanlist = 32;
	s->range_table = &range_digital;
	s->io_bits = 0;

	/* digital I/O lines default to input on board reset. */
	pci20xxx_dio_config(dev, s);


	return 0;
	return insn->n;
}
}


static int pci20xxx_attach(struct comedi_device *dev,
static int pci20xxx_attach(struct comedi_device *dev,
			   struct comedi_devconfig *it)
			   struct comedi_devconfig *it)
{
{
	struct pci20xxx_private *devpriv;
	struct pci20xxx_private *devpriv;
	unsigned char i;
	int ret;
	int id;
	struct comedi_subdevice *s;
	union pci20xxx_subdev_private *sdp;
	union pci20xxx_subdev_private *sdp;

	struct comedi_subdevice *s;
	ret = comedi_alloc_subdevices(dev, 1 + PCI20000_MODULES);
	unsigned char id;
	if (ret)
	bool has_dio;
		return ret;
	int ret;
	int i;


	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
	if (!devpriv)
	if (!devpriv)
@@ -536,17 +518,22 @@ static int pci20xxx_attach(struct comedi_device *dev,


	devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];
	devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];


	/* Check PCI-20001 C-2A Carrier Board ID */
	id = readb(devpriv->ioaddr + II20K_ID_REG);
	if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) {
	switch (id & II20K_ID_MASK) {
		dev_warn(dev->class_dev,
	case II20K_ID_PCI20001C_1A:
			 "PCI-20001 C-2A Carrier Board at base=0x%p not found !\n",
		break;
			 devpriv->ioaddr);
	case II20K_ID_PCI20001C_2A:
		return -EINVAL;
		has_dio = true;
		break;
	default:
		return -ENODEV;
	}
	}
	dev_info(dev->class_dev, "PCI-20001 C-2A at base=0x%p\n",
		 devpriv->ioaddr);


	for (i = 0; i < PCI20000_MODULES; i++) {
	ret = comedi_alloc_subdevices(dev, 4);
	if (ret)
		return ret;

	for (i = 0; i < 3; i++) {
		s = &dev->subdevices[i];
		s = &dev->subdevices[i];
		sdp = comedi_alloc_spriv(s, sizeof(*sdp));
		sdp = comedi_alloc_spriv(s, sizeof(*sdp));
		if (!sdp)
		if (!sdp)
@@ -580,8 +567,22 @@ static int pci20xxx_attach(struct comedi_device *dev,
		}
		}
	}
	}


	/* initialize struct pci20xxx_private */
	/* Digital I/O subdevice */
	pci20xxx_dio_init(dev, &dev->subdevices[PCI20000_MODULES]);
	s = &dev->subdevices[3];
	if (has_dio) {
		s->type		= COMEDI_SUBD_DIO;
		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
		s->n_chan	= 32;
		s->maxdata	= 1;
		s->range_table	= &range_digital;
		s->insn_bits	= ii20k_dio_insn_bits;
		s->insn_config	= ii20k_dio_insn_config;

		/* default all channels to input */
		ii20k_dio_config(dev, s);
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}


	return 1;
	return 1;
}
}