Commit 099ec87d authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: pcmuio: spinlock protect pcmuio_{write, read}()

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: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 04426acf
...@@ -146,7 +146,7 @@ struct pcmuio_subdev_private { ...@@ -146,7 +146,7 @@ struct pcmuio_subdev_private {
struct pcmuio_private { struct pcmuio_private {
struct { struct {
spinlock_t spinlock; spinlock_t pagelock;
} asics[PCMUIO_MAX_ASICS]; } asics[PCMUIO_MAX_ASICS];
struct pcmuio_subdev_private *sprivs; struct pcmuio_subdev_private *sprivs;
unsigned int irq2; unsigned int irq2;
...@@ -155,8 +155,11 @@ struct pcmuio_private { ...@@ -155,8 +155,11 @@ struct pcmuio_private {
static void pcmuio_write(struct comedi_device *dev, unsigned int val, static void pcmuio_write(struct comedi_device *dev, unsigned int val,
int asic, int page, int port) int asic, int page, int port)
{ {
struct pcmuio_private *devpriv = dev->private;
unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
unsigned long flags;
spin_lock_irqsave(&devpriv->asics[asic].pagelock, flags);
if (page == 0) { if (page == 0) {
/* Port registers are valid for any page */ /* Port registers are valid for any page */
outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0)); outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0));
...@@ -168,14 +171,18 @@ static void pcmuio_write(struct comedi_device *dev, unsigned int val, ...@@ -168,14 +171,18 @@ static void pcmuio_write(struct comedi_device *dev, unsigned int val,
outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1)); outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1));
outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2)); 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, static unsigned int pcmuio_read(struct comedi_device *dev,
int asic, int page, int port) int asic, int page, int port)
{ {
struct pcmuio_private *devpriv = dev->private;
unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
unsigned long flags;
unsigned int val; unsigned int val;
spin_lock_irqsave(&devpriv->asics[asic].pagelock, flags);
if (page == 0) { if (page == 0) {
/* Port registers are valid for any page */ /* Port registers are valid for any page */
val = inb(iobase + PCMUIO_PORT_REG(port + 0)); val = inb(iobase + PCMUIO_PORT_REG(port + 0));
...@@ -187,6 +194,7 @@ static unsigned int pcmuio_read(struct comedi_device *dev, ...@@ -187,6 +194,7 @@ static unsigned int pcmuio_read(struct comedi_device *dev,
val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8); val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8);
val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16); val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16);
} }
spin_unlock_irqrestore(&devpriv->asics[asic].pagelock, flags);
return val; return val;
} }
...@@ -346,17 +354,13 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, ...@@ -346,17 +354,13 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev,
static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
{ {
struct pcmuio_private *devpriv = dev->private;
struct pcmuio_subdev_private *subpriv; struct pcmuio_subdev_private *subpriv;
unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
unsigned int triggered = 0; unsigned int triggered = 0;
int got1 = 0; int got1 = 0;
unsigned long flags;
unsigned char int_pend; unsigned char int_pend;
int i; int i;
spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07; int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07;
if (int_pend) { if (int_pend) {
triggered = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0); triggered = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0);
...@@ -365,8 +369,6 @@ static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) ...@@ -365,8 +369,6 @@ static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
++got1; ++got1;
} }
spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
if (triggered) { if (triggered) {
struct comedi_subdevice *s; struct comedi_subdevice *s;
/* TODO here: dispatch io lines to subdevs with commands.. */ /* TODO here: dispatch io lines to subdevs with commands.. */
...@@ -598,7 +600,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) ...@@ -598,7 +600,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM; return -ENOMEM;
for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic) 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); pcmuio_reset(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment