Commit 71b3e9e8 authored by Ian Abbott's avatar Ian Abbott Committed by Greg Kroah-Hartman

staging: comedi: amplc_dio200: support memory-mapped I/O

The boards currently supported by this module all use port I/O.  Support
memory-mapped I/O as well for future PCI/PCIe cards.

Define `struct dio200_region` to hold the type of register access and
either the port I/O base address or an ioremapped MMIO address.  Add a
member `io` to the comedi device private data (`struct dio200_private`)
to hold this.  Use this instead of `dev->iobase`.  Memory-mapped
registers are mapped in `dio200_pci_attach()` and unmapped in
`dio200_detach()`.

`dio200_detach()` now uses the private data pointer `devpriv` set to
`dev->private` but can return early if it is `NULL` because no clean-up
needs to be done in that case.
Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9bfa0d54
...@@ -264,6 +264,18 @@ static const unsigned clock_period[8] = { ...@@ -264,6 +264,18 @@ static const unsigned clock_period[8] = {
0 /* group clock input pin */ 0 /* group clock input pin */
}; };
/*
* Register region.
*/
enum dio200_regtype { no_regtype = 0, io_regtype, mmio_regtype };
struct dio200_region {
union {
unsigned long iobase; /* I/O base address */
unsigned char __iomem *membase; /* mapped MMIO base address */
} u;
enum dio200_regtype regtype;
};
/* /*
* Board descriptions. * Board descriptions.
*/ */
...@@ -425,6 +437,7 @@ static const struct dio200_layout dio200_layouts[] = { ...@@ -425,6 +437,7 @@ static const struct dio200_layout dio200_layouts[] = {
feel free to suggest moving the variable to the struct comedi_device struct. feel free to suggest moving the variable to the struct comedi_device struct.
*/ */
struct dio200_private { struct dio200_private {
struct dio200_region io; /* Register region */
int intr_sd; int intr_sd;
}; };
...@@ -480,7 +493,12 @@ static inline bool is_isa_board(const struct dio200_board *board) ...@@ -480,7 +493,12 @@ static inline bool is_isa_board(const struct dio200_board *board)
static unsigned char dio200_read8(struct comedi_device *dev, static unsigned char dio200_read8(struct comedi_device *dev,
unsigned int offset) unsigned int offset)
{ {
return inb(dev->iobase + offset); struct dio200_private *devpriv = dev->private;
if (devpriv->io.regtype == io_regtype)
return inb(devpriv->io.u.iobase + offset);
else
return readb(devpriv->io.u.membase + offset);
} }
/* /*
...@@ -489,7 +507,12 @@ static unsigned char dio200_read8(struct comedi_device *dev, ...@@ -489,7 +507,12 @@ static unsigned char dio200_read8(struct comedi_device *dev,
static void dio200_write8(struct comedi_device *dev, unsigned int offset, static void dio200_write8(struct comedi_device *dev, unsigned int offset,
unsigned char val) unsigned char val)
{ {
outb(val, dev->iobase + offset); struct dio200_private *devpriv = dev->private;
if (devpriv->io.regtype == io_regtype)
outb(val, devpriv->io.u.iobase + offset);
else
writeb(val, devpriv->io.u.membase + offset);
} }
/* /*
...@@ -1405,13 +1428,14 @@ static void dio200_subdev_8255_cleanup(struct comedi_device *dev, ...@@ -1405,13 +1428,14 @@ static void dio200_subdev_8255_cleanup(struct comedi_device *dev,
static void dio200_report_attach(struct comedi_device *dev, unsigned int irq) static void dio200_report_attach(struct comedi_device *dev, unsigned int irq)
{ {
const struct dio200_board *thisboard = comedi_board(dev); const struct dio200_board *thisboard = comedi_board(dev);
struct dio200_private *devpriv = dev->private;
struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct pci_dev *pcidev = comedi_to_pci_dev(dev);
char tmpbuf[60]; char tmpbuf[60];
int tmplen; int tmplen;
if (is_isa_board(thisboard)) if (is_isa_board(thisboard))
tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
"(base %#lx) ", dev->iobase); "(base %#lx) ", devpriv->io.u.iobase);
else if (is_pci_board(thisboard)) else if (is_pci_board(thisboard))
tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
"(pci %s) ", pci_name(pcidev)); "(pci %s) ", pci_name(pcidev));
...@@ -1526,7 +1550,8 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) ...@@ -1526,7 +1550,8 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = dio200_request_region(dev, iobase, DIO200_IO_SIZE); ret = dio200_request_region(dev, iobase, DIO200_IO_SIZE);
if (ret < 0) if (ret < 0)
return ret; return ret;
dev->iobase = iobase; devpriv->io.u.iobase = iobase;
devpriv->io.regtype = io_regtype;
return dio200_common_attach(dev, irq, 0); return dio200_common_attach(dev, irq, 0);
} else if (is_pci_board(thisboard)) { } else if (is_pci_board(thisboard)) {
dev_err(dev->class_dev, dev_err(dev->class_dev,
...@@ -1549,6 +1574,7 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev, ...@@ -1549,6 +1574,7 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev,
struct pci_dev *pci_dev) struct pci_dev *pci_dev)
{ {
struct dio200_private *devpriv; struct dio200_private *devpriv;
resource_size_t base;
int ret; int ret;
if (!DO_PCI) if (!DO_PCI)
...@@ -1573,16 +1599,32 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev, ...@@ -1573,16 +1599,32 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev,
"error! cannot enable PCI device and request regions!\n"); "error! cannot enable PCI device and request regions!\n");
return ret; return ret;
} }
dev->iobase = pci_resource_start(pci_dev, 2); base = pci_resource_start(pci_dev, 2);
if ((pci_resource_flags(pci_dev, 2) & IORESOURCE_MEM) != 0) {
resource_size_t len = pci_resource_len(pci_dev, 2);
devpriv->io.u.membase = ioremap_nocache(base, len);
if (!devpriv->io.u.membase) {
dev_err(dev->class_dev,
"error! cannot remap registers\n");
return -ENOMEM;
}
devpriv->io.regtype = mmio_regtype;
} else {
devpriv->io.u.iobase = (unsigned long)base;
devpriv->io.regtype = io_regtype;
}
return dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED); return dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED);
} }
static void dio200_detach(struct comedi_device *dev) static void dio200_detach(struct comedi_device *dev)
{ {
const struct dio200_board *thisboard = comedi_board(dev); const struct dio200_board *thisboard = comedi_board(dev);
struct dio200_private *devpriv = dev->private;
const struct dio200_layout *layout; const struct dio200_layout *layout;
unsigned n; unsigned n;
if (!thisboard || !devpriv)
return;
if (dev->irq) if (dev->irq)
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
if (dev->subdevices) { if (dev->subdevices) {
...@@ -1605,13 +1647,16 @@ static void dio200_detach(struct comedi_device *dev) ...@@ -1605,13 +1647,16 @@ static void dio200_detach(struct comedi_device *dev)
} }
} }
if (is_isa_board(thisboard)) { if (is_isa_board(thisboard)) {
if (dev->iobase) if (devpriv->io.regtype == io_regtype)
release_region(dev->iobase, DIO200_IO_SIZE); release_region(devpriv->io.u.iobase, DIO200_IO_SIZE);
} else if (is_pci_board(thisboard)) { } else if (is_pci_board(thisboard)) {
struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct pci_dev *pcidev = comedi_to_pci_dev(dev);
if (pcidev) { if (pcidev) {
if (dev->iobase) if (devpriv->io.regtype != no_regtype) {
if (devpriv->io.regtype == mmio_regtype)
iounmap(devpriv->io.u.membase);
comedi_pci_disable(pcidev); comedi_pci_disable(pcidev);
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment