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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxxxxxxx>
Cc: Ian Abbott <abbotti@xxxxxxxxx>
Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
 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

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel




[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux