Skip to content

Commit

Permalink
staging: comedi: amplc_dio200: support memory-mapped I/O
Browse files Browse the repository at this point in the history
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: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Ian Abbott authored and Greg Kroah-Hartman committed Oct 24, 2012
1 parent 9bfa0d5 commit 71b3e9e
Showing 1 changed file with 53 additions and 8 deletions.
61 changes: 53 additions & 8 deletions drivers/staging/comedi/drivers/amplc_dio200.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,18 @@ static const unsigned clock_period[8] = {
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.
*/
Expand Down Expand Up @@ -425,6 +437,7 @@ static const struct dio200_layout dio200_layouts[] = {
feel free to suggest moving the variable to the struct comedi_device struct.
*/
struct dio200_private {
struct dio200_region io; /* Register region */
int intr_sd;
};

Expand Down Expand Up @@ -480,7 +493,12 @@ static inline bool is_isa_board(const struct dio200_board *board)
static unsigned char dio200_read8(struct comedi_device *dev,
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);
}

/*
Expand All @@ -489,7 +507,12 @@ static unsigned char dio200_read8(struct comedi_device *dev,
static void dio200_write8(struct comedi_device *dev, unsigned int offset,
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);
}

/*
Expand Down Expand Up @@ -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)
{
const struct dio200_board *thisboard = comedi_board(dev);
struct dio200_private *devpriv = dev->private;
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
char tmpbuf[60];
int tmplen;

if (is_isa_board(thisboard))
tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
"(base %#lx) ", dev->iobase);
"(base %#lx) ", devpriv->io.u.iobase);
else if (is_pci_board(thisboard))
tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
"(pci %s) ", pci_name(pcidev));
Expand Down Expand Up @@ -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);
if (ret < 0)
return ret;
dev->iobase = iobase;
devpriv->io.u.iobase = iobase;
devpriv->io.regtype = io_regtype;
return dio200_common_attach(dev, irq, 0);
} else if (is_pci_board(thisboard)) {
dev_err(dev->class_dev,
Expand All @@ -1549,6 +1574,7 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev,
struct pci_dev *pci_dev)
{
struct dio200_private *devpriv;
resource_size_t base;
int ret;

if (!DO_PCI)
Expand All @@ -1573,16 +1599,32 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev,
"error! cannot enable PCI device and request regions!\n");
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);
}

static void dio200_detach(struct comedi_device *dev)
{
const struct dio200_board *thisboard = comedi_board(dev);
struct dio200_private *devpriv = dev->private;
const struct dio200_layout *layout;
unsigned n;

if (!thisboard || !devpriv)
return;
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->subdevices) {
Expand All @@ -1605,13 +1647,16 @@ static void dio200_detach(struct comedi_device *dev)
}
}
if (is_isa_board(thisboard)) {
if (dev->iobase)
release_region(dev->iobase, DIO200_IO_SIZE);
if (devpriv->io.regtype == io_regtype)
release_region(devpriv->io.u.iobase, DIO200_IO_SIZE);
} else if (is_pci_board(thisboard)) {
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
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);
}
}
}
}
Expand Down

0 comments on commit 71b3e9e

Please sign in to comment.