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