From: Ian Abbott Date: Wed, 24 Oct 2012 15:48:01 +0000 (+0100) Subject: staging: comedi: amplc_dio200: support memory-mapped I/O X-Git-Tag: next-20121025~21^2~13 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=71b3e9e8dc218133417d3c167632a61f9fed3651;p=karo-tx-linux.git 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 Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 1b734dc51b33..39fb82b4eca8 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -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. */ @@ -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; }; @@ -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); } /* @@ -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); } /* @@ -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)); @@ -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, @@ -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) @@ -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) { @@ -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); + } } } }