mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:44:45 +01:00
comedi: dmm32at: serialize use of paged registers
Some of the hardware registers of the DMM-32-AT board are multiplexed,
using the least significant two bits of the Miscellaneous Control
register to select the function of registers at offsets 12 to 15:
00 => 8254 timer/counter registers are accessible
01 => 8255 digital I/O registers are accessible
10 => Reserved
11 => Calibration registers are accessible
The interrupt service routine (`dmm32at_isr()`) clobbers the bottom two
bits of the register with value 00, which would interfere with access to
the 8255 registers by the `dm32at_8255_io()` function (used for Comedi
instruction handling on the digital I/O subdevice).
Make use of the generic Comedi device spin-lock `dev->spinlock` (which
is otherwise unused by this driver) to serialize access to the
miscellaneous control register and paged registers.
Fixes: 3c501880ac ("Staging: comedi: add dmm32at driver")
Cc: stable@vger.kernel.org
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Link: https://patch.msgid.link/20260112162835.91688-1-abbotti@mev.co.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
06d5a7afe1
commit
e03b29b55f
1 changed files with 30 additions and 2 deletions
|
|
@ -330,6 +330,7 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev,
|
|||
|
||||
static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
unsigned char lo1, lo2, hi2;
|
||||
unsigned short both2;
|
||||
|
||||
|
|
@ -342,6 +343,9 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
|
|||
/* set counter clocks to 10MHz, disable all aux dio */
|
||||
outb(0, dev->iobase + DMM32AT_CTRDIO_CFG_REG);
|
||||
|
||||
/* serialize access to control register and paged registers */
|
||||
spin_lock_irqsave(&dev->spinlock, irq_flags);
|
||||
|
||||
/* get access to the clock regs */
|
||||
outb(DMM32AT_CTRL_PAGE_8254, dev->iobase + DMM32AT_CTRL_REG);
|
||||
|
||||
|
|
@ -354,6 +358,8 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
|
|||
outb(lo2, dev->iobase + DMM32AT_CLK2);
|
||||
outb(hi2, dev->iobase + DMM32AT_CLK2);
|
||||
|
||||
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
||||
|
||||
/* enable the ai conversion interrupt and the clock to start scans */
|
||||
outb(DMM32AT_INTCLK_ADINT |
|
||||
DMM32AT_INTCLK_CLKEN | DMM32AT_INTCLK_CLKSEL,
|
||||
|
|
@ -363,13 +369,19 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
|
|||
static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
{
|
||||
struct comedi_cmd *cmd = &s->async->cmd;
|
||||
unsigned long irq_flags;
|
||||
int ret;
|
||||
|
||||
dmm32at_ai_set_chanspec(dev, s, cmd->chanlist[0], cmd->chanlist_len);
|
||||
|
||||
/* serialize access to control register and paged registers */
|
||||
spin_lock_irqsave(&dev->spinlock, irq_flags);
|
||||
|
||||
/* reset the interrupt just in case */
|
||||
outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG);
|
||||
|
||||
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
||||
|
||||
/*
|
||||
* wait for circuit to settle
|
||||
* we don't have the 'insn' here but it's not needed
|
||||
|
|
@ -429,8 +441,13 @@ static irqreturn_t dmm32at_isr(int irq, void *d)
|
|||
comedi_handle_events(dev, s);
|
||||
}
|
||||
|
||||
/* serialize access to control register and paged registers */
|
||||
spin_lock(&dev->spinlock);
|
||||
|
||||
/* reset the interrupt */
|
||||
outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG);
|
||||
|
||||
spin_unlock(&dev->spinlock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -481,14 +498,25 @@ static int dmm32at_ao_insn_write(struct comedi_device *dev,
|
|||
static int dmm32at_8255_io(struct comedi_device *dev,
|
||||
int dir, int port, int data, unsigned long regbase)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
int ret;
|
||||
|
||||
/* serialize access to control register and paged registers */
|
||||
spin_lock_irqsave(&dev->spinlock, irq_flags);
|
||||
|
||||
/* get access to the DIO regs */
|
||||
outb(DMM32AT_CTRL_PAGE_8255, dev->iobase + DMM32AT_CTRL_REG);
|
||||
|
||||
if (dir) {
|
||||
outb(data, dev->iobase + regbase + port);
|
||||
return 0;
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = inb(dev->iobase + regbase + port);
|
||||
}
|
||||
return inb(dev->iobase + regbase + port);
|
||||
|
||||
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make sure the board is there and put it to a known state */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue