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: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
9bfa0d548c
commit
71b3e9e8dc
@@ -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[] = {
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
"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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user