[PATCH 02/13] staging: comedi: pcmuio: spinlock pcmuio_{write, read}()

H Hartley Sweeten hsweeten at visionengravers.com
Wed Jul 24 18:45:29 UTC 2013


Currently only the pcmuio_handle_asic_interrupt() function uses the
spinlock in the private data to protect the read of the paged interrupt
id registers. All accesses to the paged registers should be protected
to ensure that the page is not changed until the access is complete.
Move the lock/unlock into the pcmuio_{write,read}() functions to make
sure the access completes correctly. Rename the spinlock to variable
to clarify its use.

Signed-off-by: H Hartley Sweeten <hsweeten at visionengravers.com>
Cc: Ian Abbott <abbotti at mev.co.uk>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
 drivers/staging/comedi/drivers/pcmuio.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 2c491be..4f1e806 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -146,7 +146,7 @@ struct pcmuio_subdev_private {
 
 struct pcmuio_private {
 	struct {
-		spinlock_t spinlock;
+		spinlock_t pagelock;	/* protect r/w of page registers */
 	} asics[PCMUIO_MAX_ASICS];
 	struct pcmuio_subdev_private *sprivs;
 };
@@ -154,8 +154,11 @@ struct pcmuio_private {
 static void pcmuio_write(struct comedi_device *dev, unsigned int val,
 			 int asic, int page, int port)
 {
+	struct pcmuio_private *devpriv = dev->private;
 	unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
+	unsigned long flags;
 
+	spin_lock_irqsave(&devpriv->asics[asic].pagelock, flags);
 	if (page == 0) {
 		/* Port registers are valid for any page */
 		outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0));
@@ -167,14 +170,18 @@ static void pcmuio_write(struct comedi_device *dev, unsigned int val,
 		outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1));
 		outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2));
 	}
+	spin_unlock_irqrestore(&devpriv->asics[asic].pagelock, flags);
 }
 
 static unsigned int pcmuio_read(struct comedi_device *dev,
 				int asic, int page, int port)
 {
+	struct pcmuio_private *devpriv = dev->private;
 	unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
+	unsigned long flags;
 	unsigned int val;
 
+	spin_lock_irqsave(&devpriv->asics[asic].pagelock, flags);
 	if (page == 0) {
 		/* Port registers are valid for any page */
 		val = inb(iobase + PCMUIO_PORT_REG(port + 0));
@@ -186,6 +193,7 @@ static unsigned int pcmuio_read(struct comedi_device *dev,
 		val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8);
 		val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16);
 	}
+	spin_unlock_irqrestore(&devpriv->asics[asic].pagelock, flags);
 
 	return val;
 }
@@ -353,17 +361,13 @@ done:
 
 static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
 {
-	struct pcmuio_private *devpriv = dev->private;
 	struct pcmuio_subdev_private *subpriv;
 	unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
 	unsigned int triggered = 0;
 	int got1 = 0;
-	unsigned long flags;
 	unsigned char int_pend;
 	int i;
 
-	spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
-
 	int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07;
 	if (int_pend) {
 		triggered = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0);
@@ -372,8 +376,6 @@ static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
 		++got1;
 	}
 
-	spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
-
 	if (triggered) {
 		struct comedi_subdevice *s;
 		/* TODO here: dispatch io lines to subdevs with commands.. */
@@ -605,7 +607,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 		return -ENOMEM;
 
 	for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic)
-		spin_lock_init(&devpriv->asics[asic].spinlock);
+		spin_lock_init(&devpriv->asics[asic].pagelock);
 
 	pcmuio_reset(dev);
 
-- 
1.8.3.2



More information about the devel mailing list