Skip to content

Commit e03b29b

Browse files
ian-abbottgregkh
authored andcommitted
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: 3c50188 ("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>
1 parent 06d5a7a commit e03b29b

1 file changed

Lines changed: 30 additions & 2 deletions

File tree

drivers/comedi/drivers/dmm32at.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev,
330330

331331
static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
332332
{
333+
unsigned long irq_flags;
333334
unsigned char lo1, lo2, hi2;
334335
unsigned short both2;
335336

@@ -342,6 +343,9 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
342343
/* set counter clocks to 10MHz, disable all aux dio */
343344
outb(0, dev->iobase + DMM32AT_CTRDIO_CFG_REG);
344345

346+
/* serialize access to control register and paged registers */
347+
spin_lock_irqsave(&dev->spinlock, irq_flags);
348+
345349
/* get access to the clock regs */
346350
outb(DMM32AT_CTRL_PAGE_8254, dev->iobase + DMM32AT_CTRL_REG);
347351

@@ -354,6 +358,8 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
354358
outb(lo2, dev->iobase + DMM32AT_CLK2);
355359
outb(hi2, dev->iobase + DMM32AT_CLK2);
356360

361+
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
362+
357363
/* enable the ai conversion interrupt and the clock to start scans */
358364
outb(DMM32AT_INTCLK_ADINT |
359365
DMM32AT_INTCLK_CLKEN | DMM32AT_INTCLK_CLKSEL,
@@ -363,13 +369,19 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
363369
static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
364370
{
365371
struct comedi_cmd *cmd = &s->async->cmd;
372+
unsigned long irq_flags;
366373
int ret;
367374

368375
dmm32at_ai_set_chanspec(dev, s, cmd->chanlist[0], cmd->chanlist_len);
369376

377+
/* serialize access to control register and paged registers */
378+
spin_lock_irqsave(&dev->spinlock, irq_flags);
379+
370380
/* reset the interrupt just in case */
371381
outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG);
372382

383+
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
384+
373385
/*
374386
* wait for circuit to settle
375387
* 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)
429441
comedi_handle_events(dev, s);
430442
}
431443

444+
/* serialize access to control register and paged registers */
445+
spin_lock(&dev->spinlock);
446+
432447
/* reset the interrupt */
433448
outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG);
449+
450+
spin_unlock(&dev->spinlock);
434451
return IRQ_HANDLED;
435452
}
436453

@@ -481,14 +498,25 @@ static int dmm32at_ao_insn_write(struct comedi_device *dev,
481498
static int dmm32at_8255_io(struct comedi_device *dev,
482499
int dir, int port, int data, unsigned long regbase)
483500
{
501+
unsigned long irq_flags;
502+
int ret;
503+
504+
/* serialize access to control register and paged registers */
505+
spin_lock_irqsave(&dev->spinlock, irq_flags);
506+
484507
/* get access to the DIO regs */
485508
outb(DMM32AT_CTRL_PAGE_8255, dev->iobase + DMM32AT_CTRL_REG);
486509

487510
if (dir) {
488511
outb(data, dev->iobase + regbase + port);
489-
return 0;
512+
ret = 0;
513+
} else {
514+
ret = inb(dev->iobase + regbase + port);
490515
}
491-
return inb(dev->iobase + regbase + port);
516+
517+
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
518+
519+
return ret;
492520
}
493521

494522
/* Make sure the board is there and put it to a known state */

0 commit comments

Comments
 (0)